| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| | 2 | const base64 = std.base64; |
| 2 | const crypto = std.crypto; | 3 | const crypto = std.crypto; |
| 3 | const debug = std.debug; | 4 | const debug = std.debug; |
| 4 | const fmt = std.fmt; | 5 | const fmt = std.fmt; |
| ... | @@ -533,71 +534,10 @@ const crypt_format = struct { | ... | @@ -533,71 +534,10 @@ const crypt_format = struct { |
| 533 | pub const prefix = "$2"; | 534 | pub const prefix = "$2"; |
| 534 | | 535 | |
| 535 | // bcrypt has its own variant of base64, with its own alphabet and no padding | 536 | // bcrypt has its own variant of base64, with its own alphabet and no padding |
| 536 | const Codec = struct { | 537 | const bcrypt_alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".*; |
| 537 | const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | 538 | const Codec = struct { Encoder: base64.Base64Encoder, Decoder: base64.Base64Decoder }{ |
| 538 | | 539 | .Encoder = base64.Base64Encoder.init(bcrypt_alphabet, null), |
| 539 | fn encode(b64: []u8, bin: []const u8) void { | 540 | .Decoder = base64.Base64Decoder.init(bcrypt_alphabet, null), |
| 540 | var i: usize = 0; | | |
| 541 | var j: usize = 0; | | |
| 542 | while (i < bin.len) { | | |
| 543 | var c1 = bin[i]; | | |
| 544 | i += 1; | | |
| 545 | b64[j] = alphabet[c1 >> 2]; | | |
| 546 | j += 1; | | |
| 547 | c1 = (c1 & 3) << 4; | | |
| 548 | if (i >= bin.len) { | | |
| 549 | b64[j] = alphabet[c1]; | | |
| 550 | j += 1; | | |
| 551 | break; | | |
| 552 | } | | |
| 553 | var c2 = bin[i]; | | |
| 554 | i += 1; | | |
| 555 | c1 |= (c2 >> 4) & 0x0f; | | |
| 556 | b64[j] = alphabet[c1]; | | |
| 557 | j += 1; | | |
| 558 | c1 = (c2 & 0x0f) << 2; | | |
| 559 | if (i >= bin.len) { | | |
| 560 | b64[j] = alphabet[c1]; | | |
| 561 | j += 1; | | |
| 562 | break; | | |
| 563 | } | | |
| 564 | c2 = bin[i]; | | |
| 565 | i += 1; | | |
| 566 | c1 |= (c2 >> 6) & 3; | | |
| 567 | b64[j] = alphabet[c1]; | | |
| 568 | b64[j + 1] = alphabet[c2 & 0x3f]; | | |
| 569 | j += 2; | | |
| 570 | } | | |
| 571 | debug.assert(j == b64.len); | | |
| 572 | } | | |
| 573 | | | |
| 574 | fn decode(bin: []u8, b64: []const u8) EncodingError!void { | | |
| 575 | var i: usize = 0; | | |
| 576 | var j: usize = 0; | | |
| 577 | while (j < bin.len) { | | |
| 578 | const c1 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i]) orelse | | |
| 579 | return EncodingError.InvalidEncoding); | | |
| 580 | const c2 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 1]) orelse | | |
| 581 | return EncodingError.InvalidEncoding); | | |
| 582 | bin[j] = (c1 << 2) | ((c2 & 0x30) >> 4); | | |
| 583 | j += 1; | | |
| 584 | if (j >= bin.len) { | | |
| 585 | break; | | |
| 586 | } | | |
| 587 | const c3 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 2]) orelse | | |
| 588 | return EncodingError.InvalidEncoding); | | |
| 589 | bin[j] = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); | | |
| 590 | j += 1; | | |
| 591 | if (j >= bin.len) { | | |
| 592 | break; | | |
| 593 | } | | |
| 594 | const c4 = @intCast(u8, mem.indexOfScalar(u8, alphabet, b64[i + 3]) orelse | | |
| 595 | return EncodingError.InvalidEncoding); | | |
| 596 | bin[j] = ((c3 & 0x03) << 6) | c4; | | |
| 597 | j += 1; | | |
| 598 | i += 4; | | |
| 599 | } | | |
| 600 | } | | |
| 601 | }; | 541 | }; |
| 602 | | 542 | |
| 603 | fn strHashInternal( | 543 | fn strHashInternal( |
| ... | @@ -608,10 +548,10 @@ const crypt_format = struct { | ... | @@ -608,10 +548,10 @@ const crypt_format = struct { |
| 608 | var dk = bcrypt(password, salt, params); | 548 | var dk = bcrypt(password, salt, params); |
| 609 | | 549 | |
| 610 | var salt_str: [salt_str_length]u8 = undefined; | 550 | var salt_str: [salt_str_length]u8 = undefined; |
| 611 | Codec.encode(salt_str[0..], salt[0..]); | 551 | _ = Codec.Encoder.encode(salt_str[0..], salt[0..]); |
| 612 | | 552 | |
| 613 | var ct_str: [ct_str_length]u8 = undefined; | 553 | var ct_str: [ct_str_length]u8 = undefined; |
| 614 | Codec.encode(ct_str[0..], dk[0..]); | 554 | _ = Codec.Encoder.encode(ct_str[0..], dk[0..]); |
| 615 | | 555 | |
| 616 | var s_buf: [hash_length]u8 = undefined; | 556 | var s_buf: [hash_length]u8 = undefined; |
| 617 | const s = fmt.bufPrint( | 557 | const s = fmt.bufPrint( |
| ... | @@ -709,7 +649,7 @@ const CryptFormatHasher = struct { | ... | @@ -709,7 +649,7 @@ const CryptFormatHasher = struct { |
| 709 | | 649 | |
| 710 | const salt_str = str[7..][0..salt_str_length]; | 650 | const salt_str = str[7..][0..salt_str_length]; |
| 711 | var salt: [salt_length]u8 = undefined; | 651 | var salt: [salt_length]u8 = undefined; |
| 712 | try crypt_format.Codec.decode(salt[0..], salt_str[0..]); | 652 | crypt_format.Codec.Decoder.decode(salt[0..], salt_str[0..]) catch return HasherError.InvalidEncoding; |
| 713 | | 653 | |
| 714 | const wanted_s = crypt_format.strHashInternal(password, salt, .{ .rounds_log = rounds_log }); | 654 | const wanted_s = crypt_format.strHashInternal(password, salt, .{ .rounds_log = rounds_log }); |
| 715 | if (!mem.eql(u8, wanted_s[0..], str[0..])) return HasherError.PasswordVerificationFailed; | 655 | if (!mem.eql(u8, wanted_s[0..], str[0..])) return HasherError.PasswordVerificationFailed; |
| ... | @@ -764,9 +704,9 @@ test "bcrypt codec" { | ... | @@ -764,9 +704,9 @@ test "bcrypt codec" { |
| 764 | var salt: [salt_length]u8 = undefined; | 704 | var salt: [salt_length]u8 = undefined; |
| 765 | crypto.random.bytes(&salt); | 705 | crypto.random.bytes(&salt); |
| 766 | var salt_str: [salt_str_length]u8 = undefined; | 706 | var salt_str: [salt_str_length]u8 = undefined; |
| 767 | crypt_format.Codec.encode(salt_str[0..], salt[0..]); | 707 | _ = crypt_format.Codec.Encoder.encode(salt_str[0..], salt[0..]); |
| 768 | var salt2: [salt_length]u8 = undefined; | 708 | var salt2: [salt_length]u8 = undefined; |
| 769 | try crypt_format.Codec.decode(salt2[0..], salt_str[0..]); | 709 | try crypt_format.Codec.Decoder.decode(salt2[0..], salt_str[0..]); |
| 770 | try testing.expectEqualSlices(u8, salt[0..], salt2[0..]); | 710 | try testing.expectEqualSlices(u8, salt[0..], salt2[0..]); |
| 771 | } | 711 | } |
| 772 | | 712 | |