| ... | @@ -95,11 +95,10 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: | ... | @@ -95,11 +95,10 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: |
| 95 | // | 95 | // |
| 96 | // DK = T_1 || T_2 || ... || T_l<0..r-1> | 96 | // DK = T_1 || T_2 || ... || T_l<0..r-1> |
| 97 | | 97 | |
| 98 | var prevBlock: [hLen]u8 = undefined; | | |
| 99 | var newBlock: [hLen]u8 = undefined; | | |
| 100 | | | |
| 101 | var block: u32 = 0; // Spec limits to u32 | 98 | var block: u32 = 0; // Spec limits to u32 |
| 102 | while (block < l) : (block += 1) { | 99 | while (block < l) : (block += 1) { |
| | 100 | var prevBlock: [hLen]u8 = undefined; |
| | 101 | var newBlock: [hLen]u8 = undefined; |
| 103 | | 102 | |
| 104 | // U_1 = PRF (P, S || INT (i)) | 103 | // U_1 = PRF (P, S || INT (i)) |
| 105 | const blockIndex = mem.toBytes(mem.nativeToBig(u32, block + 1)); // Block index starts at 0001 | 104 | const blockIndex = mem.toBytes(mem.nativeToBig(u32, block + 1)); // Block index starts at 0001 |
| ... | @@ -109,15 +108,15 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: | ... | @@ -109,15 +108,15 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: |
| 109 | ctx.final(prevBlock[0..]); | 108 | ctx.final(prevBlock[0..]); |
| 110 | | 109 | |
| 111 | // Choose portion of DK to write into (T_n) and initialize | 110 | // Choose portion of DK to write into (T_n) and initialize |
| 112 | const offset = block * hLen; | 111 | const offset: usize = block * hLen; |
| 113 | const blockLen = if (block != l - 1) hLen else r; | 112 | const blockLen = if (block != l - 1) hLen else r; |
| 114 | var dkBlock = derivedKey[offset..(offset + blockLen)]; | 113 | var dkBlock = derivedKey[offset..(offset + blockLen)]; |
| 115 | mem.copy(u8, dkBlock[0..], prevBlock[0..dkBlock.len]); | 114 | mem.copy(u8, dkBlock, prevBlock[0..dkBlock.len]); |
| 116 | | 115 | |
| 117 | var i: u32 = 1; | 116 | var i: u32 = 1; |
| 118 | while (i < rounds) : (i += 1) { | 117 | while (i < rounds) : (i += 1) { |
| 119 | // U_c = PRF (P, U_{c-1}) | 118 | // U_c = PRF (P, U_{c-1}) |
| 120 | Prf.create(newBlock[0..], prevBlock[0..], password); | 119 | Prf.create(&newBlock, prevBlock[0..], password); |
| 121 | mem.copy(u8, prevBlock[0..], newBlock[0..]); | 120 | mem.copy(u8, prevBlock[0..], newBlock[0..]); |
| 122 | | 121 | |
| 123 | // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c | 122 | // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c |
| ... | @@ -225,3 +224,26 @@ test "RFC 6070 embedded NUL" { | ... | @@ -225,3 +224,26 @@ test "RFC 6070 embedded NUL" { |
| 225 | | 224 | |
| 226 | htest.assertEqual(expected, derivedKey[0..]); | 225 | htest.assertEqual(expected, derivedKey[0..]); |
| 227 | } | 226 | } |
| | 227 | |
| | 228 | test "Very large dkLen" { |
| | 229 | // These iteration tests are slow so we always skip them. Results have been verified. |
| | 230 | if (true) { |
| | 231 | return error.SkipZigTest; |
| | 232 | } |
| | 233 | |
| | 234 | const p = "password"; |
| | 235 | const s = "salt"; |
| | 236 | const c = 1; |
| | 237 | const dkLen = 1 << 33; |
| | 238 | |
| | 239 | var derivedKey = try std.testing.allocator.alloc(u8, dkLen); |
| | 240 | defer { |
| | 241 | std.testing.allocator.free(derivedKey); |
| | 242 | } |
| | 243 | |
| | 244 | pbkdf2(derivedKey, p, s, c, crypto.hash.Sha1); |
| | 245 | |
| | 246 | const expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6"; |
| | 247 | |
| | 248 | htest.assertEqual(expected, derivedKey[0..]); |
| | 249 | } |