authorgravatar for 35231115+Rocknest@users.noreply.github.comRocknest <35231115+Rocknest@users.noreply.github.com> 2020-09-13 22:39:54+03:00
committergravatar for 35231115+Rocknest@users.noreply.github.comRocknest <35231115+Rocknest@users.noreply.github.com> 2020-09-13 22:39:54+03:00
logb6385870d0e65c5d7c6d7c6ef8c8ed33780b71e4
tree862145f9e85c0183e961ce29af59c436e405cdc1
parenta6d947191e528c02b2f7193dde7c1e51653bc848

Convert asserts to errors, make sure nothing overflows


1 files changed, 37 insertions(+), 32 deletions(-)

lib/std/crypto/pbkdf2.zig+37-32
...@@ -5,15 +5,8 @@...@@ -5,15 +5,8 @@
5// and substantial portions of the software.5// and substantial portions of the software.
66
7const std = @import("std");7const std = @import("std");
8const crypto = std.crypto;
9const debug = std.debug;
10const assert = debug.assert;
11const mem = std.mem;8const mem = std.mem;
129const maxInt = std.math.maxInt;
13// Exports
14comptime {
15 _ = crypto.kdf.pbkdf2;
16}
1710
18// RFC 2898 Section 5.211// RFC 2898 Section 5.2
19//12//
...@@ -48,8 +41,8 @@ comptime {...@@ -48,8 +41,8 @@ comptime {
48/// PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132.41/// PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132.
49///42///
50/// derivedKey: Slice of appropriate size for generated key. Generally 16 or 32 bytes in length.43/// derivedKey: Slice of appropriate size for generated key. Generally 16 or 32 bytes in length.
51/// May be uninitialized. All bytes will be written.44/// May be uninitialized. All bytes will be overwritten.
52/// Maximum size is (2^32 - 1) * Hash.digest_length45/// Maximum size is `maxInt(u32) * Hash.digest_length`
53/// It is a programming error to pass buffer longer than the maximum size.46/// It is a programming error to pass buffer longer than the maximum size.
54///47///
55/// password: Arbitrary sequence of bytes of any length, including empty.48/// password: Arbitrary sequence of bytes of any length, including empty.
...@@ -60,29 +53,41 @@ comptime {...@@ -60,29 +53,41 @@ comptime {
60/// Larger iteration counts improve security by increasing the time required to compute53/// Larger iteration counts improve security by increasing the time required to compute
61/// the derivedKey. It is common to tune this parameter to achieve approximately 100ms.54/// the derivedKey. It is common to tune this parameter to achieve approximately 100ms.
62///55///
63/// Prf: Pseudo-random function to use. A common choice is std.crypto.auth.hmac.HmacSha256.56/// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.HmacSha256`.
64pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) void {57pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) !void {
65 assert(rounds >= 1);58 if (rounds < 1) return error.TooFewRounds;
6659
67 const dkLen: u64 = derivedKey.len;60 const dkLen = derivedKey.len;
68 const hLen: u32 = Prf.mac_length; // Force type to ensure multiplications can't overflow61 const hLen = Prf.mac_length;
6962
70 // FromSpec:63 // FromSpec:
71 //64 //
72 // 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and65 // 1. If dkLen > maxInt(u32) * hLen, output "derived key too long" and
73 // stop.66 // stop.
74 //67 //
75 assert(dkLen > 0 and dkLen <= @as(u64, 1 << 32 - 1) * hLen);68 if (comptime (maxInt(usize) < maxInt(u32) * hLen) and (dkLen > @as(usize, maxInt(u32) * hLen))) {
69 // If maxInt(usize) is less than `maxInt(u32) * hLen` then dkLen is always inbounds
70 // This also asserts hLen >= 1
71 return error.DerivedKeyTooLong;
72 }
7673
77 // FromSpec:74 // FromSpec:
78 //75 //
79 // 2. Let l be the number of hLen-octet blocks in the derived key,76 // 2. Let l be the number of hLen-long blocks of bytes in the derived key,
80 // rounding up, and let r be the number of octets in the last77 // rounding up, and let r be the number of bytes in the last
81 // block78 // block
82 //79 //
83 const l = (dkLen + hLen - 1) / hLen;80
84 var r = dkLen % hLen;81 // l will not overflow, proof:
85 r = if (r != 0) r else hLen;82 // let `L(dkLen, hLen) = (dkLen + hLen - 1) / hLen`
83 // then `L^-1(l, hLen) = l*hLen - hLen + 1`
84 // 1) L^-1(maxInt(u32), hLen) <= maxInt(u32)*hLen
85 // 2) maxInt(u32)*hLen - hLen + 1 <= maxInt(u32)*hLen // subtract maxInt(u32)*hLen + 1
86 // 3) -hLen <= -1 // multiply by -1
87 // 4) hLen >= 1
88 const r_ = dkLen % hLen;
89 const l = @intCast(u32, (dkLen / hLen) + if (r_ == 0) 0 else 1); // original: (dkLen + hLen - 1) / hLen
90 const r = if (r_ == 0) hLen else r_;
8691
87 // FromSpec:92 // FromSpec:
88 //93 //
...@@ -116,7 +121,6 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:...@@ -116,7 +121,6 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:
116 // produce a derived key DK:121 // produce a derived key DK:
117 //122 //
118 // DK = T_1 || T_2 || ... || T_l<0..r-1>123 // DK = T_1 || T_2 || ... || T_l<0..r-1>
119
120 var block: u32 = 0; // Spec limits to u32124 var block: u32 = 0; // Spec limits to u32
121 while (block < l) : (block += 1) {125 while (block < l) : (block += 1) {
122 var prevBlock: [hLen]u8 = undefined;126 var prevBlock: [hLen]u8 = undefined;
...@@ -130,9 +134,9 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:...@@ -130,9 +134,9 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:
130 ctx.final(prevBlock[0..]);134 ctx.final(prevBlock[0..]);
131135
132 // Choose portion of DK to write into (T_n) and initialize136 // Choose portion of DK to write into (T_n) and initialize
133 const offset: usize = @as(usize, block) * hLen;137 const offset = block * hLen;
134 const blockLen = if (block != l - 1) hLen else r;138 const blockLen = if (block != l - 1) hLen else r;
135 var dkBlock = derivedKey[offset..(offset + blockLen)];139 const dkBlock: []u8 = derivedKey[offset..][0..blockLen];
136 mem.copy(u8, dkBlock, prevBlock[0..dkBlock.len]);140 mem.copy(u8, dkBlock, prevBlock[0..dkBlock.len]);
137141
138 var i: u32 = 1;142 var i: u32 = 1;
...@@ -150,6 +154,7 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:...@@ -150,6 +154,7 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds:
150}154}
151155
152const htest = @import("test.zig");156const htest = @import("test.zig");
157const HmacSha1 = std.crypto.auth.hmac.HmacSha1;
153158
154// RFC 6070 PBKDF2 HMAC-SHA1 Test Vectors159// RFC 6070 PBKDF2 HMAC-SHA1 Test Vectors
155test "RFC 6070 one iteration" {160test "RFC 6070 one iteration" {
...@@ -160,7 +165,7 @@ test "RFC 6070 one iteration" {...@@ -160,7 +165,7 @@ test "RFC 6070 one iteration" {
160165
161 var derivedKey: [dkLen]u8 = undefined;166 var derivedKey: [dkLen]u8 = undefined;
162167
163 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);168 try pbkdf2(&derivedKey, p, s, c, HmacSha1);
164169
165 const expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";170 const expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
166171
...@@ -175,7 +180,7 @@ test "RFC 6070 two iterations" {...@@ -175,7 +180,7 @@ test "RFC 6070 two iterations" {
175180
176 var derivedKey: [dkLen]u8 = undefined;181 var derivedKey: [dkLen]u8 = undefined;
177182
178 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);183 try pbkdf2(&derivedKey, p, s, c, HmacSha1);
179184
180 const expected = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957";185 const expected = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957";
181186
...@@ -190,7 +195,7 @@ test "RFC 6070 4096 iterations" {...@@ -190,7 +195,7 @@ test "RFC 6070 4096 iterations" {
190195
191 var derivedKey: [dkLen]u8 = undefined;196 var derivedKey: [dkLen]u8 = undefined;
192197
193 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);198 try pbkdf2(&derivedKey, p, s, c, HmacSha1);
194199
195 const expected = "4b007901b765489abead49d926f721d065a429c1";200 const expected = "4b007901b765489abead49d926f721d065a429c1";
196201
...@@ -210,7 +215,7 @@ test "RFC 6070 16,777,216 iterations" {...@@ -210,7 +215,7 @@ test "RFC 6070 16,777,216 iterations" {
210215
211 var derivedKey = [_]u8{0} ** dkLen;216 var derivedKey = [_]u8{0} ** dkLen;
212217
213 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);218 try pbkdf2(&derivedKey, p, s, c, HmacSha1);
214219
215 const expected = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";220 const expected = "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984";
216221
...@@ -225,7 +230,7 @@ test "RFC 6070 multi-block salt and password" {...@@ -225,7 +230,7 @@ test "RFC 6070 multi-block salt and password" {
225230
226 var derivedKey: [dkLen]u8 = undefined;231 var derivedKey: [dkLen]u8 = undefined;
227232
228 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);233 try pbkdf2(&derivedKey, p, s, c, HmacSha1);
229234
230 const expected = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038";235 const expected = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038";
231236
...@@ -240,7 +245,7 @@ test "RFC 6070 embedded NUL" {...@@ -240,7 +245,7 @@ test "RFC 6070 embedded NUL" {
240245
241 var derivedKey: [dkLen]u8 = undefined;246 var derivedKey: [dkLen]u8 = undefined;
242247
243 pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);248 try pbkdf2(&derivedKey, p, s, c, );
244249
245 const expected = "56fa6aa75548099dcc37d7f03425e0c3";250 const expected = "56fa6aa75548099dcc37d7f03425e0c3";
246251
...@@ -262,6 +267,6 @@ test "Very large dkLen" {...@@ -262,6 +267,6 @@ test "Very large dkLen" {
262 std.testing.allocator.free(derivedKey);267 std.testing.allocator.free(derivedKey);
263 }268 }
264269
265 pbkdf2(derivedKey, p, s, c, crypto.auth.hmac.HmacSha1);270 try pbkdf2(derivedKey, p, s, c, HmacSha1);
266 // Just verify this doesn't crash with an overflow271 // Just verify this doesn't crash with an overflow
267}272}