| author | |
| committer | |
| log | 96a4e9b866ee899fcae164693a47b68d18f56257 |
| tree | f11a31331b2c071a462fc693e72e03cd0ef347b4 |
| parent | 5a8acc91158e84d1478478cbf6aa510091708b93 |
3 files changed, 308 insertions(+), 323 deletions(-)
lib/std/crypto.zig+2-4| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | //! Cryptography. | 1 | //! Cryptography. |
| 2 | 2 | ||
| 3 | const root = @import("root"); | 3 | const std = @import("std.zig"); |
| 4 | 4 | ||
| 5 | pub const timing_safe = @import("crypto/timing_safe.zig"); | 5 | pub const timing_safe = @import("crypto/timing_safe.zig"); |
| 6 | 6 | ||
| ... | @@ -118,7 +118,7 @@ pub const hash = struct { | ... | @@ -118,7 +118,7 @@ pub const hash = struct { |
| 118 | pub const blake2 = @import("crypto/blake2.zig"); | 118 | pub const blake2 = @import("crypto/blake2.zig"); |
| 119 | pub const Blake3 = @import("crypto/blake3.zig").Blake3; | 119 | pub const Blake3 = @import("crypto/blake3.zig").Blake3; |
| 120 | pub const Md5 = @import("crypto/md5.zig").Md5; | 120 | pub const Md5 = @import("crypto/md5.zig").Md5; |
| 121 | pub const Sha1 = @import("crypto/sha1.zig").Sha1; | 121 | pub const Sha1 = @import("crypto/Sha1.zig"); |
| 122 | pub const sha2 = @import("crypto/sha2.zig"); | 122 | pub const sha2 = @import("crypto/sha2.zig"); |
| 123 | pub const sha3 = @import("crypto/sha3.zig"); | 123 | pub const sha3 = @import("crypto/sha3.zig"); |
| 124 | pub const composition = @import("crypto/hash_composition.zig"); | 124 | pub const composition = @import("crypto/hash_composition.zig"); |
| ... | @@ -216,8 +216,6 @@ pub const random = @import("crypto/tlcsprng.zig").interface; | ... | @@ -216,8 +216,6 @@ pub const random = @import("crypto/tlcsprng.zig").interface; |
| 216 | /// Encoding and decoding | 216 | /// Encoding and decoding |
| 217 | pub const codecs = @import("crypto/codecs.zig"); | 217 | pub const codecs = @import("crypto/codecs.zig"); |
| 218 | 218 | ||
| 219 | const std = @import("std.zig"); | ||
| 220 | |||
| 221 | pub const errors = @import("crypto/errors.zig"); | 219 | pub const errors = @import("crypto/errors.zig"); |
| 222 | 220 | ||
| 223 | pub const tls = @import("crypto/tls.zig"); | 221 | pub const tls = @import("crypto/tls.zig"); |
lib/std/crypto/Sha1.zig created+306| ... | @@ -0,0 +1,306 @@ | ||
| 1 | //! The SHA-1 function is now considered cryptographically broken. | ||
| 2 | //! Namely, it is feasible to find multiple inputs producing the same hash. | ||
| 3 | //! For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. | ||
| 4 | |||
| 5 | const std = @import("../std.zig"); | ||
| 6 | const mem = std.mem; | ||
| 7 | const math = std.math; | ||
| 8 | const Sha1 = @This(); | ||
| 9 | |||
| 10 | pub const block_length = 64; | ||
| 11 | pub const digest_length = 20; | ||
| 12 | pub const Options = struct {}; | ||
| 13 | |||
| 14 | s: [5]u32, | ||
| 15 | /// Streaming Cache | ||
| 16 | buf: [64]u8 = undefined, | ||
| 17 | buf_len: u8 = 0, | ||
| 18 | total_len: u64 = 0, | ||
| 19 | |||
| 20 | pub fn init(options: Options) Sha1 { | ||
| 21 | _ = options; | ||
| 22 | return .{ | ||
| 23 | .s = [_]u32{ | ||
| 24 | 0x67452301, | ||
| 25 | 0xEFCDAB89, | ||
| 26 | 0x98BADCFE, | ||
| 27 | 0x10325476, | ||
| 28 | 0xC3D2E1F0, | ||
| 29 | }, | ||
| 30 | }; | ||
| 31 | } | ||
| 32 | |||
| 33 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { | ||
| 34 | var d = Sha1.init(options); | ||
| 35 | d.update(b); | ||
| 36 | d.final(out); | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn update(d: *Sha1, b: []const u8) void { | ||
| 40 | var off: usize = 0; | ||
| 41 | |||
| 42 | // Partial buffer exists from previous update. Copy into buffer then hash. | ||
| 43 | if (d.buf_len != 0 and d.buf_len + b.len >= 64) { | ||
| 44 | off += 64 - d.buf_len; | ||
| 45 | @memcpy(d.buf[d.buf_len..][0..off], b[0..off]); | ||
| 46 | |||
| 47 | d.round(d.buf[0..]); | ||
| 48 | d.buf_len = 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | // Full middle blocks. | ||
| 52 | while (off + 64 <= b.len) : (off += 64) { | ||
| 53 | d.round(b[off..][0..64]); | ||
| 54 | } | ||
| 55 | |||
| 56 | // Copy any remainder for next pass. | ||
| 57 | @memcpy(d.buf[d.buf_len..][0 .. b.len - off], b[off..]); | ||
| 58 | d.buf_len += @as(u8, @intCast(b[off..].len)); | ||
| 59 | |||
| 60 | d.total_len += b.len; | ||
| 61 | } | ||
| 62 | |||
| 63 | pub fn peek(d: Sha1) [digest_length]u8 { | ||
| 64 | var copy = d; | ||
| 65 | return copy.finalResult(); | ||
| 66 | } | ||
| 67 | |||
| 68 | pub fn final(d: *Sha1, out: *[digest_length]u8) void { | ||
| 69 | // The buffer here will never be completely full. | ||
| 70 | @memset(d.buf[d.buf_len..], 0); | ||
| 71 | |||
| 72 | // Append padding bits. | ||
| 73 | d.buf[d.buf_len] = 0x80; | ||
| 74 | d.buf_len += 1; | ||
| 75 | |||
| 76 | // > 448 mod 512 so need to add an extra round to wrap around. | ||
| 77 | if (64 - d.buf_len < 8) { | ||
| 78 | d.round(d.buf[0..]); | ||
| 79 | @memset(d.buf[0..], 0); | ||
| 80 | } | ||
| 81 | |||
| 82 | // Append message length. | ||
| 83 | var i: usize = 1; | ||
| 84 | var len = d.total_len >> 5; | ||
| 85 | d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3; | ||
| 86 | while (i < 8) : (i += 1) { | ||
| 87 | d.buf[63 - i] = @as(u8, @intCast(len & 0xff)); | ||
| 88 | len >>= 8; | ||
| 89 | } | ||
| 90 | |||
| 91 | d.round(d.buf[0..]); | ||
| 92 | |||
| 93 | for (d.s, 0..) |s, j| { | ||
| 94 | mem.writeInt(u32, out[4 * j ..][0..4], s, .big); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn finalResult(d: *Sha1) [digest_length]u8 { | ||
| 99 | var result: [digest_length]u8 = undefined; | ||
| 100 | d.final(&result); | ||
| 101 | return result; | ||
| 102 | } | ||
| 103 | |||
| 104 | fn round(d: *Sha1, b: *const [64]u8) void { | ||
| 105 | var s: [16]u32 = undefined; | ||
| 106 | |||
| 107 | var v: [5]u32 = [_]u32{ | ||
| 108 | d.s[0], | ||
| 109 | d.s[1], | ||
| 110 | d.s[2], | ||
| 111 | d.s[3], | ||
| 112 | d.s[4], | ||
| 113 | }; | ||
| 114 | |||
| 115 | const round0a = comptime [_]RoundParam{ | ||
| 116 | .abcdei(0, 1, 2, 3, 4, 0), | ||
| 117 | .abcdei(4, 0, 1, 2, 3, 1), | ||
| 118 | .abcdei(3, 4, 0, 1, 2, 2), | ||
| 119 | .abcdei(2, 3, 4, 0, 1, 3), | ||
| 120 | .abcdei(1, 2, 3, 4, 0, 4), | ||
| 121 | .abcdei(0, 1, 2, 3, 4, 5), | ||
| 122 | .abcdei(4, 0, 1, 2, 3, 6), | ||
| 123 | .abcdei(3, 4, 0, 1, 2, 7), | ||
| 124 | .abcdei(2, 3, 4, 0, 1, 8), | ||
| 125 | .abcdei(1, 2, 3, 4, 0, 9), | ||
| 126 | .abcdei(0, 1, 2, 3, 4, 10), | ||
| 127 | .abcdei(4, 0, 1, 2, 3, 11), | ||
| 128 | .abcdei(3, 4, 0, 1, 2, 12), | ||
| 129 | .abcdei(2, 3, 4, 0, 1, 13), | ||
| 130 | .abcdei(1, 2, 3, 4, 0, 14), | ||
| 131 | .abcdei(0, 1, 2, 3, 4, 15), | ||
| 132 | }; | ||
| 133 | inline for (round0a) |r| { | ||
| 134 | s[r.i] = mem.readInt(u32, b[r.i * 4 ..][0..4], .big); | ||
| 135 | |||
| 136 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d])); | ||
| 137 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 138 | } | ||
| 139 | |||
| 140 | const round0b = comptime [_]RoundParam{ | ||
| 141 | .abcdei(4, 0, 1, 2, 3, 16), | ||
| 142 | .abcdei(3, 4, 0, 1, 2, 17), | ||
| 143 | .abcdei(2, 3, 4, 0, 1, 18), | ||
| 144 | .abcdei(1, 2, 3, 4, 0, 19), | ||
| 145 | }; | ||
| 146 | inline for (round0b) |r| { | ||
| 147 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 148 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 149 | |||
| 150 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d])); | ||
| 151 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 152 | } | ||
| 153 | |||
| 154 | const round1 = comptime [_]RoundParam{ | ||
| 155 | .abcdei(0, 1, 2, 3, 4, 20), | ||
| 156 | .abcdei(4, 0, 1, 2, 3, 21), | ||
| 157 | .abcdei(3, 4, 0, 1, 2, 22), | ||
| 158 | .abcdei(2, 3, 4, 0, 1, 23), | ||
| 159 | .abcdei(1, 2, 3, 4, 0, 24), | ||
| 160 | .abcdei(0, 1, 2, 3, 4, 25), | ||
| 161 | .abcdei(4, 0, 1, 2, 3, 26), | ||
| 162 | .abcdei(3, 4, 0, 1, 2, 27), | ||
| 163 | .abcdei(2, 3, 4, 0, 1, 28), | ||
| 164 | .abcdei(1, 2, 3, 4, 0, 29), | ||
| 165 | .abcdei(0, 1, 2, 3, 4, 30), | ||
| 166 | .abcdei(4, 0, 1, 2, 3, 31), | ||
| 167 | .abcdei(3, 4, 0, 1, 2, 32), | ||
| 168 | .abcdei(2, 3, 4, 0, 1, 33), | ||
| 169 | .abcdei(1, 2, 3, 4, 0, 34), | ||
| 170 | .abcdei(0, 1, 2, 3, 4, 35), | ||
| 171 | .abcdei(4, 0, 1, 2, 3, 36), | ||
| 172 | .abcdei(3, 4, 0, 1, 2, 37), | ||
| 173 | .abcdei(2, 3, 4, 0, 1, 38), | ||
| 174 | .abcdei(1, 2, 3, 4, 0, 39), | ||
| 175 | }; | ||
| 176 | inline for (round1) |r| { | ||
| 177 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 178 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 179 | |||
| 180 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]); | ||
| 181 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 182 | } | ||
| 183 | |||
| 184 | const round2 = comptime [_]RoundParam{ | ||
| 185 | .abcdei(0, 1, 2, 3, 4, 40), | ||
| 186 | .abcdei(4, 0, 1, 2, 3, 41), | ||
| 187 | .abcdei(3, 4, 0, 1, 2, 42), | ||
| 188 | .abcdei(2, 3, 4, 0, 1, 43), | ||
| 189 | .abcdei(1, 2, 3, 4, 0, 44), | ||
| 190 | .abcdei(0, 1, 2, 3, 4, 45), | ||
| 191 | .abcdei(4, 0, 1, 2, 3, 46), | ||
| 192 | .abcdei(3, 4, 0, 1, 2, 47), | ||
| 193 | .abcdei(2, 3, 4, 0, 1, 48), | ||
| 194 | .abcdei(1, 2, 3, 4, 0, 49), | ||
| 195 | .abcdei(0, 1, 2, 3, 4, 50), | ||
| 196 | .abcdei(4, 0, 1, 2, 3, 51), | ||
| 197 | .abcdei(3, 4, 0, 1, 2, 52), | ||
| 198 | .abcdei(2, 3, 4, 0, 1, 53), | ||
| 199 | .abcdei(1, 2, 3, 4, 0, 54), | ||
| 200 | .abcdei(0, 1, 2, 3, 4, 55), | ||
| 201 | .abcdei(4, 0, 1, 2, 3, 56), | ||
| 202 | .abcdei(3, 4, 0, 1, 2, 57), | ||
| 203 | .abcdei(2, 3, 4, 0, 1, 58), | ||
| 204 | .abcdei(1, 2, 3, 4, 0, 59), | ||
| 205 | }; | ||
| 206 | inline for (round2) |r| { | ||
| 207 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 208 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 209 | |||
| 210 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d])); | ||
| 211 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 212 | } | ||
| 213 | |||
| 214 | const round3 = comptime [_]RoundParam{ | ||
| 215 | .abcdei(0, 1, 2, 3, 4, 60), | ||
| 216 | .abcdei(4, 0, 1, 2, 3, 61), | ||
| 217 | .abcdei(3, 4, 0, 1, 2, 62), | ||
| 218 | .abcdei(2, 3, 4, 0, 1, 63), | ||
| 219 | .abcdei(1, 2, 3, 4, 0, 64), | ||
| 220 | .abcdei(0, 1, 2, 3, 4, 65), | ||
| 221 | .abcdei(4, 0, 1, 2, 3, 66), | ||
| 222 | .abcdei(3, 4, 0, 1, 2, 67), | ||
| 223 | .abcdei(2, 3, 4, 0, 1, 68), | ||
| 224 | .abcdei(1, 2, 3, 4, 0, 69), | ||
| 225 | .abcdei(0, 1, 2, 3, 4, 70), | ||
| 226 | .abcdei(4, 0, 1, 2, 3, 71), | ||
| 227 | .abcdei(3, 4, 0, 1, 2, 72), | ||
| 228 | .abcdei(2, 3, 4, 0, 1, 73), | ||
| 229 | .abcdei(1, 2, 3, 4, 0, 74), | ||
| 230 | .abcdei(0, 1, 2, 3, 4, 75), | ||
| 231 | .abcdei(4, 0, 1, 2, 3, 76), | ||
| 232 | .abcdei(3, 4, 0, 1, 2, 77), | ||
| 233 | .abcdei(2, 3, 4, 0, 1, 78), | ||
| 234 | .abcdei(1, 2, 3, 4, 0, 79), | ||
| 235 | }; | ||
| 236 | inline for (round3) |r| { | ||
| 237 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 238 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 239 | |||
| 240 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]); | ||
| 241 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 242 | } | ||
| 243 | |||
| 244 | d.s[0] +%= v[0]; | ||
| 245 | d.s[1] +%= v[1]; | ||
| 246 | d.s[2] +%= v[2]; | ||
| 247 | d.s[3] +%= v[3]; | ||
| 248 | d.s[4] +%= v[4]; | ||
| 249 | } | ||
| 250 | |||
| 251 | const RoundParam = struct { | ||
| 252 | a: usize, | ||
| 253 | b: usize, | ||
| 254 | c: usize, | ||
| 255 | d: usize, | ||
| 256 | e: usize, | ||
| 257 | i: u32, | ||
| 258 | |||
| 259 | fn abcdei(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam { | ||
| 260 | return .{ | ||
| 261 | .a = a, | ||
| 262 | .b = b, | ||
| 263 | .c = c, | ||
| 264 | .d = d, | ||
| 265 | .e = e, | ||
| 266 | .i = i, | ||
| 267 | }; | ||
| 268 | } | ||
| 269 | }; | ||
| 270 | |||
| 271 | const htest = @import("test.zig"); | ||
| 272 | |||
| 273 | test "sha1 single" { | ||
| 274 | try htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", ""); | ||
| 275 | try htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc"); | ||
| 276 | try htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); | ||
| 277 | } | ||
| 278 | |||
| 279 | test "sha1 streaming" { | ||
| 280 | var h = Sha1.init(.{}); | ||
| 281 | var out: [20]u8 = undefined; | ||
| 282 | |||
| 283 | h.final(&out); | ||
| 284 | try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); | ||
| 285 | |||
| 286 | h = Sha1.init(.{}); | ||
| 287 | h.update("abc"); | ||
| 288 | h.final(&out); | ||
| 289 | try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); | ||
| 290 | |||
| 291 | h = Sha1.init(.{}); | ||
| 292 | h.update("a"); | ||
| 293 | h.update("b"); | ||
| 294 | h.update("c"); | ||
| 295 | h.final(&out); | ||
| 296 | try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); | ||
| 297 | } | ||
| 298 | |||
| 299 | test "sha1 aligned final" { | ||
| 300 | var block = [_]u8{0} ** Sha1.block_length; | ||
| 301 | var out: [Sha1.digest_length]u8 = undefined; | ||
| 302 | |||
| 303 | var h = Sha1.init(.{}); | ||
| 304 | h.update(&block); | ||
| 305 | h.final(out[0..]); | ||
| 306 | } | ||
lib/std/crypto/sha1.zig deleted-319| ... | @@ -1,319 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const math = std.math; | ||
| 4 | |||
| 5 | const RoundParam = struct { | ||
| 6 | a: usize, | ||
| 7 | b: usize, | ||
| 8 | c: usize, | ||
| 9 | d: usize, | ||
| 10 | e: usize, | ||
| 11 | i: u32, | ||
| 12 | }; | ||
| 13 | |||
| 14 | fn roundParam(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam { | ||
| 15 | return RoundParam{ | ||
| 16 | .a = a, | ||
| 17 | .b = b, | ||
| 18 | .c = c, | ||
| 19 | .d = d, | ||
| 20 | .e = e, | ||
| 21 | .i = i, | ||
| 22 | }; | ||
| 23 | } | ||
| 24 | |||
| 25 | /// The SHA-1 function is now considered cryptographically broken. | ||
| 26 | /// Namely, it is feasible to find multiple inputs producing the same hash. | ||
| 27 | /// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3. | ||
| 28 | pub const Sha1 = struct { | ||
| 29 | const Self = @This(); | ||
| 30 | pub const block_length = 64; | ||
| 31 | pub const digest_length = 20; | ||
| 32 | pub const Options = struct {}; | ||
| 33 | |||
| 34 | s: [5]u32, | ||
| 35 | // Streaming Cache | ||
| 36 | buf: [64]u8 = undefined, | ||
| 37 | buf_len: u8 = 0, | ||
| 38 | total_len: u64 = 0, | ||
| 39 | |||
| 40 | pub fn init(options: Options) Self { | ||
| 41 | _ = options; | ||
| 42 | return Self{ | ||
| 43 | .s = [_]u32{ | ||
| 44 | 0x67452301, | ||
| 45 | 0xEFCDAB89, | ||
| 46 | 0x98BADCFE, | ||
| 47 | 0x10325476, | ||
| 48 | 0xC3D2E1F0, | ||
| 49 | }, | ||
| 50 | }; | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { | ||
| 54 | var d = Sha1.init(options); | ||
| 55 | d.update(b); | ||
| 56 | d.final(out); | ||
| 57 | } | ||
| 58 | |||
| 59 | pub fn update(d: *Self, b: []const u8) void { | ||
| 60 | var off: usize = 0; | ||
| 61 | |||
| 62 | // Partial buffer exists from previous update. Copy into buffer then hash. | ||
| 63 | if (d.buf_len != 0 and d.buf_len + b.len >= 64) { | ||
| 64 | off += 64 - d.buf_len; | ||
| 65 | @memcpy(d.buf[d.buf_len..][0..off], b[0..off]); | ||
| 66 | |||
| 67 | d.round(d.buf[0..]); | ||
| 68 | d.buf_len = 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | // Full middle blocks. | ||
| 72 | while (off + 64 <= b.len) : (off += 64) { | ||
| 73 | d.round(b[off..][0..64]); | ||
| 74 | } | ||
| 75 | |||
| 76 | // Copy any remainder for next pass. | ||
| 77 | @memcpy(d.buf[d.buf_len..][0 .. b.len - off], b[off..]); | ||
| 78 | d.buf_len += @as(u8, @intCast(b[off..].len)); | ||
| 79 | |||
| 80 | d.total_len += b.len; | ||
| 81 | } | ||
| 82 | |||
| 83 | pub fn peek(d: Self) [digest_length]u8 { | ||
| 84 | var copy = d; | ||
| 85 | return copy.finalResult(); | ||
| 86 | } | ||
| 87 | |||
| 88 | pub fn final(d: *Self, out: *[digest_length]u8) void { | ||
| 89 | // The buffer here will never be completely full. | ||
| 90 | @memset(d.buf[d.buf_len..], 0); | ||
| 91 | |||
| 92 | // Append padding bits. | ||
| 93 | d.buf[d.buf_len] = 0x80; | ||
| 94 | d.buf_len += 1; | ||
| 95 | |||
| 96 | // > 448 mod 512 so need to add an extra round to wrap around. | ||
| 97 | if (64 - d.buf_len < 8) { | ||
| 98 | d.round(d.buf[0..]); | ||
| 99 | @memset(d.buf[0..], 0); | ||
| 100 | } | ||
| 101 | |||
| 102 | // Append message length. | ||
| 103 | var i: usize = 1; | ||
| 104 | var len = d.total_len >> 5; | ||
| 105 | d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3; | ||
| 106 | while (i < 8) : (i += 1) { | ||
| 107 | d.buf[63 - i] = @as(u8, @intCast(len & 0xff)); | ||
| 108 | len >>= 8; | ||
| 109 | } | ||
| 110 | |||
| 111 | d.round(d.buf[0..]); | ||
| 112 | |||
| 113 | for (d.s, 0..) |s, j| { | ||
| 114 | mem.writeInt(u32, out[4 * j ..][0..4], s, .big); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | pub fn finalResult(d: *Self) [digest_length]u8 { | ||
| 119 | var result: [digest_length]u8 = undefined; | ||
| 120 | d.final(&result); | ||
| 121 | return result; | ||
| 122 | } | ||
| 123 | |||
| 124 | fn round(d: *Self, b: *const [64]u8) void { | ||
| 125 | var s: [16]u32 = undefined; | ||
| 126 | |||
| 127 | var v: [5]u32 = [_]u32{ | ||
| 128 | d.s[0], | ||
| 129 | d.s[1], | ||
| 130 | d.s[2], | ||
| 131 | d.s[3], | ||
| 132 | d.s[4], | ||
| 133 | }; | ||
| 134 | |||
| 135 | const round0a = comptime [_]RoundParam{ | ||
| 136 | roundParam(0, 1, 2, 3, 4, 0), | ||
| 137 | roundParam(4, 0, 1, 2, 3, 1), | ||
| 138 | roundParam(3, 4, 0, 1, 2, 2), | ||
| 139 | roundParam(2, 3, 4, 0, 1, 3), | ||
| 140 | roundParam(1, 2, 3, 4, 0, 4), | ||
| 141 | roundParam(0, 1, 2, 3, 4, 5), | ||
| 142 | roundParam(4, 0, 1, 2, 3, 6), | ||
| 143 | roundParam(3, 4, 0, 1, 2, 7), | ||
| 144 | roundParam(2, 3, 4, 0, 1, 8), | ||
| 145 | roundParam(1, 2, 3, 4, 0, 9), | ||
| 146 | roundParam(0, 1, 2, 3, 4, 10), | ||
| 147 | roundParam(4, 0, 1, 2, 3, 11), | ||
| 148 | roundParam(3, 4, 0, 1, 2, 12), | ||
| 149 | roundParam(2, 3, 4, 0, 1, 13), | ||
| 150 | roundParam(1, 2, 3, 4, 0, 14), | ||
| 151 | roundParam(0, 1, 2, 3, 4, 15), | ||
| 152 | }; | ||
| 153 | inline for (round0a) |r| { | ||
| 154 | s[r.i] = mem.readInt(u32, b[r.i * 4 ..][0..4], .big); | ||
| 155 | |||
| 156 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d])); | ||
| 157 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 158 | } | ||
| 159 | |||
| 160 | const round0b = comptime [_]RoundParam{ | ||
| 161 | roundParam(4, 0, 1, 2, 3, 16), | ||
| 162 | roundParam(3, 4, 0, 1, 2, 17), | ||
| 163 | roundParam(2, 3, 4, 0, 1, 18), | ||
| 164 | roundParam(1, 2, 3, 4, 0, 19), | ||
| 165 | }; | ||
| 166 | inline for (round0b) |r| { | ||
| 167 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 168 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 169 | |||
| 170 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x5A827999 +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d])); | ||
| 171 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 172 | } | ||
| 173 | |||
| 174 | const round1 = comptime [_]RoundParam{ | ||
| 175 | roundParam(0, 1, 2, 3, 4, 20), | ||
| 176 | roundParam(4, 0, 1, 2, 3, 21), | ||
| 177 | roundParam(3, 4, 0, 1, 2, 22), | ||
| 178 | roundParam(2, 3, 4, 0, 1, 23), | ||
| 179 | roundParam(1, 2, 3, 4, 0, 24), | ||
| 180 | roundParam(0, 1, 2, 3, 4, 25), | ||
| 181 | roundParam(4, 0, 1, 2, 3, 26), | ||
| 182 | roundParam(3, 4, 0, 1, 2, 27), | ||
| 183 | roundParam(2, 3, 4, 0, 1, 28), | ||
| 184 | roundParam(1, 2, 3, 4, 0, 29), | ||
| 185 | roundParam(0, 1, 2, 3, 4, 30), | ||
| 186 | roundParam(4, 0, 1, 2, 3, 31), | ||
| 187 | roundParam(3, 4, 0, 1, 2, 32), | ||
| 188 | roundParam(2, 3, 4, 0, 1, 33), | ||
| 189 | roundParam(1, 2, 3, 4, 0, 34), | ||
| 190 | roundParam(0, 1, 2, 3, 4, 35), | ||
| 191 | roundParam(4, 0, 1, 2, 3, 36), | ||
| 192 | roundParam(3, 4, 0, 1, 2, 37), | ||
| 193 | roundParam(2, 3, 4, 0, 1, 38), | ||
| 194 | roundParam(1, 2, 3, 4, 0, 39), | ||
| 195 | }; | ||
| 196 | inline for (round1) |r| { | ||
| 197 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 198 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 199 | |||
| 200 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x6ED9EBA1 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]); | ||
| 201 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 202 | } | ||
| 203 | |||
| 204 | const round2 = comptime [_]RoundParam{ | ||
| 205 | roundParam(0, 1, 2, 3, 4, 40), | ||
| 206 | roundParam(4, 0, 1, 2, 3, 41), | ||
| 207 | roundParam(3, 4, 0, 1, 2, 42), | ||
| 208 | roundParam(2, 3, 4, 0, 1, 43), | ||
| 209 | roundParam(1, 2, 3, 4, 0, 44), | ||
| 210 | roundParam(0, 1, 2, 3, 4, 45), | ||
| 211 | roundParam(4, 0, 1, 2, 3, 46), | ||
| 212 | roundParam(3, 4, 0, 1, 2, 47), | ||
| 213 | roundParam(2, 3, 4, 0, 1, 48), | ||
| 214 | roundParam(1, 2, 3, 4, 0, 49), | ||
| 215 | roundParam(0, 1, 2, 3, 4, 50), | ||
| 216 | roundParam(4, 0, 1, 2, 3, 51), | ||
| 217 | roundParam(3, 4, 0, 1, 2, 52), | ||
| 218 | roundParam(2, 3, 4, 0, 1, 53), | ||
| 219 | roundParam(1, 2, 3, 4, 0, 54), | ||
| 220 | roundParam(0, 1, 2, 3, 4, 55), | ||
| 221 | roundParam(4, 0, 1, 2, 3, 56), | ||
| 222 | roundParam(3, 4, 0, 1, 2, 57), | ||
| 223 | roundParam(2, 3, 4, 0, 1, 58), | ||
| 224 | roundParam(1, 2, 3, 4, 0, 59), | ||
| 225 | }; | ||
| 226 | inline for (round2) |r| { | ||
| 227 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 228 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 229 | |||
| 230 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0x8F1BBCDC +% s[r.i & 0xf] +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d])); | ||
| 231 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 232 | } | ||
| 233 | |||
| 234 | const round3 = comptime [_]RoundParam{ | ||
| 235 | roundParam(0, 1, 2, 3, 4, 60), | ||
| 236 | roundParam(4, 0, 1, 2, 3, 61), | ||
| 237 | roundParam(3, 4, 0, 1, 2, 62), | ||
| 238 | roundParam(2, 3, 4, 0, 1, 63), | ||
| 239 | roundParam(1, 2, 3, 4, 0, 64), | ||
| 240 | roundParam(0, 1, 2, 3, 4, 65), | ||
| 241 | roundParam(4, 0, 1, 2, 3, 66), | ||
| 242 | roundParam(3, 4, 0, 1, 2, 67), | ||
| 243 | roundParam(2, 3, 4, 0, 1, 68), | ||
| 244 | roundParam(1, 2, 3, 4, 0, 69), | ||
| 245 | roundParam(0, 1, 2, 3, 4, 70), | ||
| 246 | roundParam(4, 0, 1, 2, 3, 71), | ||
| 247 | roundParam(3, 4, 0, 1, 2, 72), | ||
| 248 | roundParam(2, 3, 4, 0, 1, 73), | ||
| 249 | roundParam(1, 2, 3, 4, 0, 74), | ||
| 250 | roundParam(0, 1, 2, 3, 4, 75), | ||
| 251 | roundParam(4, 0, 1, 2, 3, 76), | ||
| 252 | roundParam(3, 4, 0, 1, 2, 77), | ||
| 253 | roundParam(2, 3, 4, 0, 1, 78), | ||
| 254 | roundParam(1, 2, 3, 4, 0, 79), | ||
| 255 | }; | ||
| 256 | inline for (round3) |r| { | ||
| 257 | const t = s[(r.i - 3) & 0xf] ^ s[(r.i - 8) & 0xf] ^ s[(r.i - 14) & 0xf] ^ s[(r.i - 16) & 0xf]; | ||
| 258 | s[r.i & 0xf] = math.rotl(u32, t, @as(u32, 1)); | ||
| 259 | |||
| 260 | v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], @as(u32, 5)) +% 0xCA62C1D6 +% s[r.i & 0xf] +% (v[r.b] ^ v[r.c] ^ v[r.d]); | ||
| 261 | v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30)); | ||
| 262 | } | ||
| 263 | |||
| 264 | d.s[0] +%= v[0]; | ||
| 265 | d.s[1] +%= v[1]; | ||
| 266 | d.s[2] +%= v[2]; | ||
| 267 | d.s[3] +%= v[3]; | ||
| 268 | d.s[4] +%= v[4]; | ||
| 269 | } | ||
| 270 | |||
| 271 | pub const Error = error{}; | ||
| 272 | pub const Writer = std.io.GenericWriter(*Self, Error, write); | ||
| 273 | |||
| 274 | fn write(self: *Self, bytes: []const u8) Error!usize { | ||
| 275 | self.update(bytes); | ||
| 276 | return bytes.len; | ||
| 277 | } | ||
| 278 | |||
| 279 | pub fn writer(self: *Self) Writer { | ||
| 280 | return .{ .context = self }; | ||
| 281 | } | ||
| 282 | }; | ||
| 283 | |||
| 284 | const htest = @import("test.zig"); | ||
| 285 | |||
| 286 | test "sha1 single" { | ||
| 287 | try htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", ""); | ||
| 288 | try htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc"); | ||
| 289 | try htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); | ||
| 290 | } | ||
| 291 | |||
| 292 | test "sha1 streaming" { | ||
| 293 | var h = Sha1.init(.{}); | ||
| 294 | var out: [20]u8 = undefined; | ||
| 295 | |||
| 296 | h.final(&out); | ||
| 297 | try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]); | ||
| 298 | |||
| 299 | h = Sha1.init(.{}); | ||
| 300 | h.update("abc"); | ||
| 301 | h.final(&out); | ||
| 302 | try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); | ||
| 303 | |||
| 304 | h = Sha1.init(.{}); | ||
| 305 | h.update("a"); | ||
| 306 | h.update("b"); | ||
| 307 | h.update("c"); | ||
| 308 | h.final(&out); | ||
| 309 | try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]); | ||
| 310 | } | ||
| 311 | |||
| 312 | test "sha1 aligned final" { | ||
| 313 | var block = [_]u8{0} ** Sha1.block_length; | ||
| 314 | var out: [Sha1.digest_length]u8 = undefined; | ||
| 315 | |||
| 316 | var h = Sha1.init(.{}); | ||
| 317 | h.update(&block); | ||
| 318 | h.final(out[0..]); | ||
| 319 | } | ||