| ... | @@ -917,18 +917,20 @@ pub const rsa = struct { | ... | @@ -917,18 +917,20 @@ pub const rsa = struct { |
| 917 | return result; | 917 | return result; |
| 918 | } | 918 | } |
| 919 | | 919 | |
| 920 | pub fn verify(comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type, allocator: std.mem.Allocator) !void { | 920 | pub fn verify(comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type) !void { |
| 921 | const mod_bits = public_key.n.bits(); | 921 | const mod_bits = public_key.n.bits(); |
| 922 | const em_dec = try encrypt(modulus_len, sig, public_key); | 922 | const em_dec = try encrypt(modulus_len, sig, public_key); |
| 923 | | 923 | |
| 924 | EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash, allocator) catch unreachable; | 924 | EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash) catch unreachable; |
| 925 | } | 925 | } |
| 926 | | 926 | |
| 927 | fn EMSA_PSS_VERIFY(msg: []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type, allocator: std.mem.Allocator) !void { | 927 | fn EMSA_PSS_VERIFY(msg: []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type) !void { |
| 928 | // TODO | | |
| 929 | // 1. If the length of M is greater than the input limitation for | 928 | // 1. If the length of M is greater than the input limitation for |
| 930 | // the hash function (2^61 - 1 octets for SHA-1), output | 929 | // the hash function (2^61 - 1 octets for SHA-1), output |
| 931 | // "inconsistent" and stop. | 930 | // "inconsistent" and stop. |
| | 931 | // All the cryptographic hash functions in the standard library have a limit of >= 2^61 - 1. |
| | 932 | // Even then, this check is only there for paranoia. In the context of TLS certifcates, emBit cannot exceed 4096. |
| | 933 | if (emBit >= 1 << 61) return error.InvalidSignature; |
| 932 | | 934 | |
| 933 | // emLen = \ceil(emBits/8) | 935 | // emLen = \ceil(emBits/8) |
| 934 | const emLen = ((emBit - 1) / 8) + 1; | 936 | const emLen = ((emBit - 1) / 8) + 1; |
| ... | @@ -952,7 +954,7 @@ pub const rsa = struct { | ... | @@ -952,7 +954,7 @@ pub const rsa = struct { |
| 952 | // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, | 954 | // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, |
| 953 | // and let H be the next hLen octets. | 955 | // and let H be the next hLen octets. |
| 954 | const maskedDB = em[0..(emLen - Hash.digest_length - 1)]; | 956 | const maskedDB = em[0..(emLen - Hash.digest_length - 1)]; |
| 955 | const h = em[(emLen - Hash.digest_length - 1)..(emLen - 1)]; | 957 | const h = em[(emLen - Hash.digest_length - 1)..(emLen - 1)][0..Hash.digest_length]; |
| 956 | | 958 | |
| 957 | // 6. If the leftmost 8emLen - emBits bits of the leftmost octet in | 959 | // 6. If the leftmost 8emLen - emBits bits of the leftmost octet in |
| 958 | // maskedDB are not all equal to zero, output "inconsistent" and | 960 | // maskedDB are not all equal to zero, output "inconsistent" and |
| ... | @@ -969,9 +971,12 @@ pub const rsa = struct { | ... | @@ -969,9 +971,12 @@ pub const rsa = struct { |
| 969 | | 971 | |
| 970 | // 7. Let dbMask = MGF(H, emLen - hLen - 1). | 972 | // 7. Let dbMask = MGF(H, emLen - hLen - 1). |
| 971 | const mgf_len = emLen - Hash.digest_length - 1; | 973 | const mgf_len = emLen - Hash.digest_length - 1; |
| 972 | var mgf_out = try allocator.alloc(u8, ((mgf_len - 1) / Hash.digest_length + 1) * Hash.digest_length); | 974 | var mgf_out_buf: [512]u8 = undefined; |
| 973 | defer allocator.free(mgf_out); | 975 | if (mgf_len > mgf_out_buf.len) { // Modulus > 4096 bits |
| 974 | var dbMask = try MGF1(mgf_out, h, mgf_len, Hash, allocator); | 976 | return error.InvalidSignature; |
| | 977 | } |
| | 978 | var mgf_out = mgf_out_buf[0 .. ((mgf_len - 1) / Hash.digest_length + 1) * Hash.digest_length]; |
| | 979 | var dbMask = try MGF1(Hash, mgf_out, h, mgf_len); |
| 975 | | 980 | |
| 976 | // 8. Let DB = maskedDB \xor dbMask. | 981 | // 8. Let DB = maskedDB \xor dbMask. |
| 977 | i = 0; | 982 | i = 0; |
| ... | @@ -1008,8 +1013,11 @@ pub const rsa = struct { | ... | @@ -1008,8 +1013,11 @@ pub const rsa = struct { |
| 1008 | // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; | 1013 | // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ; |
| 1009 | // M' is an octet string of length 8 + hLen + sLen with eight | 1014 | // M' is an octet string of length 8 + hLen + sLen with eight |
| 1010 | // initial zero octets. | 1015 | // initial zero octets. |
| 1011 | var m_p = try allocator.alloc(u8, 8 + Hash.digest_length + sLen); | 1016 | if (sLen > Hash.digest_length) { // A seed larger than the hash length would be useless |
| 1012 | defer allocator.free(m_p); | 1017 | return error.InvalidSignature; |
| | 1018 | } |
| | 1019 | var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined; |
| | 1020 | var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen]; |
| 1013 | std.mem.copyForwards(u8, m_p, &([_]u8{0} ** 8)); | 1021 | std.mem.copyForwards(u8, m_p, &([_]u8{0} ** 8)); |
| 1014 | std.mem.copyForwards(u8, m_p[8..], &mHash); | 1022 | std.mem.copyForwards(u8, m_p[8..], &mHash); |
| 1015 | std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt); | 1023 | std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt); |
| ... | @@ -1025,14 +1033,12 @@ pub const rsa = struct { | ... | @@ -1025,14 +1033,12 @@ pub const rsa = struct { |
| 1025 | } | 1033 | } |
| 1026 | } | 1034 | } |
| 1027 | | 1035 | |
| 1028 | fn MGF1(out: []u8, seed: []const u8, len: usize, comptime Hash: type, allocator: std.mem.Allocator) ![]u8 { | 1036 | fn MGF1(comptime Hash: type, out: []u8, seed: *const [Hash.digest_length]u8, len: usize) ![]u8 { |
| 1029 | var counter: usize = 0; | 1037 | var counter: usize = 0; |
| 1030 | var idx: usize = 0; | 1038 | var idx: usize = 0; |
| 1031 | var c: [4]u8 = undefined; | 1039 | var c: [4]u8 = undefined; |
| 1032 | | 1040 | var hash: [Hash.digest_length + c.len]u8 = undefined; |
| 1033 | var hash = try allocator.alloc(u8, seed.len + c.len); | 1041 | @memcpy(hash[0..Hash.digest_length], seed); |
| 1034 | defer allocator.free(hash); | | |
| 1035 | std.mem.copyForwards(u8, hash, seed); | | |
| 1036 | var hashed: [Hash.digest_length]u8 = undefined; | 1042 | var hashed: [Hash.digest_length]u8 = undefined; |
| 1037 | | 1043 | |
| 1038 | while (idx < len) { | 1044 | while (idx < len) { |
| ... | @@ -1042,7 +1048,7 @@ pub const rsa = struct { | ... | @@ -1042,7 +1048,7 @@ pub const rsa = struct { |
| 1042 | c[3] = @intCast(u8, counter & 0xFF); | 1048 | c[3] = @intCast(u8, counter & 0xFF); |
| 1043 | | 1049 | |
| 1044 | std.mem.copyForwards(u8, hash[seed.len..], &c); | 1050 | std.mem.copyForwards(u8, hash[seed.len..], &c); |
| 1045 | Hash.hash(hash, &hashed, .{}); | 1051 | Hash.hash(&hash, &hashed, .{}); |
| 1046 | | 1052 | |
| 1047 | std.mem.copyForwards(u8, out[idx..], &hashed); | 1053 | std.mem.copyForwards(u8, out[idx..], &hashed); |
| 1048 | idx += hashed.len; | 1054 | idx += hashed.len; |