Skip to content

Commit d3a0d78

Browse files
committed
feat(KDFs): add PBKDF2 algorithm
1 parent d6260ca commit d3a0d78

File tree

5 files changed

+58
-1
lines changed

5 files changed

+58
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ A collection of useful cryptographic algorithms written in Typescript.
2626
### [Key Derivation Functions] (KDFs)
2727

2828
- [HKDF]
29+
- [PBKDF2]
2930

3031
## Examples
3132

@@ -63,3 +64,4 @@ reviews. **USE AT YOUR OWN RISK**
6364
[HMAC]: https://en.wikipedia.org/wiki/HMAC
6465
[Key Derivation Functions]: https://en.wikipedia.org/wiki/Key_derivation_function
6566
[HKDF]: https://en.wikipedia.org/wiki/HKDF
67+
[PBKDF2]: https://en.wikipedia.org/wiki/PBKDF2

pbkdf2.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { pbkdf2 } from "./src/pbkdf2/mod.ts";
2+
export type { SupportedAlgorithm } from "./src/pbkdf2/mod.ts";

src/hkdf/mod.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function hkdf(
2828
const concat = new Uint8Array(t.length + info.length + 1);
2929
concat.set(t);
3030
concat.set(info, t.length);
31-
concat.set([i + 1], t.length + info.length);
31+
concat[t.length + info.length] = i + 1;
3232
t = hmac(hash, prk, concat);
3333
okm.set(t, hashLen * i);
3434
}

src/pbkdf2/mod.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { hmac, outputSizes, SupportedAlgorithm } from "../hmac/mod.ts";
2+
3+
export type { SupportedAlgorithm };
4+
5+
/**
6+
* PKCS #5: Password-Based Key Derivation Function 2 (PBKDF2)
7+
*/
8+
export function pbkdf2(
9+
hash: SupportedAlgorithm,
10+
password: Uint8Array,
11+
salt: Uint8Array,
12+
iterations: number,
13+
keylen: number,
14+
): Uint8Array {
15+
const dk = new Uint8Array(keylen);
16+
17+
const salti = new Uint8Array(salt.length + 4);
18+
const saltiView = new DataView(salti.buffer);
19+
salti.set(salt);
20+
21+
const hashLen = outputSizes[hash];
22+
const len = Math.ceil(keylen / hashLen);
23+
24+
for (let i = 1, offset = 0; i <= len; i++, offset += hashLen) {
25+
saltiView.setUint32(salt.length, i);
26+
27+
const t = hmac(hash, password, salti);
28+
let u = t;
29+
30+
for (let j = 1; j < iterations; j++) {
31+
u = hmac(hash, password, u);
32+
for (let k = 0; k < hashLen; k++) t[k] ^= u[k];
33+
}
34+
35+
dk.set(t, offset);
36+
}
37+
38+
return dk;
39+
}

tests/pbkdf2.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { pbkdf2 } from "../src/pbkdf2/mod.ts";
2+
import { assertEquals, encodeToHex } from "../dev_deps.ts";
3+
4+
Deno.test("PBKDF2 HMAC-SHA1", () => {
5+
// https://tools.ietf.org/html/rfc6070#section-2
6+
const te = new TextEncoder();
7+
8+
const password = te.encode("password");
9+
const salt = te.encode("salt");
10+
11+
const dk = pbkdf2("sha1", password, salt, 1, 20);
12+
13+
assertEquals(encodeToHex(dk), "0c60c80f961f0e71f3a9b524af6012062fe037a6");
14+
});

0 commit comments

Comments
 (0)