authorgravatar for 53379023+x13a@users.noreply.github.comlucky <53379023+x13a@users.noreply.github.com> 2021-11-15 22:48:24+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-15 20:48:24+01:00
log590880158a03fa97056b30a3379aab5328ccc977
tree2e253aa0712ac4036c9b7d376e42d97f9c67c7ee
parentd3135f76823a053c4e580830f6a6c080caae5ab5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

update docs (#10150)

add fast kdf test fix inconsistent kdf error refactor Co-authored-by: lucky <>

1 files changed, 63 insertions(+), 18 deletions(-)

lib/std/crypto/scrypt.zig+63-18
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1// https://tools.ietf.org/html/rfc79141// https://tools.ietf.org/html/rfc7914
2// https://github.com/golang/crypto/blob/master/scrypt/scrypt.go2// https://github.com/golang/crypto/blob/master/scrypt/scrypt.go
3// https://github.com/Tarsnap/scrypt
34
4const std = @import("std");5const std = @import("std");
5const crypto = std.crypto;6const crypto = std.crypto;
...@@ -119,11 +120,19 @@ fn smix(b: []align(16) u8, r: u30, n: usize, v: []align(16) u32, xy: []align(16)...@@ -119,11 +120,19 @@ fn smix(b: []align(16) u8, r: u30, n: usize, v: []align(16) u32, xy: []align(16)
119 }120 }
120}121}
121122
123/// Scrypt parameters
122pub const Params = struct {124pub const Params = struct {
123 const Self = @This();125 const Self = @This();
124126
127 /// The CPU/Memory cost parameter [ln] is log2(N).
125 ln: u6,128 ln: u6,
129
130 /// The [r]esource usage parameter specifies the block size.
126 r: u30,131 r: u30,
132
133 /// The [p]arallelization parameter.
134 /// A large value of [p] can be used to increase the computational cost of scrypt without
135 /// increasing the memory usage.
127 p: u30,136 p: u30,
128137
129 /// Baseline parameters for interactive logins138 /// Baseline parameters for interactive logins
...@@ -132,7 +141,7 @@ pub const Params = struct {...@@ -132,7 +141,7 @@ pub const Params = struct {
132 /// Baseline parameters for offline usage141 /// Baseline parameters for offline usage
133 pub const sensitive = Self.fromLimits(33554432, 1073741824);142 pub const sensitive = Self.fromLimits(33554432, 1073741824);
134143
135 /// Create parameters from ops and mem limits144 /// Create parameters from ops and mem limits, where mem_limit given in bytes
136 pub fn fromLimits(ops_limit: u64, mem_limit: usize) Self {145 pub fn fromLimits(ops_limit: u64, mem_limit: usize) Self {
137 const ops = math.max(32768, ops_limit);146 const ops = math.max(32768, ops_limit);
138 const r: u30 = 8;147 const r: u30 = 8;
...@@ -170,7 +179,8 @@ pub fn kdf(...@@ -170,7 +179,8 @@ pub fn kdf(
170 salt: []const u8,179 salt: []const u8,
171 params: Params,180 params: Params,
172) KdfError!void {181) KdfError!void {
173 if (derived_key.len == 0 or derived_key.len / 32 > 0xffff_ffff) return KdfError.OutputTooLong;182 if (derived_key.len == 0) return KdfError.WeakParameters;
183 if (derived_key.len / 32 > 0xffff_ffff) return KdfError.OutputTooLong;
174 if (params.ln == 0 or params.r == 0 or params.p == 0) return KdfError.WeakParameters;184 if (params.ln == 0 or params.r == 0 or params.p == 0) return KdfError.WeakParameters;
175185
176 const n64 = @as(u64, 1) << params.ln;186 const n64 = @as(u64, 1) << params.ln;
...@@ -484,6 +494,8 @@ const CryptFormatHasher = struct {...@@ -484,6 +494,8 @@ const CryptFormatHasher = struct {
484};494};
485495
486/// Options for hashing a password.496/// Options for hashing a password.
497///
498/// Allocator is required for scrypt.
487pub const HashOptions = struct {499pub const HashOptions = struct {
488 allocator: ?*mem.Allocator,500 allocator: ?*mem.Allocator,
489 params: Params,501 params: Params,
...@@ -505,6 +517,8 @@ pub fn strHash(...@@ -505,6 +517,8 @@ pub fn strHash(
505}517}
506518
507/// Options for hash verification.519/// Options for hash verification.
520///
521/// Allocator is required for scrypt.
508pub const VerifyOptions = struct {522pub const VerifyOptions = struct {
509 allocator: ?*mem.Allocator,523 allocator: ?*mem.Allocator,
510};524};
...@@ -609,14 +623,16 @@ test "kdf rfc 4" {...@@ -609,14 +623,16 @@ test "kdf rfc 4" {
609test "password hashing (crypt format)" {623test "password hashing (crypt format)" {
610 if (!run_long_tests) return error.SkipZigTest;624 if (!run_long_tests) return error.SkipZigTest;
611625
626 const alloc = std.testing.allocator;
627
612 const str = "$7$A6....1....TrXs5Zk6s8sWHpQgWDIXTR8kUU3s6Jc3s.DtdS8M2i4$a4ik5hGDN7foMuHOW.cp.CtX01UyCeO0.JAG.AHPpx5";628 const str = "$7$A6....1....TrXs5Zk6s8sWHpQgWDIXTR8kUU3s6Jc3s.DtdS8M2i4$a4ik5hGDN7foMuHOW.cp.CtX01UyCeO0.JAG.AHPpx5";
613 const password = "Y0!?iQa9M%5ekffW(`";629 const password = "Y0!?iQa9M%5ekffW(`";
614 try CryptFormatHasher.verify(std.testing.allocator, str, password);630 try CryptFormatHasher.verify(alloc, str, password);
615631
616 const params = Params.interactive;632 const params = Params.interactive;
617 var buf: [CryptFormatHasher.pwhash_str_length]u8 = undefined;633 var buf: [CryptFormatHasher.pwhash_str_length]u8 = undefined;
618 const str2 = try CryptFormatHasher.create(std.testing.allocator, password, params, &buf);634 const str2 = try CryptFormatHasher.create(alloc, password, params, &buf);
619 try CryptFormatHasher.verify(std.testing.allocator, str2, password);635 try CryptFormatHasher.verify(alloc, str2, password);
620}636}
621637
622test "strHash and strVerify" {638test "strHash and strVerify" {
...@@ -625,22 +641,26 @@ test "strHash and strVerify" {...@@ -625,22 +641,26 @@ test "strHash and strVerify" {
625 const alloc = std.testing.allocator;641 const alloc = std.testing.allocator;
626642
627 const password = "testpass";643 const password = "testpass";
644 const params = Params.interactive;
628 const verify_options = VerifyOptions{ .allocator = alloc };645 const verify_options = VerifyOptions{ .allocator = alloc };
629 var buf: [128]u8 = undefined;646 var buf: [128]u8 = undefined;
630647
631 const s = try strHash(648 {
632 password,649 const str = try strHash(
633 HashOptions{ .allocator = alloc, .params = Params.interactive, .encoding = .crypt },650 password,
634 &buf,651 .{ .allocator = alloc, .params = params, .encoding = .crypt },
635 );652 &buf,
636 try strVerify(s, password, verify_options);653 );
637654 try strVerify(str, password, verify_options);
638 const s1 = try strHash(655 }
639 password,656 {
640 HashOptions{ .allocator = alloc, .params = Params.interactive, .encoding = .phc },657 const str = try strHash(
641 &buf,658 password,
642 );659 .{ .allocator = alloc, .params = params, .encoding = .phc },
643 try strVerify(s1, password, verify_options);660 &buf,
661 );
662 try strVerify(str, password, verify_options);
663 }
644}664}
645665
646test "unix-scrypt" {666test "unix-scrypt" {
...@@ -669,3 +689,28 @@ test "crypt format" {...@@ -669,3 +689,28 @@ test "crypt format" {
669 const s1 = try crypt_format.serialize(params, &buf);689 const s1 = try crypt_format.serialize(params, &buf);
670 try std.testing.expectEqualStrings(s1, str);690 try std.testing.expectEqualStrings(s1, str);
671}691}
692
693test "kdf fast" {
694 const TestVector = struct {
695 password: []const u8,
696 salt: []const u8,
697 params: Params,
698 want: []const u8,
699 };
700 const test_vectors = [_]TestVector{
701 .{
702 .password = "p",
703 .salt = "s",
704 .params = .{ .ln = 1, .r = 1, .p = 1 },
705 .want = &([_]u8{
706 0x48, 0xb0, 0xd2, 0xa8, 0xa3, 0x27, 0x26, 0x11,
707 0x98, 0x4c, 0x50, 0xeb, 0xd6, 0x30, 0xaf, 0x52,
708 }),
709 },
710 };
711 inline for (test_vectors) |v| {
712 var dk: [v.want.len]u8 = undefined;
713 try kdf(std.testing.allocator, &dk, v.password, v.salt, v.params);
714 try std.testing.expectEqualSlices(u8, &dk, v.want);
715 }
716}