authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-30 16:23:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-30 16:23:22-07:00
log18bc68847107d5bd183df0023b5bb123139f5343
treedd8f14a52e41177093958fdfa13f11fd7ef3aa90
parenteb1a4970dae76b49fe8cf1fa792a571cfebed86d

std.crypto.Sha1: make it a Writer


18 files changed, 196 insertions(+), 145 deletions(-)

lib/std/compress/xz/block.zig+1-1
...@@ -191,7 +191,7 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -191,7 +191,7 @@ pub fn Decoder(comptime ReaderType: type) type {
191 },191 },
192 .sha256 => {192 .sha256 => {
193 var hash_a: [Sha256.digest_length]u8 = undefined;193 var hash_a: [Sha256.digest_length]u8 = undefined;
194 Sha256.hash(unpacked_bytes, &hash_a, .{});194 Sha256.hash(unpacked_bytes, &hash_a);
195195
196 var hash_b: [Sha256.digest_length]u8 = undefined;196 var hash_b: [Sha256.digest_length]u8 = undefined;
197 try self.inner_reader.readNoEof(&hash_b);197 try self.inner_reader.readNoEof(&hash_b);
lib/std/crypto.zig+19-1
...@@ -347,7 +347,6 @@ test "CSPRNG" {...@@ -347,7 +347,6 @@ test "CSPRNG" {
347test "issue #4532: no index out of bounds" {347test "issue #4532: no index out of bounds" {
348 const types = [_]type{348 const types = [_]type{
349 hash.Md5,349 hash.Md5,
350 hash.Sha1,
351 hash.sha2.Sha224,350 hash.sha2.Sha224,
352 hash.sha2.Sha256,351 hash.sha2.Sha256,
353 hash.sha2.Sha384,352 hash.sha2.Sha384,
...@@ -380,6 +379,25 @@ test "issue #4532: no index out of bounds" {...@@ -380,6 +379,25 @@ test "issue #4532: no index out of bounds" {
380379
381 try std.testing.expectEqual(out1, out2);380 try std.testing.expectEqual(out1, out2);
382 }381 }
382
383 try checkIndexOob(hash.Sha1);
384}
385
386fn checkIndexOob(Hasher: type) !void {
387 var buffer1: [Hasher.block_length]u8 = undefined;
388 var buffer2: [Hasher.block_length]u8 = undefined;
389 var block: [Hasher.block_length]u8 = @splat('#');
390 var out1: [Hasher.digest_length]u8 = undefined;
391 var out2: [Hasher.digest_length]u8 = undefined;
392 var h0: Hasher = .init(&buffer1);
393 var h = h0.copy(&buffer2);
394 h.update(&block);
395 out1 = h.final();
396 h = h0.copy(&buffer2);
397 h.update(block[0..1]);
398 h.update(block[1..]);
399 out2 = h.final();
400 try std.testing.expectEqualSlices(u8, &out1, &out2);
383}401}
384402
385/// Sets a slice to zeroes.403/// Sets a slice to zeroes.
lib/std/crypto/25519/ed25519.zig+1-1
...@@ -163,7 +163,7 @@ pub const Ed25519 = struct {...@@ -163,7 +163,7 @@ pub const Ed25519 = struct {
163 const expected_r = try Curve.fromBytes(r);163 const expected_r = try Curve.fromBytes(r);
164 try expected_r.rejectIdentity();164 try expected_r.rejectIdentity();
165165
166 var h = Sha512.init(.{});166 var h = Sha512.init();
167 h.update(&r);167 h.update(&r);
168 h.update(&public_key.bytes);168 h.update(&public_key.bytes);
169169
lib/std/crypto/Certificate.zig+22-10
...@@ -949,7 +949,7 @@ pub const rsa = struct {...@@ -949,7 +949,7 @@ pub const rsa = struct {
949 // 2. Let mHash = Hash(M), an octet string of length hLen.949 // 2. Let mHash = Hash(M), an octet string of length hLen.
950 var mHash: [Hash.digest_length]u8 = undefined;950 var mHash: [Hash.digest_length]u8 = undefined;
951 {951 {
952 var hasher: Hash = .init(.{});952 var hasher: Hash = .init();
953 for (msg) |part| hasher.update(part);953 for (msg) |part| hasher.update(part);
954 hasher.final(&mHash);954 hasher.final(&mHash);
955 }955 }
...@@ -1038,7 +1038,7 @@ pub const rsa = struct {...@@ -1038,7 +1038,7 @@ pub const rsa = struct {
10381038
1039 // 13. Let H' = Hash(M'), an octet string of length hLen.1039 // 13. Let H' = Hash(M'), an octet string of length hLen.
1040 var h_p: [Hash.digest_length]u8 = undefined;1040 var h_p: [Hash.digest_length]u8 = undefined;
1041 Hash.hash(m_p, &h_p, .{});1041 Hash.hash(m_p, &h_p);
10421042
1043 // 14. If H = H', output "consistent". Otherwise, output1043 // 14. If H = H', output "consistent". Otherwise, output
1044 // "inconsistent".1044 // "inconsistent".
...@@ -1054,7 +1054,7 @@ pub const rsa = struct {...@@ -1054,7 +1054,7 @@ pub const rsa = struct {
10541054
1055 while (idx < len) {1055 while (idx < len) {
1056 std.mem.writeInt(u32, hash[seed.len..][0..4], counter, .big);1056 std.mem.writeInt(u32, hash[seed.len..][0..4], counter, .big);
1057 Hash.hash(&hash, out[idx..][0..Hash.digest_length], .{});1057 Hash.hash(&hash, out[idx..][0..Hash.digest_length]);
1058 idx += Hash.digest_length;1058 idx += Hash.digest_length;
1059 counter += 1;1059 counter += 1;
1060 }1060 }
...@@ -1081,13 +1081,14 @@ pub const rsa = struct {...@@ -1081,13 +1081,14 @@ pub const rsa = struct {
1081 public_key: PublicKey,1081 public_key: PublicKey,
1082 comptime Hash: type,1082 comptime Hash: type,
1083 ) VerifyError!void {1083 ) VerifyError!void {
1084 try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash);1084 var msgs: [1][]const u8 = .{msg};
1085 try concatVerify(modulus_len, sig, &msgs, public_key, Hash);
1085 }1086 }
10861087
1087 pub fn concatVerify(1088 pub fn concatVerify(
1088 comptime modulus_len: usize,1089 comptime modulus_len: usize,
1089 sig: [modulus_len]u8,1090 sig: [modulus_len]u8,
1090 msg: []const []const u8,1091 msg: [][]const u8,
1091 public_key: PublicKey,1092 public_key: PublicKey,
1092 comptime Hash: type,1093 comptime Hash: type,
1093 ) VerifyError!void {1094 ) VerifyError!void {
...@@ -1096,7 +1097,7 @@ pub const rsa = struct {...@@ -1096,7 +1097,7 @@ pub const rsa = struct {
1096 if (!std.mem.eql(u8, &em_dec, &em)) return error.InvalidSignature;1097 if (!std.mem.eql(u8, &em_dec, &em)) return error.InvalidSignature;
1097 }1098 }
10981099
1099 fn EMSA_PKCS1_V1_5_ENCODE(msg: []const []const u8, comptime emLen: usize, comptime Hash: type) VerifyError![emLen]u8 {1100 fn EMSA_PKCS1_V1_5_ENCODE(msg: [][]const u8, comptime emLen: usize, comptime Hash: type) VerifyError![emLen]u8 {
1100 comptime var em_index = emLen;1101 comptime var em_index = emLen;
1101 var em: [emLen]u8 = undefined;1102 var em: [emLen]u8 = undefined;
11021103
...@@ -1107,10 +1108,21 @@ pub const rsa = struct {...@@ -1107,10 +1108,21 @@ pub const rsa = struct {
1107 //1108 //
1108 // If the hash function outputs "message too long," output "message1109 // If the hash function outputs "message too long," output "message
1109 // too long" and stop.1110 // too long" and stop.
1110 var hasher: Hash = .init(.{});1111 switch (Hash) {
1111 for (msg) |part| hasher.update(part);1112 crypto.hash.Sha1 => {
1112 em_index -= Hash.digest_length;1113 var buffer: [64]u8 = undefined;
1113 hasher.final(em[em_index..]);1114 var hasher: Hash = .init(&buffer);
1115 hasher.writer.writeVecAll(msg) catch unreachable; // writing to hasher cannot fail
1116 em_index -= Hash.digest_length;
1117 em[em_index..][0..Hash.digest_length].* = hasher.final();
1118 },
1119 else => {
1120 var hasher: Hash = .init();
1121 for (msg) |part| hasher.update(part);
1122 em_index -= Hash.digest_length;
1123 hasher.final(em[em_index..]);
1124 },
1125 }
11141126
1115 // 2. Encode the algorithm ID for the hash function and the hash value1127 // 2. Encode the algorithm ID for the hash function and the hash value
1116 // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with1128 // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
lib/std/crypto/Sha1.zig+98-90
...@@ -2,115 +2,121 @@...@@ -2,115 +2,121 @@
2//! Namely, it is feasible to find multiple inputs producing the same hash.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.3//! For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
44
5const Sha1 = @This();
5const std = @import("../std.zig");6const std = @import("../std.zig");
6const mem = std.mem;7const mem = std.mem;
7const math = std.math;8const math = std.math;
8const Sha1 = @This();9const assert = std.debug.assert;
10const Writer = std.Io.Writer;
911
10pub const block_length = 64;12pub const block_length = 64;
11pub const digest_length = 20;13pub const digest_length = 20;
12pub const Options = struct {};
1314
14s: [5]u32,15s: [5]u32,
15/// Streaming Cache16total_len: u64,
16buf: [64]u8 = undefined,17writer: Writer,
17buf_len: u8 = 0,
18total_len: u64 = 0,
1918
20pub fn init(options: Options) Sha1 {19pub fn init(buffer: []u8) Sha1 {
21 _ = options;20 assert(buffer.len >= block_length);
22 return .{21 return .{
23 .s = [_]u32{22 .s = .{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 },
24 0x67452301,23 .total_len = 0,
25 0xEFCDAB89,24 .writer = .{
26 0x98BADCFE,25 .buffer = buffer,
27 0x10325476,26 .vtable = &vtable,
28 0xC3D2E1F0,
29 },27 },
30 };28 };
31}29}
3230
33pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void {31pub fn copy(sha1: *Sha1, buffer: []u8) Sha1 {
34 var d = Sha1.init(options);32 assert(buffer.len >= block_length);
35 d.update(b);33 const mine = sha1.writer.buffered();
36 d.final(out);34 assert(mine.len <= block_length);
35 @memcpy(buffer[0..mine.len], mine);
36 return .{
37 .s = sha1.s,
38 .total_len = sha1.total_len,
39 .writer = .{
40 .buffer = buffer,
41 .end = mine.len,
42 .vtable = &vtable,
43 },
44 };
37}45}
3846
39pub fn update(d: *Sha1, b: []const u8) void {47const vtable: Writer.VTable = .{ .drain = drain };
40 var off: usize = 0;48
4149fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
42 // Partial buffer exists from previous update. Copy into buffer then hash.50 const d: *Sha1 = @alignCast(@fieldParentPtr("writer", w));
43 if (d.buf_len != 0 and d.buf_len + b.len >= 64) {51 {
44 off += 64 - d.buf_len;52 const buf = w.buffered();
45 @memcpy(d.buf[d.buf_len..][0..off], b[0..off]);53 var off: usize = 0;
4654 while (off + block_length <= buf.len) : (off += block_length) {
47 d.round(d.buf[0..]);55 round(&d.s, buf[off..][0..block_length]);
48 d.buf_len = 0;56 }
57 d.total_len += off;
58 if (off != buf.len) return w.consume(off);
59 w.end = 0;
49 }60 }
5061 if (data.len == 1 and splat == 0) return 0;
51 // Full middle blocks.62 var total_off: usize = 0;
52 while (off + 64 <= b.len) : (off += 64) {63 for (data) |buf| {
53 d.round(b[off..][0..64]);64 var off: usize = 0;
65 while (off + block_length <= buf.len) : (off += block_length) {
66 round(&d.s, buf[off..][0..block_length]);
67 }
68 total_off += off;
69 if (off != buf.len) break;
54 }70 }
5571 d.total_len += total_off;
56 // Copy any remainder for next pass.72 return total_off;
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}73}
6274
63pub fn peek(d: Sha1) [digest_length]u8 {75pub fn hash(data: []const u8) [digest_length]u8 {
64 var copy = d;76 var buf: [block_length]u8 = undefined;
65 return copy.finalResult();77 var s: Sha1 = .init(&buf);
78 s.writer.writeAll(data) catch unreachable;
79 return s.final();
66}80}
6781
68pub fn final(d: *Sha1, out: *[digest_length]u8) void {82pub fn update(d: *Sha1, b: []const u8) void {
69 // The buffer here will never be completely full.83 d.writer.writeAll(b) catch unreachable;
70 @memset(d.buf[d.buf_len..], 0);84}
7185
72 // Append padding bits.86pub fn final(d: *Sha1) [digest_length]u8 {
73 d.buf[d.buf_len] = 0x80;87 _ = drain(&d.writer, &.{""}, 1) catch unreachable;
74 d.buf_len += 1;88 const buf = d.writer.buffer[0..block_length];
89 const pad = d.writer.end;
90 assert(pad < block_length);
91 d.total_len += pad;
92 buf[pad] = 0x80; // Append padding bits.
93 const end = pad + 1;
94 @memset(buf[end..], 0);
7595
76 // > 448 mod 512 so need to add an extra round to wrap around.96 // > 448 mod 512 so need to add an extra round to wrap around.
77 if (64 - d.buf_len < 8) {97 if (block_length - end < 8) {
78 d.round(d.buf[0..]);98 round(&d.s, buf);
79 @memset(d.buf[0..], 0);99 @memset(buf, 0);
80 }100 }
81101
82 // Append message length.102 // Append message length.
83 var i: usize = 1;
84 var len = d.total_len >> 5;103 var len = d.total_len >> 5;
85 d.buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3;104 buf[63] = @as(u8, @intCast(d.total_len & 0x1f)) << 3;
86 while (i < 8) : (i += 1) {105 for (1..8) |i| {
87 d.buf[63 - i] = @as(u8, @intCast(len & 0xff));106 buf[63 - i] = @as(u8, @intCast(len & 0xff));
88 len >>= 8;107 len >>= 8;
89 }108 }
90109
91 d.round(d.buf[0..]);110 round(&d.s, buf);
92111
93 for (d.s, 0..) |s, j| {112 var out: [digest_length]u8 = undefined;
94 mem.writeInt(u32, out[4 * j ..][0..4], s, .big);113 for (&d.s, 0..) |s, j| mem.writeInt(u32, out[4 * j ..][0..4], s, .big);
95 }114 return out;
96}115}
97116
98pub fn finalResult(d: *Sha1) [digest_length]u8 {117pub fn round(d_s: *[5]u32, b: *const [block_length]u8) void {
99 var result: [digest_length]u8 = undefined;
100 d.final(&result);
101 return result;
102}
103
104fn round(d: *Sha1, b: *const [64]u8) void {
105 var s: [16]u32 = undefined;118 var s: [16]u32 = undefined;
106119 var v = d_s.*;
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 };
114120
115 const round0a = comptime [_]RoundParam{121 const round0a = comptime [_]RoundParam{
116 .abcdei(0, 1, 2, 3, 4, 0),122 .abcdei(0, 1, 2, 3, 4, 0),
...@@ -241,11 +247,11 @@ fn round(d: *Sha1, b: *const [64]u8) void {...@@ -241,11 +247,11 @@ fn round(d: *Sha1, b: *const [64]u8) void {
241 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));247 v[r.b] = math.rotl(u32, v[r.b], @as(u32, 30));
242 }248 }
243249
244 d.s[0] +%= v[0];250 d_s[0] +%= v[0];
245 d.s[1] +%= v[1];251 d_s[1] +%= v[1];
246 d.s[2] +%= v[2];252 d_s[2] +%= v[2];
247 d.s[3] +%= v[3];253 d_s[3] +%= v[3];
248 d.s[4] +%= v[4];254 d_s[4] +%= v[4];
249}255}
250256
251const RoundParam = struct {257const RoundParam = struct {
...@@ -271,36 +277,38 @@ const RoundParam = struct {...@@ -271,36 +277,38 @@ const RoundParam = struct {
271const htest = @import("test.zig");277const htest = @import("test.zig");
272278
273test "sha1 single" {279test "sha1 single" {
274 try htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");280 try htest.assertEqualHashInterface(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
275 try htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");281 try htest.assertEqualHashInterface(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
276 try htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");282 try htest.assertEqualHashInterface(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
277}283}
278284
279test "sha1 streaming" {285test "sha1 streaming" {
280 var h = Sha1.init(.{});286 var buffer: [block_length]u8 = undefined;
287 var h: Sha1 = .init(&buffer);
281 var out: [20]u8 = undefined;288 var out: [20]u8 = undefined;
282289
283 h.final(&out);290 out = h.final();
284 try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);291 try htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
285292
286 h = Sha1.init(.{});293 h = .init(&buffer);
287 h.update("abc");294 h.update("abc");
288 h.final(&out);295 out = h.final();
289 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);296 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
290297
291 h = Sha1.init(.{});298 h = .init(&buffer);
292 h.update("a");299 h.update("a");
293 h.update("b");300 h.update("b");
294 h.update("c");301 h.update("c");
295 h.final(&out);302 out = h.final();
296 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);303 try htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
297}304}
298305
299test "sha1 aligned final" {306test "sha1 aligned final" {
300 var block = [_]u8{0} ** Sha1.block_length;307 var block: [block_length]u8 = @splat(0);
301 var out: [Sha1.digest_length]u8 = undefined;308 var out: [Sha1.digest_length]u8 = undefined;
309 var buffer: [block_length]u8 = undefined;
302310
303 var h = Sha1.init(.{});311 var h: Sha1 = .init(&buffer);
304 h.update(&block);312 h.update(&block);
305 h.final(out[0..]);313 out = h.final();
306}314}
lib/std/crypto/ecdsa.zig+2-2
...@@ -258,8 +258,8 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {...@@ -258,8 +258,8 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
258 const s = try Curve.scalar.Scalar.fromBytes(sig.s, .big);258 const s = try Curve.scalar.Scalar.fromBytes(sig.s, .big);
259 if (r.isZero() or s.isZero()) return error.IdentityElement;259 if (r.isZero() or s.isZero()) return error.IdentityElement;
260260
261 return Verifier{261 return .{
262 .h = Hash.init(.{}),262 .h = Hash.init(),
263 .r = r,263 .r = r,
264 .s = s,264 .s = s,
265 .public_key = public_key,265 .public_key = public_key,
lib/std/crypto/hmac.zig+3-3
...@@ -37,7 +37,7 @@ pub fn Hmac(comptime Hash: type) type {...@@ -37,7 +37,7 @@ pub fn Hmac(comptime Hash: type) type {
3737
38 // Normalize key length to block size of hash38 // Normalize key length to block size of hash
39 if (key.len > Hash.block_length) {39 if (key.len > Hash.block_length) {
40 Hash.hash(key, scratch[0..mac_length], .{});40 Hash.hash(key, scratch[0..mac_length]);
41 @memset(scratch[mac_length..Hash.block_length], 0);41 @memset(scratch[mac_length..Hash.block_length], 0);
42 } else if (key.len < Hash.block_length) {42 } else if (key.len < Hash.block_length) {
43 @memcpy(scratch[0..key.len], key);43 @memcpy(scratch[0..key.len], key);
...@@ -54,7 +54,7 @@ pub fn Hmac(comptime Hash: type) type {...@@ -54,7 +54,7 @@ pub fn Hmac(comptime Hash: type) type {
54 b.* = scratch[i] ^ 0x36;54 b.* = scratch[i] ^ 0x36;
55 }55 }
5656
57 ctx.hash = Hash.init(.{});57 ctx.hash = Hash.init();
58 ctx.hash.update(&i_key_pad);58 ctx.hash.update(&i_key_pad);
59 return ctx;59 return ctx;
60 }60 }
...@@ -66,7 +66,7 @@ pub fn Hmac(comptime Hash: type) type {...@@ -66,7 +66,7 @@ pub fn Hmac(comptime Hash: type) type {
66 pub fn final(ctx: *Self, out: *[mac_length]u8) void {66 pub fn final(ctx: *Self, out: *[mac_length]u8) void {
67 var scratch: [mac_length]u8 = undefined;67 var scratch: [mac_length]u8 = undefined;
68 ctx.hash.final(&scratch);68 ctx.hash.final(&scratch);
69 var ohash = Hash.init(.{});69 var ohash = Hash.init();
70 ohash.update(&ctx.o_key_pad);70 ohash.update(&ctx.o_key_pad);
71 ohash.update(&scratch);71 ohash.update(&scratch);
72 ohash.final(out);72 ohash.final(out);
lib/std/crypto/md5.zig+3-5
...@@ -31,7 +31,6 @@ pub const Md5 = struct {...@@ -31,7 +31,6 @@ pub const Md5 = struct {
31 const Self = @This();31 const Self = @This();
32 pub const block_length = 64;32 pub const block_length = 64;
33 pub const digest_length = 16;33 pub const digest_length = 16;
34 pub const Options = struct {};
3534
36 s: [4]u32,35 s: [4]u32,
37 // Streaming Cache36 // Streaming Cache
...@@ -39,8 +38,7 @@ pub const Md5 = struct {...@@ -39,8 +38,7 @@ pub const Md5 = struct {
39 buf_len: u8,38 buf_len: u8,
40 total_len: u64,39 total_len: u64,
4140
42 pub fn init(options: Options) Self {41 pub fn init() Self {
43 _ = options;
44 return Self{42 return Self{
45 .s = [_]u32{43 .s = [_]u32{
46 0x67452301,44 0x67452301,
...@@ -54,8 +52,8 @@ pub const Md5 = struct {...@@ -54,8 +52,8 @@ pub const Md5 = struct {
54 };52 };
55 }53 }
5654
57 pub fn hash(data: []const u8, out: *[digest_length]u8, options: Options) void {55 pub fn hash(data: []const u8, out: *[digest_length]u8) void {
58 var d = Md5.init(options);56 var d = Md5.init();
59 d.update(data);57 d.update(data);
60 d.final(out);58 d.final(out);
61 }59 }
lib/std/crypto/test.zig+17-9
...@@ -3,19 +3,27 @@ const testing = std.testing;...@@ -3,19 +3,27 @@ const testing = std.testing;
3const fmt = std.fmt;3const fmt = std.fmt;
44
5// Hash using the specified hasher `H` asserting `expected == H(input)`.5// Hash using the specified hasher `H` asserting `expected == H(input)`.
6pub fn assertEqualHash(comptime Hasher: anytype, comptime expected_hex: *const [Hasher.digest_length * 2:0]u8, input: []const u8) !void {6pub fn assertEqualHash(
7 comptime Hasher: type,
8 expected_hex: *const [Hasher.digest_length * 2:0]u8,
9 input: []const u8,
10) !void {
7 var h: [Hasher.digest_length]u8 = undefined;11 var h: [Hasher.digest_length]u8 = undefined;
8 Hasher.hash(input, &h, .{});12 Hasher.hash(input, &h, .{});
9
10 try assertEqual(expected_hex, &h);13 try assertEqual(expected_hex, &h);
11}14}
1215
13// Assert `expected` == hex(`input`) where `input` is a bytestring16pub fn assertEqualHashInterface(
14pub fn assertEqual(comptime expected_hex: [:0]const u8, input: []const u8) !void {17 comptime Hasher: type,
15 var expected_bytes: [expected_hex.len / 2]u8 = undefined;18 expected_hex: *const [Hasher.digest_length * 2:0]u8,
16 for (&expected_bytes, 0..) |*r, i| {19 input: []const u8,
17 r.* = fmt.parseInt(u8, expected_hex[2 * i .. 2 * i + 2], 16) catch unreachable;20) !void {
18 }21 const digest = Hasher.hash(input);
22 try assertEqual(expected_hex, &digest);
23}
1924
20 try testing.expectEqualSlices(u8, &expected_bytes, input);25pub fn assertEqual(expected_hex: [:0]const u8, actual_bin_digest: []const u8) !void {
26 var buffer: [200]u8 = undefined;
27 const actual_hex = std.fmt.bufPrint(&buffer, "{x}", .{actual_bin_digest}) catch @panic("buffer too small");
28 try testing.expectEqualStrings(expected_hex, actual_hex);
21}29}
lib/std/crypto/tls.zig+1-1
...@@ -578,7 +578,7 @@ pub fn hkdfExpandLabel(...@@ -578,7 +578,7 @@ pub fn hkdfExpandLabel(
578578
579pub fn emptyHash(comptime Hash: type) [Hash.digest_length]u8 {579pub fn emptyHash(comptime Hash: type) [Hash.digest_length]u8 {
580 var result: [Hash.digest_length]u8 = undefined;580 var result: [Hash.digest_length]u8 = undefined;
581 Hash.hash(&.{}, &result, .{});581 Hash.hash(&.{}, &result);
582 return result;582 return result;
583}583}
584584
lib/std/crypto/tls/Client.zig+7-5
...@@ -498,7 +498,7 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client...@@ -498,7 +498,7 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
498 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,498 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
499 => |tag| {499 => |tag| {
500 handshake_cipher = @unionInit(tls.HandshakeCipher, @tagName(tag.with()), .{500 handshake_cipher = @unionInit(tls.HandshakeCipher, @tagName(tag.with()), .{
501 .transcript_hash = .init(.{}),501 .transcript_hash = .init(),
502 .version = undefined,502 .version = undefined,
503 });503 });
504 const p = &@field(handshake_cipher, @tagName(tag.with()));504 const p = &@field(handshake_cipher, @tagName(tag.with()));
...@@ -680,7 +680,8 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client...@@ -680,7 +680,8 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
680 const key_size = hsd.decode(u8);680 const key_size = hsd.decode(u8);
681 try hsd.ensure(key_size);681 try hsd.ensure(key_size);
682 const server_pub_key = hsd.slice(key_size);682 const server_pub_key = hsd.slice(key_size);
683 try main_cert_pub_key.verifySignature(&hsd, &.{ &client_hello_rand, &server_hello_rand, hsd.buf[0..hsd.idx] });683 var msgs: [3][]const u8 = .{ &client_hello_rand, &server_hello_rand, hsd.buf[0..hsd.idx] };
684 try main_cert_pub_key.verifySignature(&hsd, &msgs);
684 try key_share.exchange(named_group, server_pub_key);685 try key_share.exchange(named_group, server_pub_key);
685 handshake_state = .server_hello_done;686 handshake_state = .server_hello_done;
686 },687 },
...@@ -776,10 +777,11 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client...@@ -776,10 +777,11 @@ pub fn init(stream: anytype, options: Options) InitError(@TypeOf(stream))!Client
776 }777 }
777 switch (handshake_cipher) {778 switch (handshake_cipher) {
778 inline else => |*p| {779 inline else => |*p| {
779 try main_cert_pub_key.verifySignature(&hsd, &.{780 var msgs: [2][]const u8 = .{
780 " " ** 64 ++ "TLS 1.3, server CertificateVerify\x00",781 " " ** 64 ++ "TLS 1.3, server CertificateVerify\x00",
781 &p.transcript_hash.peek(),782 &p.transcript_hash.peek(),
782 });783 };
784 try main_cert_pub_key.verifySignature(&hsd, &msgs);
783 p.transcript_hash.update(wrapped_handshake);785 p.transcript_hash.update(wrapped_handshake);
784 },786 },
785 }787 }
...@@ -1755,7 +1757,7 @@ const CertificatePublicKey = struct {...@@ -1755,7 +1757,7 @@ const CertificatePublicKey = struct {
1755 fn verifySignature(1757 fn verifySignature(
1756 cert_pub_key: *const CertificatePublicKey,1758 cert_pub_key: *const CertificatePublicKey,
1757 sigd: *tls.Decoder,1759 sigd: *tls.Decoder,
1758 msg: []const []const u8,1760 msg: [][]const u8,
1759 ) VerifyError!void {1761 ) VerifyError!void {
1760 const pub_key = cert_pub_key.buf[0..cert_pub_key.len];1762 const pub_key = cert_pub_key.buf[0..cert_pub_key.len];
17611763
lib/std/http/WebSocket.zig+3-3
...@@ -45,11 +45,11 @@ pub fn init(...@@ -45,11 +45,11 @@ pub fn init(
4545
46 const key = sec_websocket_key orelse return error.WebSocketUpgradeMissingKey;46 const key = sec_websocket_key orelse return error.WebSocketUpgradeMissingKey;
4747
48 var sha1 = std.crypto.hash.Sha1.init(.{});48 var sha1_buffer: [64]u8 = undefined;
49 var sha1: std.crypto.hash.Sha1 = .init(&sha1_buffer);
49 sha1.update(key);50 sha1.update(key);
50 sha1.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");51 sha1.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
51 var digest: [std.crypto.hash.Sha1.digest_length]u8 = undefined;52 const digest = sha1.final();
52 sha1.final(&digest);
53 var base64_digest: [28]u8 = undefined;53 var base64_digest: [28]u8 = undefined;
54 assert(std.base64.standard.Encoder.encode(&base64_digest, &digest).len == base64_digest.len);54 assert(std.base64.standard.Encoder.encode(&base64_digest, &digest).len == base64_digest.len);
5555
src/Package.zig+1-1
...@@ -133,7 +133,7 @@ pub const Hash = struct {...@@ -133,7 +133,7 @@ pub const Hash = struct {
133 return result;133 return result;
134 }134 }
135 var bin_digest: [Algo.digest_length]u8 = undefined;135 var bin_digest: [Algo.digest_length]u8 = undefined;
136 Algo.hash(sub_path, &bin_digest, .{});136 Algo.hash(sub_path, &bin_digest);
137 _ = std.fmt.bufPrint(result.bytes[i..], "{x}", .{&bin_digest}) catch unreachable;137 _ = std.fmt.bufPrint(result.bytes[i..], "{x}", .{&bin_digest}) catch unreachable;
138 return result;138 return result;
139 }139 }
src/Package/Fetch.zig+2-2
...@@ -1621,7 +1621,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute...@@ -1621,7 +1621,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute
16211621
1622 std.mem.sortUnstable(*HashedFile, all_files.items, {}, HashedFile.lessThan);1622 std.mem.sortUnstable(*HashedFile, all_files.items, {}, HashedFile.lessThan);
16231623
1624 var hasher = Package.Hash.Algo.init(.{});1624 var hasher = Package.Hash.Algo.init();
1625 var any_failures = false;1625 var any_failures = false;
1626 for (all_files.items) |hashed_file| {1626 for (all_files.items) |hashed_file| {
1627 hashed_file.failure catch |err| {1627 hashed_file.failure catch |err| {
...@@ -1690,7 +1690,7 @@ fn workerDeleteFile(dir: fs.Dir, deleted_file: *DeletedFile) void {...@@ -1690,7 +1690,7 @@ fn workerDeleteFile(dir: fs.Dir, deleted_file: *DeletedFile) void {
16901690
1691fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {1691fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
1692 var buf: [8000]u8 = undefined;1692 var buf: [8000]u8 = undefined;
1693 var hasher = Package.Hash.Algo.init(.{});1693 var hasher = Package.Hash.Algo.init();
1694 hasher.update(hashed_file.normalized_path);1694 hasher.update(hashed_file.normalized_path);
1695 var file_size: u64 = 0;1695 var file_size: u64 = 0;
16961696
src/Package/Fetch/git.zig+12-7
...@@ -45,10 +45,10 @@ pub const Oid = union(Format) {...@@ -45,10 +45,10 @@ pub const Oid = union(Format) {
45 sha1: Sha1,45 sha1: Sha1,
46 sha256: Sha256,46 sha256: Sha256,
4747
48 fn init(oid_format: Format) Hasher {48 fn init(oid_format: Format, buffer: []u8) Hasher {
49 return switch (oid_format) {49 return switch (oid_format) {
50 .sha1 => .{ .sha1 = Sha1.init(.{}) },50 .sha1 => .{ .sha1 = .init(buffer) },
51 .sha256 => .{ .sha256 = Sha256.init(.{}) },51 .sha256 => .{ .sha256 = Sha256.init() },
52 };52 };
53 }53 }
5454
...@@ -61,6 +61,7 @@ pub const Oid = union(Format) {...@@ -61,6 +61,7 @@ pub const Oid = union(Format) {
6161
62 fn finalResult(hasher: *Hasher) Oid {62 fn finalResult(hasher: *Hasher) Oid {
63 return switch (hasher.*) {63 return switch (hasher.*) {
64 .sha1 => |*inner| .{ .sha1 = inner.final() },
64 inline else => |*inner, tag| @unionInit(Oid, @tagName(tag), inner.finalResult()),65 inline else => |*inner, tag| @unionInit(Oid, @tagName(tag), inner.finalResult()),
65 };66 };
66 }67 }
...@@ -1281,7 +1282,8 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in...@@ -1281,7 +1282,8 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in
1281 }1282 }
1282 @memset(fan_out_table[fan_out_index..], count);1283 @memset(fan_out_table[fan_out_index..], count);
12831284
1284 var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format));1285 var hash_buffer: [64]u8 = undefined;
1286 var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format, &hash_buffer));
1285 const writer = index_hashed_writer.writer();1287 const writer = index_hashed_writer.writer();
1286 try writer.writeAll(IndexHeader.signature);1288 try writer.writeAll(IndexHeader.signature);
1287 try writer.writeInt(u32, IndexHeader.supported_version, .big);1289 try writer.writeInt(u32, IndexHeader.supported_version, .big);
...@@ -1331,7 +1333,8 @@ fn indexPackFirstPass(...@@ -1331,7 +1333,8 @@ fn indexPackFirstPass(
1331) !Oid {1333) !Oid {
1332 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());1334 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
1333 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());1335 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
1334 var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));1336 var hash_buffer: [64]u8 = undefined;
1337 var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format, &hash_buffer));
1335 const pack_reader = pack_hashed_reader.reader();1338 const pack_reader = pack_hashed_reader.reader();
13361339
1337 const pack_header = try PackHeader.read(pack_reader);1340 const pack_header = try PackHeader.read(pack_reader);
...@@ -1345,7 +1348,8 @@ fn indexPackFirstPass(...@@ -1345,7 +1348,8 @@ fn indexPackFirstPass(
1345 .commit, .tree, .blob, .tag => |object| {1348 .commit, .tree, .blob, .tag => |object| {
1346 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());1349 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1347 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());1350 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1348 var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format));1351 var entry_hash_buffer: [64]u8 = undefined;
1352 var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format, &entry_hash_buffer));
1349 const entry_writer = entry_hashed_writer.writer();1353 const entry_writer = entry_hashed_writer.writer();
1350 // The object header is not included in the pack data but is1354 // The object header is not included in the pack data but is
1351 // part of the object's ID1355 // part of the object's ID
...@@ -1431,7 +1435,8 @@ fn indexPackHashDelta(...@@ -1431,7 +1435,8 @@ fn indexPackHashDelta(
14311435
1432 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);1436 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14331437
1434 var entry_hasher: Oid.Hasher = .init(format);1438 var hash_buffer: [64]u8 = undefined;
1439 var entry_hasher: Oid.Hasher = .init(format, &hash_buffer);
1435 var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher);1440 var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher);
1436 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });1441 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
1437 entry_hasher.update(base_data);1442 entry_hasher.update(base_data);
src/link/MachO/CodeSignature.zig+2-2
...@@ -307,7 +307,7 @@ pub fn writeAdhocSignature(...@@ -307,7 +307,7 @@ pub fn writeAdhocSignature(
307 var buf = std.ArrayList(u8).init(allocator);307 var buf = std.ArrayList(u8).init(allocator);
308 defer buf.deinit();308 defer buf.deinit();
309 try req.write(buf.writer());309 try req.write(buf.writer());
310 Sha256.hash(buf.items, &hash, .{});310 Sha256.hash(buf.items, &hash);
311 self.code_directory.addSpecialHash(req.slotType(), hash);311 self.code_directory.addSpecialHash(req.slotType(), hash);
312312
313 try blobs.append(.{ .requirements = req });313 try blobs.append(.{ .requirements = req });
...@@ -319,7 +319,7 @@ pub fn writeAdhocSignature(...@@ -319,7 +319,7 @@ pub fn writeAdhocSignature(
319 var buf = std.ArrayList(u8).init(allocator);319 var buf = std.ArrayList(u8).init(allocator);
320 defer buf.deinit();320 defer buf.deinit();
321 try ents.write(buf.writer());321 try ents.write(buf.writer());
322 Sha256.hash(buf.items, &hash, .{});322 Sha256.hash(buf.items, &hash);
323 self.code_directory.addSpecialHash(ents.slotType(), hash);323 self.code_directory.addSpecialHash(ents.slotType(), hash);
324324
325 try blobs.append(.{ .entitlements = ents });325 try blobs.append(.{ .entitlements = ents });
src/link/MachO/hasher.zig+1-1
...@@ -58,7 +58,7 @@ pub fn ParallelHasher(comptime Hasher: type) type {...@@ -58,7 +58,7 @@ pub fn ParallelHasher(comptime Hasher: type) type {
58 const tracy = trace(@src());58 const tracy = trace(@src());
59 defer tracy.end();59 defer tracy.end();
60 err.* = file.preadAll(buffer, fstart);60 err.* = file.preadAll(buffer, fstart);
61 Hasher.hash(buffer, out, .{});61 Hasher.hash(buffer, out);
62 }62 }
6363
64 const Self = @This();64 const Self = @This();
src/link/MachO/uuid.zig+1-1
...@@ -28,7 +28,7 @@ pub fn calcUuid(comp: *const Compilation, file: fs.File, file_size: u64, out: *[...@@ -28,7 +28,7 @@ pub fn calcUuid(comp: *const Compilation, file: fs.File, file_size: u64, out: *[
28 @memcpy(final_buffer[i * Md5.digest_length ..][0..Md5.digest_length], &hash);28 @memcpy(final_buffer[i * Md5.digest_length ..][0..Md5.digest_length], &hash);
29 }29 }
3030
31 Md5.hash(final_buffer, out, .{});31 Md5.hash(final_buffer, out);
32 conform(out);32 conform(out);
33}33}
3434