| ... | @@ -7,12 +7,11 @@ const builtin = @import("builtin"); | ... | @@ -7,12 +7,11 @@ const builtin = @import("builtin"); |
| 7 | | 7 | |
| 8 | const blake2 = crypto.hash.blake2; | 8 | const blake2 = crypto.hash.blake2; |
| 9 | const crypto = std.crypto; | 9 | const crypto = std.crypto; |
| | 10 | const Io = std.Io; |
| 10 | const math = std.math; | 11 | const math = std.math; |
| 11 | const mem = std.mem; | 12 | const mem = std.mem; |
| 12 | const phc_format = pwhash.phc_format; | 13 | const phc_format = pwhash.phc_format; |
| 13 | const pwhash = crypto.pwhash; | 14 | const pwhash = crypto.pwhash; |
| 14 | | | |
| 15 | const Thread = std.Thread; | | |
| 16 | const Blake2b512 = blake2.Blake2b512; | 15 | const Blake2b512 = blake2.Blake2b512; |
| 17 | const Blocks = std.array_list.AlignedManaged([block_length]u64, .@"16"); | 16 | const Blocks = std.array_list.AlignedManaged([block_length]u64, .@"16"); |
| 18 | const H0 = [Blake2b512.digest_length + 8]u8; | 17 | const H0 = [Blake2b512.digest_length + 8]u8; |
| ... | @@ -204,20 +203,20 @@ fn initBlocks( | ... | @@ -204,20 +203,20 @@ fn initBlocks( |
| 204 | } | 203 | } |
| 205 | | 204 | |
| 206 | fn processBlocks( | 205 | fn processBlocks( |
| 207 | allocator: mem.Allocator, | | |
| 208 | blocks: *Blocks, | 206 | blocks: *Blocks, |
| 209 | time: u32, | 207 | time: u32, |
| 210 | memory: u32, | 208 | memory: u32, |
| 211 | threads: u24, | 209 | threads: u24, |
| 212 | mode: Mode, | 210 | mode: Mode, |
| 213 | ) KdfError!void { | 211 | io: Io, |
| | 212 | ) void { |
| 214 | const lanes = memory / threads; | 213 | const lanes = memory / threads; |
| 215 | const segments = lanes / sync_points; | 214 | const segments = lanes / sync_points; |
| 216 | | 215 | |
| 217 | if (builtin.single_threaded or threads == 1) { | 216 | if (builtin.single_threaded or threads == 1) { |
| 218 | processBlocksSt(blocks, time, memory, threads, mode, lanes, segments); | 217 | processBlocksSt(blocks, time, memory, threads, mode, lanes, segments); |
| 219 | } else { | 218 | } else { |
| 220 | try processBlocksMt(allocator, blocks, time, memory, threads, mode, lanes, segments); | 219 | processBlocksMt(blocks, time, memory, threads, mode, lanes, segments, io); |
| 221 | } | 220 | } |
| 222 | } | 221 | } |
| 223 | | 222 | |
| ... | @@ -243,7 +242,6 @@ fn processBlocksSt( | ... | @@ -243,7 +242,6 @@ fn processBlocksSt( |
| 243 | } | 242 | } |
| 244 | | 243 | |
| 245 | fn processBlocksMt( | 244 | fn processBlocksMt( |
| 246 | allocator: mem.Allocator, | | |
| 247 | blocks: *Blocks, | 245 | blocks: *Blocks, |
| 248 | time: u32, | 246 | time: u32, |
| 249 | memory: u32, | 247 | memory: u32, |
| ... | @@ -251,26 +249,20 @@ fn processBlocksMt( | ... | @@ -251,26 +249,20 @@ fn processBlocksMt( |
| 251 | mode: Mode, | 249 | mode: Mode, |
| 252 | lanes: u32, | 250 | lanes: u32, |
| 253 | segments: u32, | 251 | segments: u32, |
| 254 | ) KdfError!void { | 252 | io: Io, |
| 255 | var threads_list = try std.array_list.Managed(Thread).initCapacity(allocator, threads); | 253 | ) void { |
| 256 | defer threads_list.deinit(); | | |
| 257 | | | |
| 258 | var n: u32 = 0; | 254 | var n: u32 = 0; |
| 259 | while (n < time) : (n += 1) { | 255 | while (n < time) : (n += 1) { |
| 260 | var slice: u32 = 0; | 256 | var slice: u32 = 0; |
| 261 | while (slice < sync_points) : (slice += 1) { | 257 | while (slice < sync_points) : (slice += 1) { |
| | 258 | var group: Io.Group = .init; |
| 262 | var lane: u24 = 0; | 259 | var lane: u24 = 0; |
| 263 | while (lane < threads) : (lane += 1) { | 260 | while (lane < threads) : (lane += 1) { |
| 264 | const thread = try Thread.spawn(.{}, processSegment, .{ | 261 | group.async(io, processSegment, .{ |
| 265 | blocks, time, memory, threads, mode, lanes, segments, n, slice, lane, | 262 | blocks, time, memory, threads, mode, lanes, segments, n, slice, lane, |
| 266 | }); | 263 | }); |
| 267 | threads_list.appendAssumeCapacity(thread); | | |
| 268 | } | | |
| 269 | lane = 0; | | |
| 270 | while (lane < threads) : (lane += 1) { | | |
| 271 | threads_list.items[lane].join(); | | |
| 272 | } | 264 | } |
| 273 | threads_list.clearRetainingCapacity(); | 265 | group.wait(io); |
| 274 | } | 266 | } |
| 275 | } | 267 | } |
| 276 | } | 268 | } |
| ... | @@ -489,6 +481,7 @@ pub fn kdf( | ... | @@ -489,6 +481,7 @@ pub fn kdf( |
| 489 | salt: []const u8, | 481 | salt: []const u8, |
| 490 | params: Params, | 482 | params: Params, |
| 491 | mode: Mode, | 483 | mode: Mode, |
| | 484 | io: Io, |
| 492 | ) KdfError!void { | 485 | ) KdfError!void { |
| 493 | if (derived_key.len < 4) return KdfError.WeakParameters; | 486 | if (derived_key.len < 4) return KdfError.WeakParameters; |
| 494 | if (derived_key.len > max_int) return KdfError.OutputTooLong; | 487 | if (derived_key.len > max_int) return KdfError.OutputTooLong; |
| ... | @@ -510,7 +503,7 @@ pub fn kdf( | ... | @@ -510,7 +503,7 @@ pub fn kdf( |
| 510 | blocks.appendNTimesAssumeCapacity(@splat(0), memory); | 503 | blocks.appendNTimesAssumeCapacity(@splat(0), memory); |
| 511 | | 504 | |
| 512 | initBlocks(&blocks, &h0, memory, params.p); | 505 | initBlocks(&blocks, &h0, memory, params.p); |
| 513 | try processBlocks(allocator, &blocks, params.t, memory, params.p, mode); | 506 | processBlocks(&blocks, params.t, memory, params.p, mode, io); |
| 514 | finalize(&blocks, memory, params.p, derived_key); | 507 | finalize(&blocks, memory, params.p, derived_key); |
| 515 | } | 508 | } |
| 516 | | 509 | |
| ... | @@ -533,6 +526,7 @@ const PhcFormatHasher = struct { | ... | @@ -533,6 +526,7 @@ const PhcFormatHasher = struct { |
| 533 | params: Params, | 526 | params: Params, |
| 534 | mode: Mode, | 527 | mode: Mode, |
| 535 | buf: []u8, | 528 | buf: []u8, |
| | 529 | io: Io, |
| 536 | ) HasherError![]const u8 { | 530 | ) HasherError![]const u8 { |
| 537 | if (params.secret != null or params.ad != null) return HasherError.InvalidEncoding; | 531 | if (params.secret != null or params.ad != null) return HasherError.InvalidEncoding; |
| 538 | | 532 | |
| ... | @@ -540,7 +534,7 @@ const PhcFormatHasher = struct { | ... | @@ -540,7 +534,7 @@ const PhcFormatHasher = struct { |
| 540 | crypto.random.bytes(&salt); | 534 | crypto.random.bytes(&salt); |
| 541 | | 535 | |
| 542 | var hash: [default_hash_len]u8 = undefined; | 536 | var hash: [default_hash_len]u8 = undefined; |
| 543 | try kdf(allocator, &hash, password, &salt, params, mode); | 537 | try kdf(allocator, &hash, password, &salt, params, mode, io); |
| 544 | | 538 | |
| 545 | return phc_format.serialize(HashResult{ | 539 | return phc_format.serialize(HashResult{ |
| 546 | .alg_id = @tagName(mode), | 540 | .alg_id = @tagName(mode), |
| ... | @@ -557,6 +551,7 @@ const PhcFormatHasher = struct { | ... | @@ -557,6 +551,7 @@ const PhcFormatHasher = struct { |
| 557 | allocator: mem.Allocator, | 551 | allocator: mem.Allocator, |
| 558 | str: []const u8, | 552 | str: []const u8, |
| 559 | password: []const u8, | 553 | password: []const u8, |
| | 554 | io: Io, |
| 560 | ) HasherError!void { | 555 | ) HasherError!void { |
| 561 | const hash_result = try phc_format.deserialize(HashResult, str); | 556 | const hash_result = try phc_format.deserialize(HashResult, str); |
| 562 | | 557 | |
| ... | @@ -572,7 +567,7 @@ const PhcFormatHasher = struct { | ... | @@ -572,7 +567,7 @@ const PhcFormatHasher = struct { |
| 572 | if (expected_hash.len > hash_buf.len) return HasherError.InvalidEncoding; | 567 | if (expected_hash.len > hash_buf.len) return HasherError.InvalidEncoding; |
| 573 | const hash = hash_buf[0..expected_hash.len]; | 568 | const hash = hash_buf[0..expected_hash.len]; |
| 574 | | 569 | |
| 575 | try kdf(allocator, hash, password, hash_result.salt.constSlice(), params, mode); | 570 | try kdf(allocator, hash, password, hash_result.salt.constSlice(), params, mode, io); |
| 576 | if (!mem.eql(u8, hash, expected_hash)) return HasherError.PasswordVerificationFailed; | 571 | if (!mem.eql(u8, hash, expected_hash)) return HasherError.PasswordVerificationFailed; |
| 577 | } | 572 | } |
| 578 | }; | 573 | }; |
| ... | @@ -595,6 +590,7 @@ pub fn strHash( | ... | @@ -595,6 +590,7 @@ pub fn strHash( |
| 595 | password: []const u8, | 590 | password: []const u8, |
| 596 | options: HashOptions, | 591 | options: HashOptions, |
| 597 | out: []u8, | 592 | out: []u8, |
| | 593 | io: Io, |
| 598 | ) Error![]const u8 { | 594 | ) Error![]const u8 { |
| 599 | const allocator = options.allocator orelse return Error.AllocatorRequired; | 595 | const allocator = options.allocator orelse return Error.AllocatorRequired; |
| 600 | switch (options.encoding) { | 596 | switch (options.encoding) { |
| ... | @@ -604,6 +600,7 @@ pub fn strHash( | ... | @@ -604,6 +600,7 @@ pub fn strHash( |
| 604 | options.params, | 600 | options.params, |
| 605 | options.mode, | 601 | options.mode, |
| 606 | out, | 602 | out, |
| | 603 | io, |
| 607 | ), | 604 | ), |
| 608 | .crypt => return Error.InvalidEncoding, | 605 | .crypt => return Error.InvalidEncoding, |
| 609 | } | 606 | } |
| ... | @@ -621,9 +618,10 @@ pub fn strVerify( | ... | @@ -621,9 +618,10 @@ pub fn strVerify( |
| 621 | str: []const u8, | 618 | str: []const u8, |
| 622 | password: []const u8, | 619 | password: []const u8, |
| 623 | options: VerifyOptions, | 620 | options: VerifyOptions, |
| | 621 | io: Io, |
| 624 | ) Error!void { | 622 | ) Error!void { |
| 625 | const allocator = options.allocator orelse return Error.AllocatorRequired; | 623 | const allocator = options.allocator orelse return Error.AllocatorRequired; |
| 626 | return PhcFormatHasher.verify(allocator, str, password); | 624 | return PhcFormatHasher.verify(allocator, str, password, io); |
| 627 | } | 625 | } |
| 628 | | 626 | |
| 629 | test "argon2d" { | 627 | test "argon2d" { |
| ... | @@ -640,6 +638,7 @@ test "argon2d" { | ... | @@ -640,6 +638,7 @@ test "argon2d" { |
| 640 | &salt, | 638 | &salt, |
| 641 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, | 639 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, |
| 642 | .argon2d, | 640 | .argon2d, |
| | 641 | std.testing.io, |
| 643 | ); | 642 | ); |
| 644 | | 643 | |
| 645 | const want = [_]u8{ | 644 | const want = [_]u8{ |
| ... | @@ -665,6 +664,7 @@ test "argon2i" { | ... | @@ -665,6 +664,7 @@ test "argon2i" { |
| 665 | &salt, | 664 | &salt, |
| 666 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, | 665 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, |
| 667 | .argon2i, | 666 | .argon2i, |
| | 667 | std.testing.io, |
| 668 | ); | 668 | ); |
| 669 | | 669 | |
| 670 | const want = [_]u8{ | 670 | const want = [_]u8{ |
| ... | @@ -690,6 +690,7 @@ test "argon2id" { | ... | @@ -690,6 +690,7 @@ test "argon2id" { |
| 690 | &salt, | 690 | &salt, |
| 691 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, | 691 | .{ .t = 3, .m = 32, .p = 4, .secret = &secret, .ad = &ad }, |
| 692 | .argon2id, | 692 | .argon2id, |
| | 693 | std.testing.io, |
| 693 | ); | 694 | ); |
| 694 | | 695 | |
| 695 | const want = [_]u8{ | 696 | const want = [_]u8{ |
| ... | @@ -800,44 +801,44 @@ test "kdf" { | ... | @@ -800,44 +801,44 @@ test "kdf" { |
| 800 | .{ | 801 | .{ |
| 801 | .mode = .argon2i, | 802 | .mode = .argon2i, |
| 802 | .time = 4, | 803 | .time = 4, |
| 803 | .memory = 4096, | 804 | .memory = 256, |
| 804 | .threads = 4, | 805 | .threads = 4, |
| 805 | .hash = "a11f7b7f3f93f02ad4bddb59ab62d121e278369288a0d0e7", | 806 | .hash = "f7dbbacbf16999e3700817a7e06f65a8db2e9fa9504ede4c", |
| 806 | }, | 807 | }, |
| 807 | .{ | 808 | .{ |
| 808 | .mode = .argon2d, | 809 | .mode = .argon2d, |
| 809 | .time = 4, | 810 | .time = 4, |
| 810 | .memory = 4096, | 811 | .memory = 256, |
| 811 | .threads = 4, | 812 | .threads = 4, |
| 812 | .hash = "935598181aa8dc2b720914aa6435ac8d3e3a4210c5b0fb2d", | 813 | .hash = "ea2970501cf49faa5ba1d2e6370204e9b57ca90a8fea937b", |
| 813 | }, | 814 | }, |
| 814 | .{ | 815 | .{ |
| 815 | .mode = .argon2id, | 816 | .mode = .argon2id, |
| 816 | .time = 4, | 817 | .time = 4, |
| 817 | .memory = 4096, | 818 | .memory = 256, |
| 818 | .threads = 4, | 819 | .threads = 4, |
| 819 | .hash = "145db9733a9f4ee43edf33c509be96b934d505a4efb33c5a", | 820 | .hash = "fbd40d5a8cb92f88c20bda4b3cdb1f9d5af1efa937032410", |
| 820 | }, | 821 | }, |
| 821 | .{ | 822 | .{ |
| 822 | .mode = .argon2i, | 823 | .mode = .argon2i, |
| 823 | .time = 4, | 824 | .time = 4, |
| 824 | .memory = 1024, | 825 | .memory = 256, |
| 825 | .threads = 8, | 826 | .threads = 8, |
| 826 | .hash = "0cdd3956aa35e6b475a7b0c63488822f774f15b43f6e6e17", | 827 | .hash = "15d3c398364e53f68fd12d19baf3f21432d964254fe27467", |
| 827 | }, | 828 | }, |
| 828 | .{ | 829 | .{ |
| 829 | .mode = .argon2d, | 830 | .mode = .argon2d, |
| 830 | .time = 4, | 831 | .time = 4, |
| 831 | .memory = 1024, | 832 | .memory = 256, |
| 832 | .threads = 8, | 833 | .threads = 8, |
| 833 | .hash = "83604fc2ad0589b9d055578f4d3cc55bc616df3578a896e9", | 834 | .hash = "23c9adc06f06e21e4612c1466a1be02627690932b02c0df0", |
| 834 | }, | 835 | }, |
| 835 | .{ | 836 | .{ |
| 836 | .mode = .argon2id, | 837 | .mode = .argon2id, |
| 837 | .time = 4, | 838 | .time = 4, |
| 838 | .memory = 1024, | 839 | .memory = 256, |
| 839 | .threads = 8, | 840 | .threads = 8, |
| 840 | .hash = "8dafa8e004f8ea96bf7c0f93eecf67a6047476143d15577f", | 841 | .hash = "f22802f8ca47be93f9954e4ce20c1e944e938fbd4a125d9d", |
| 841 | }, | 842 | }, |
| 842 | .{ | 843 | .{ |
| 843 | .mode = .argon2i, | 844 | .mode = .argon2i, |
| ... | @@ -863,23 +864,23 @@ test "kdf" { | ... | @@ -863,23 +864,23 @@ test "kdf" { |
| 863 | .{ | 864 | .{ |
| 864 | .mode = .argon2i, | 865 | .mode = .argon2i, |
| 865 | .time = 3, | 866 | .time = 3, |
| 866 | .memory = 1024, | 867 | .memory = 256, |
| 867 | .threads = 6, | 868 | .threads = 6, |
| 868 | .hash = "d236b29c2b2a09babee842b0dec6aa1e83ccbdea8023dced", | 869 | .hash = "ebc8f91964abd8ceab49a12963b0a9e57d635bfa2aad2884", |
| 869 | }, | 870 | }, |
| 870 | .{ | 871 | .{ |
| 871 | .mode = .argon2d, | 872 | .mode = .argon2d, |
| 872 | .time = 3, | 873 | .time = 3, |
| 873 | .memory = 1024, | 874 | .memory = 256, |
| 874 | .threads = 6, | 875 | .threads = 6, |
| 875 | .hash = "a3351b0319a53229152023d9206902f4ef59661cdca89481", | 876 | .hash = "1dd7202fd68da6675f769f4034b7a1db30d8785331954117", |
| 876 | }, | 877 | }, |
| 877 | .{ | 878 | .{ |
| 878 | .mode = .argon2id, | 879 | .mode = .argon2id, |
| 879 | .time = 3, | 880 | .time = 3, |
| 880 | .memory = 1024, | 881 | .memory = 256, |
| 881 | .threads = 6, | 882 | .threads = 6, |
| 882 | .hash = "1640b932f4b60e272f5d2207b9a9c626ffa1bd88d2349016", | 883 | .hash = "424436b6ee22a66b04b9d0cf78f190305c5c166bae8baa09", |
| 883 | }, | 884 | }, |
| 884 | }; | 885 | }; |
| 885 | for (test_vectors) |v| { | 886 | for (test_vectors) |v| { |
| ... | @@ -894,6 +895,7 @@ test "kdf" { | ... | @@ -894,6 +895,7 @@ test "kdf" { |
| 894 | salt, | 895 | salt, |
| 895 | .{ .t = v.time, .m = v.memory, .p = v.threads }, | 896 | .{ .t = v.time, .m = v.memory, .p = v.threads }, |
| 896 | v.mode, | 897 | v.mode, |
| | 898 | std.testing.io, |
| 897 | ); | 899 | ); |
| 898 | | 900 | |
| 899 | try std.testing.expectEqualSlices(u8, &dk, &want); | 901 | try std.testing.expectEqualSlices(u8, &dk, &want); |
| ... | @@ -903,6 +905,7 @@ test "kdf" { | ... | @@ -903,6 +905,7 @@ test "kdf" { |
| 903 | test "phc format hasher" { | 905 | test "phc format hasher" { |
| 904 | const allocator = std.testing.allocator; | 906 | const allocator = std.testing.allocator; |
| 905 | const password = "testpass"; | 907 | const password = "testpass"; |
| | 908 | const io = std.testing.io; |
| 906 | | 909 | |
| 907 | var buf: [128]u8 = undefined; | 910 | var buf: [128]u8 = undefined; |
| 908 | const hash = try PhcFormatHasher.create( | 911 | const hash = try PhcFormatHasher.create( |
| ... | @@ -911,25 +914,29 @@ test "phc format hasher" { | ... | @@ -911,25 +914,29 @@ test "phc format hasher" { |
| 911 | .{ .t = 3, .m = 32, .p = 4 }, | 914 | .{ .t = 3, .m = 32, .p = 4 }, |
| 912 | .argon2id, | 915 | .argon2id, |
| 913 | &buf, | 916 | &buf, |
| | 917 | io, |
| 914 | ); | 918 | ); |
| 915 | try PhcFormatHasher.verify(allocator, hash, password); | 919 | try PhcFormatHasher.verify(allocator, hash, password, io); |
| 916 | } | 920 | } |
| 917 | | 921 | |
| 918 | test "password hash and password verify" { | 922 | test "password hash and password verify" { |
| 919 | const allocator = std.testing.allocator; | 923 | const allocator = std.testing.allocator; |
| 920 | const password = "testpass"; | 924 | const password = "testpass"; |
| | 925 | const io = std.testing.io; |
| 921 | | 926 | |
| 922 | var buf: [128]u8 = undefined; | 927 | var buf: [128]u8 = undefined; |
| 923 | const hash = try strHash( | 928 | const hash = try strHash( |
| 924 | password, | 929 | password, |
| 925 | .{ .allocator = allocator, .params = .{ .t = 3, .m = 32, .p = 4 } }, | 930 | .{ .allocator = allocator, .params = .{ .t = 3, .m = 32, .p = 4 } }, |
| 926 | &buf, | 931 | &buf, |
| | 932 | io, |
| 927 | ); | 933 | ); |
| 928 | try strVerify(hash, password, .{ .allocator = allocator }); | 934 | try strVerify(hash, password, .{ .allocator = allocator }, io); |
| 929 | } | 935 | } |
| 930 | | 936 | |
| 931 | test "kdf derived key length" { | 937 | test "kdf derived key length" { |
| 932 | const allocator = std.testing.allocator; | 938 | const allocator = std.testing.allocator; |
| | 939 | const io = std.testing.io; |
| 933 | | 940 | |
| 934 | const password = "testpass"; | 941 | const password = "testpass"; |
| 935 | const salt = "saltsalt"; | 942 | const salt = "saltsalt"; |
| ... | @@ -937,11 +944,11 @@ test "kdf derived key length" { | ... | @@ -937,11 +944,11 @@ test "kdf derived key length" { |
| 937 | const mode = Mode.argon2id; | 944 | const mode = Mode.argon2id; |
| 938 | | 945 | |
| 939 | var dk1: [11]u8 = undefined; | 946 | var dk1: [11]u8 = undefined; |
| 940 | try kdf(allocator, &dk1, password, salt, params, mode); | 947 | try kdf(allocator, &dk1, password, salt, params, mode, io); |
| 941 | | 948 | |
| 942 | var dk2: [77]u8 = undefined; | 949 | var dk2: [77]u8 = undefined; |
| 943 | try kdf(allocator, &dk2, password, salt, params, mode); | 950 | try kdf(allocator, &dk2, password, salt, params, mode, io); |
| 944 | | 951 | |
| 945 | var dk3: [111]u8 = undefined; | 952 | var dk3: [111]u8 = undefined; |
| 946 | try kdf(allocator, &dk3, password, salt, params, mode); | 953 | try kdf(allocator, &dk3, password, salt, params, mode, io); |
| 947 | } | 954 | } |