Commit 6f9ea9eaef
Changed files (16)
lib/std/build/write_file.zig
@@ -58,7 +58,7 @@ pub const WriteFileStep = struct {
// TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
// directly and construct the path, and no "cache hit" detection happens; the files
// are always written.
- var hash = std.crypto.Blake2b384.init();
+ var hash = std.crypto.hash.blake2.Blake2b384.init();
// Random bytes to make WriteFileStep unique. Refresh this with
// new random bytes when WriteFileStep implementation is modified
lib/std/crypto/25519/ed25519.zig
@@ -6,7 +6,7 @@
const std = @import("std");
const fmt = std.fmt;
const mem = std.mem;
-const Sha512 = std.crypto.Sha512;
+const Sha512 = std.crypto.hash.sha2.Sha512;
/// Ed25519 (EdDSA) signatures.
pub const Ed25519 = struct {
lib/std/crypto/benchmark.zig
@@ -22,16 +22,16 @@ const Crypto = struct {
};
const hashes = [_]Crypto{
- Crypto{ .ty = crypto.Md5, .name = "md5" },
- Crypto{ .ty = crypto.Sha1, .name = "sha1" },
- Crypto{ .ty = crypto.Sha256, .name = "sha256" },
- Crypto{ .ty = crypto.Sha512, .name = "sha512" },
- Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" },
- Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" },
- Crypto{ .ty = crypto.gimli.Hash, .name = "gimli-hash" },
- Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" },
- Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" },
- Crypto{ .ty = crypto.Blake3, .name = "blake3" },
+ Crypto{ .ty = crypto.hash.Md5, .name = "md5" },
+ Crypto{ .ty = crypto.hash.Sha1, .name = "sha1" },
+ Crypto{ .ty = crypto.hash.sha2.Sha256, .name = "sha256" },
+ Crypto{ .ty = crypto.hash.sha2.Sha512, .name = "sha512" },
+ Crypto{ .ty = crypto.hash.sha3.Sha3_256, .name = "sha3-256" },
+ Crypto{ .ty = crypto.hash.sha3.Sha3_512, .name = "sha3-512" },
+ Crypto{ .ty = crypto.hash.Gimli, .name = "gimli-hash" },
+ Crypto{ .ty = crypto.hash.blake2.Blake2s256, .name = "blake2s" },
+ Crypto{ .ty = crypto.hash.blake2.Blake2b512, .name = "blake2b" },
+ Crypto{ .ty = crypto.hash.Blake3, .name = "blake3" },
};
pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 {
@@ -55,10 +55,11 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
}
const macs = [_]Crypto{
- Crypto{ .ty = crypto.Poly1305, .name = "poly1305" },
- Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" },
- Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" },
- Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" },
+ Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
+ Crypto{ .ty = crypto.auth.HmacMd5, .name = "hmac-md5" },
+ Crypto{ .ty = crypto.auth.HmacSha1, .name = "hmac-sha1" },
+ Crypto{ .ty = crypto.auth.sha2.HmacSha256, .name = "hmac-sha256" },
+ Crypto{ .ty = crypto.auth.sha2.HmacSha512, .name = "hmac-sha512" },
};
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
@@ -84,7 +85,7 @@ pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
return throughput;
}
-const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }};
+const exchanges = [_]Crypto{Crypto{ .ty = crypto.dh.X25519, .name = "x25519" }};
pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_count: comptime_int) !u64 {
std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length);
@@ -111,7 +112,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
return throughput;
}
-const signatures = [_]Crypto{Crypto{ .ty = crypto.Ed25519, .name = "ed25519" }};
+const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
var seed: [Signature.seed_length]u8 = undefined;
lib/std/crypto/chacha20.zig
@@ -12,7 +12,7 @@ const assert = std.debug.assert;
const testing = std.testing;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
-const Poly1305 = std.crypto.Poly1305;
+const Poly1305 = std.crypto.onetimeauth.Poly1305;
const QuarterRound = struct {
a: usize,
@@ -137,56 +137,60 @@ fn keyToWords(key: [32]u8) [8]u32 {
///
/// ChaCha20 is self-reversing. To decrypt just run the cipher with the same
/// counter, nonce, and key.
-pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
- assert(in.len >= out.len);
- assert((in.len >> 6) + counter <= maxInt(u32));
-
- var c: [4]u32 = undefined;
- c[0] = counter;
- c[1] = mem.readIntLittle(u32, nonce[0..4]);
- c[2] = mem.readIntLittle(u32, nonce[4..8]);
- c[3] = mem.readIntLittle(u32, nonce[8..12]);
- chaCha20_internal(out, in, keyToWords(key), c);
-}
+pub const ChaCha20IETF = struct {
+ pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [12]u8) void {
+ assert(in.len >= out.len);
+ assert((in.len >> 6) + counter <= maxInt(u32));
+
+ var c: [4]u32 = undefined;
+ c[0] = counter;
+ c[1] = mem.readIntLittle(u32, nonce[0..4]);
+ c[2] = mem.readIntLittle(u32, nonce[4..8]);
+ c[3] = mem.readIntLittle(u32, nonce[8..12]);
+ chaCha20_internal(out, in, keyToWords(key), c);
+ }
+};
/// This is the original ChaCha20 before RFC 7539, which recommends using the
/// orgininal version on applications such as disk or file encryption that might
/// exceed the 256 GiB limit of the 96-bit nonce version.
-pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
- assert(in.len >= out.len);
- assert(counter +% (in.len >> 6) >= counter);
-
- var cursor: usize = 0;
- const k = keyToWords(key);
- var c: [4]u32 = undefined;
- c[0] = @truncate(u32, counter);
- c[1] = @truncate(u32, counter >> 32);
- c[2] = mem.readIntLittle(u32, nonce[0..4]);
- c[3] = mem.readIntLittle(u32, nonce[4..8]);
-
- const block_size = (1 << 6);
- // The full block size is greater than the address space on a 32bit machine
- const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
-
- // first partial big block
- if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
- chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
- cursor = big_block - cursor;
- c[1] += 1;
- if (comptime @sizeOf(usize) > 4) {
- // A big block is giant: 256 GiB, but we can avoid this limitation
- var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
- var i: u32 = 0;
- while (remaining_blocks > 0) : (remaining_blocks -= 1) {
- chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
- c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
- cursor += big_block;
+pub const ChaCha20With64BitNonce = struct {
+ pub fn xor(out: []u8, in: []const u8, counter: u64, key: [32]u8, nonce: [8]u8) void {
+ assert(in.len >= out.len);
+ assert(counter +% (in.len >> 6) >= counter);
+
+ var cursor: usize = 0;
+ const k = keyToWords(key);
+ var c: [4]u32 = undefined;
+ c[0] = @truncate(u32, counter);
+ c[1] = @truncate(u32, counter >> 32);
+ c[2] = mem.readIntLittle(u32, nonce[0..4]);
+ c[3] = mem.readIntLittle(u32, nonce[4..8]);
+
+ const block_size = (1 << 6);
+ // The full block size is greater than the address space on a 32bit machine
+ const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize);
+
+ // first partial big block
+ if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) {
+ chaCha20_internal(out[cursor..big_block], in[cursor..big_block], k, c);
+ cursor = big_block - cursor;
+ c[1] += 1;
+ if (comptime @sizeOf(usize) > 4) {
+ // A big block is giant: 256 GiB, but we can avoid this limitation
+ var remaining_blocks: u32 = @intCast(u32, (in.len / big_block));
+ var i: u32 = 0;
+ while (remaining_blocks > 0) : (remaining_blocks -= 1) {
+ chaCha20_internal(out[cursor .. cursor + big_block], in[cursor .. cursor + big_block], k, c);
+ c[1] += 1; // upper 32-bit of counter, generic chaCha20_internal() doesn't know about this.
+ cursor += big_block;
+ }
}
}
- }
- chaCha20_internal(out[cursor..], in[cursor..], k, c);
-}
+ chaCha20_internal(out[cursor..], in[cursor..], k, c);
+ }
+};
// https://tools.ietf.org/html/rfc7539#section-2.4.2
test "crypto.chacha20 test vector sunscreen" {
@@ -221,12 +225,12 @@ test "crypto.chacha20 test vector sunscreen" {
0, 0, 0, 0,
};
- chaCha20IETF(result[0..], input[0..], 1, key, nonce);
+ ChaCha20IETF.xor(result[0..], input[0..], 1, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
// Chacha20 is self-reversing.
var plaintext: [114]u8 = undefined;
- chaCha20IETF(plaintext[0..], result[0..], 1, key, nonce);
+ ChaCha20IETF.xor(plaintext[0..], result[0..], 1, key, nonce);
testing.expect(mem.order(u8, input, &plaintext) == .eq);
}
@@ -261,7 +265,7 @@ test "crypto.chacha20 test vector 1" {
};
const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
- chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
+ ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
}
@@ -295,7 +299,7 @@ test "crypto.chacha20 test vector 2" {
};
const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0 };
- chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
+ ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
}
@@ -329,7 +333,7 @@ test "crypto.chacha20 test vector 3" {
};
const nonce = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 1 };
- chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
+ ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
}
@@ -363,7 +367,7 @@ test "crypto.chacha20 test vector 4" {
};
const nonce = [_]u8{ 1, 0, 0, 0, 0, 0, 0, 0 };
- chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
+ ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
}
@@ -435,21 +439,21 @@ test "crypto.chacha20 test vector 5" {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
};
- chaCha20With64BitNonce(result[0..], input[0..], 0, key, nonce);
+ ChaCha20With64BitNonce.xor(result[0..], input[0..], 0, key, nonce);
testing.expectEqualSlices(u8, &expected_result, &result);
}
pub const chacha20poly1305_tag_size = 16;
-pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
+fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
assert(ciphertext.len >= plaintext.len);
// derive poly1305 key
var polyKey = [_]u8{0} ** 32;
- chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce);
+ ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce);
// encrypt plaintext
- chaCha20IETF(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);
+ ChaCha20IETF.xor(ciphertext[0..plaintext.len], plaintext, 1, key, nonce);
// construct mac
var mac = Poly1305.init(polyKey[0..]);
@@ -472,18 +476,18 @@ pub fn chacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_ta
mac.final(tag);
}
-pub fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
+fn chacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) void {
return chacha20poly1305SealDetached(ciphertextAndTag[0..plaintext.len], ciphertextAndTag[plaintext.len..][0..chacha20poly1305_tag_size], plaintext, data, key, nonce);
}
/// Verifies and decrypts an authenticated message produced by chacha20poly1305SealDetached.
-pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
+fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
// split ciphertext and tag
assert(dst.len >= ciphertext.len);
// derive poly1305 key
var polyKey = [_]u8{0} ** 32;
- chaCha20IETF(polyKey[0..], polyKey[0..], 0, key, nonce);
+ ChaCha20IETF.xor(polyKey[0..], polyKey[0..], 0, key, nonce);
// construct mac
var mac = Poly1305.init(polyKey[0..]);
@@ -519,11 +523,11 @@ pub fn chacha20poly1305OpenDetached(dst: []u8, ciphertext: []const u8, tag: *con
}
// decrypt ciphertext
- chaCha20IETF(dst[0..ciphertext.len], ciphertext, 1, key, nonce);
+ ChaCha20IETF.xor(dst[0..ciphertext.len], ciphertext, 1, key, nonce);
}
/// Verifies and decrypts an authenticated message produced by chacha20poly1305Seal.
-pub fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
+fn chacha20poly1305Open(dst: []u8, ciphertextAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [12]u8) !void {
if (ciphertextAndTag.len < chacha20poly1305_tag_size) {
return error.InvalidMessage;
}
@@ -562,31 +566,33 @@ fn extend(key: [32]u8, nonce: [24]u8) struct { key: [32]u8, nonce: [12]u8 } {
};
}
-pub fn xChaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {
- const extended = extend(key, nonce);
- chaCha20IETF(out, in, counter, extended.key, extended.nonce);
-}
+pub const XChaCha20IETF = struct {
+ pub fn xor(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: [24]u8) void {
+ const extended = extend(key, nonce);
+ ChaCha20IETF.xor(out, in, counter, extended.key, extended.nonce);
+ }
+};
pub const xchacha20poly1305_tag_size = 16;
-pub fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
+fn xchacha20poly1305SealDetached(ciphertext: []u8, tag: *[chacha20poly1305_tag_size]u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
const extended = extend(key, nonce);
return chacha20poly1305SealDetached(ciphertext, tag, plaintext, data, extended.key, extended.nonce);
}
-pub fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
+fn xchacha20poly1305Seal(ciphertextAndTag: []u8, plaintext: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) void {
const extended = extend(key, nonce);
return chacha20poly1305Seal(ciphertextAndTag, plaintext, data, extended.key, extended.nonce);
}
/// Verifies and decrypts an authenticated message produced by xchacha20poly1305SealDetached.
-pub fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
+fn xchacha20poly1305OpenDetached(plaintext: []u8, ciphertext: []const u8, tag: *const [chacha20poly1305_tag_size]u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
const extended = extend(key, nonce);
return try chacha20poly1305OpenDetached(plaintext, ciphertext, tag, data, extended.key, extended.nonce);
}
/// Verifies and decrypts an authenticated message produced by xchacha20poly1305Seal.
-pub fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
+fn xchacha20poly1305Open(ciphertextAndTag: []u8, msgAndTag: []const u8, data: []const u8, key: [32]u8, nonce: [24]u8) !void {
const extended = extend(key, nonce);
return try chacha20poly1305Open(ciphertextAndTag, msgAndTag, data, extended.key, extended.nonce);
}
@@ -714,7 +720,7 @@ test "crypto.xchacha20" {
const input = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
{
var ciphertext: [input.len]u8 = undefined;
- xChaCha20IETF(ciphertext[0..], input[0..], 0, key, nonce);
+ XChaCha20IETF.xor(ciphertext[0..], input[0..], 0, key, nonce);
var buf: [2 * ciphertext.len]u8 = undefined;
testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{ciphertext}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
}
lib/std/crypto/gimli.zig
@@ -109,17 +109,21 @@ pub const Hash = struct {
state: State,
buf_off: usize,
+ pub const block_length = State.RATE;
+
const Self = @This();
pub fn init() Self {
return Self{
- .state = State{
- .data = [_]u32{0} ** (State.BLOCKBYTES / 4),
- },
+ .state = State{ .data = [_]u32{0} ** (State.BLOCKBYTES / 4) },
.buf_off = 0,
};
}
+ pub fn reset(self: *Self) void {
+ self.* = init();
+ }
+
/// Also known as 'absorb'
pub fn update(self: *Self, data: []const u8) void {
const buf = self.state.toSlice();
lib/std/crypto/hmac.zig
@@ -8,10 +8,19 @@ const crypto = std.crypto;
const debug = std.debug;
const mem = std.mem;
-pub const HmacMd5 = Hmac(crypto.Md5);
-pub const HmacSha1 = Hmac(crypto.Sha1);
-pub const HmacSha256 = Hmac(crypto.Sha256);
-pub const HmacBlake2s256 = Hmac(crypto.Blake2s256);
+pub const HmacMd5 = Hmac(crypto.hash.legacy.Md5);
+pub const HmacSha1 = Hmac(crypto.hash.legacy.Sha1);
+
+pub const sha2 = struct {
+ pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224);
+ pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256);
+ pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384);
+ pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512);
+};
+
+pub const blake2 = struct {
+ pub const HmacBlake2s256 = Hmac(crypto.hash.blake2.Blake2s256);
+};
pub fn Hmac(comptime Hash: type) type {
return struct {
@@ -95,10 +104,10 @@ test "hmac sha1" {
}
test "hmac sha256" {
- var out: [HmacSha256.mac_length]u8 = undefined;
- HmacSha256.create(out[0..], "", "");
+ var out: [sha2.HmacSha256.mac_length]u8 = undefined;
+ sha2.HmacSha256.create(out[0..], "", "");
htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
- HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
+ sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
}
lib/std/crypto/md5.zig
@@ -32,6 +32,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) RoundPar
};
}
+/// The MD5 function is now considered cryptographically broken.
+/// Namely, it is trivial to find multiple inputs producing the same hash.
+/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
pub const Md5 = struct {
const Self = @This();
pub const block_length = 64;
@@ -44,18 +47,21 @@ pub const Md5 = struct {
total_len: u64,
pub fn init() Self {
- var d: Self = undefined;
- d.reset();
- return d;
+ return Self{
+ .s = [_]u32{
+ 0x67452301,
+ 0xEFCDAB89,
+ 0x98BADCFE,
+ 0x10325476,
+ },
+ .buf = undefined,
+ .buf_len = 0,
+ .total_len = 0,
+ };
}
- pub fn reset(d: *Self) void {
- d.s[0] = 0x67452301;
- d.s[1] = 0xEFCDAB89;
- d.s[2] = 0x98BADCFE;
- d.s[3] = 0x10325476;
- d.buf_len = 0;
- d.total_len = 0;
+ pub fn reset(self: *Self) void {
+ self.* = init();
}
pub fn hash(b: []const u8, out: []u8) void {
lib/std/crypto/sha1.zig
@@ -29,6 +29,9 @@ fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) RoundParam {
};
}
+/// The SHA-1 function is now considered cryptographically broken.
+/// Namely, it is feasible to find multiple inputs producing the same hash.
+/// For a fast-performing, cryptographically secure hash function, see SHA512/256, BLAKE2 or BLAKE3.
pub const Sha1 = struct {
const Self = @This();
pub const block_length = 64;
@@ -41,19 +44,22 @@ pub const Sha1 = struct {
total_len: u64,
pub fn init() Self {
- var d: Self = undefined;
- d.reset();
- return d;
+ return Self{
+ .s = [_]u32{
+ 0x67452301,
+ 0xEFCDAB89,
+ 0x98BADCFE,
+ 0x10325476,
+ 0xC3D2E1F0,
+ },
+ .buf = undefined,
+ .buf_len = 0,
+ .total_len = 0,
+ };
}
- pub fn reset(d: *Self) void {
- d.s[0] = 0x67452301;
- d.s[1] = 0xEFCDAB89;
- d.s[2] = 0x98BADCFE;
- d.s[3] = 0x10325476;
- d.s[4] = 0xC3D2E1F0;
- d.buf_len = 0;
- d.total_len = 0;
+ pub fn reset(self: *Self) void {
+ self.* = init();
}
pub fn hash(b: []const u8, out: []u8) void {
lib/std/crypto/sha2.zig
@@ -93,22 +93,25 @@ fn Sha2_32(comptime params: Sha2Params32) type {
total_len: u64,
pub fn init() Self {
- var d: Self = undefined;
- d.reset();
- return d;
+ return Self{
+ .s = [_]u32{
+ params.iv0,
+ params.iv1,
+ params.iv2,
+ params.iv3,
+ params.iv4,
+ params.iv5,
+ params.iv6,
+ params.iv7,
+ },
+ .buf = undefined,
+ .buf_len = 0,
+ .total_len = 0,
+ };
}
- pub fn reset(d: *Self) void {
- d.s[0] = params.iv0;
- d.s[1] = params.iv1;
- d.s[2] = params.iv2;
- d.s[3] = params.iv3;
- d.s[4] = params.iv4;
- d.s[5] = params.iv5;
- d.s[6] = params.iv6;
- d.s[7] = params.iv7;
- d.buf_len = 0;
- d.total_len = 0;
+ pub fn reset(self: *Self) void {
+ self.* = init();
}
pub fn hash(b: []const u8, out: []u8) void {
lib/std/crypto/sha3.zig
@@ -27,14 +27,14 @@ fn Keccak(comptime bits: usize, comptime delim: u8) type {
pub fn init() Self {
var d: Self = undefined;
- d.reset();
- return d;
- }
-
- pub fn reset(d: *Self) void {
mem.set(u8, d.s[0..], 0);
d.offset = 0;
d.rate = 200 - (bits / 4);
+ return d;
+ }
+
+ pub fn reset(self: *Self) void {
+ self.* = init();
}
pub fn hash(b: []const u8, out: []u8) void {
lib/std/bloom_filter.zig
@@ -158,7 +158,7 @@ pub fn BloomFilter(
}
fn hashFunc(out: []u8, Ki: usize, in: []const u8) void {
- var st = std.crypto.gimli.Hash.init();
+ var st = std.crypto.hash.Gimli.init();
st.update(std.mem.asBytes(&Ki));
st.update(in);
st.final(out);
lib/std/cache_hash.zig
@@ -4,7 +4,7 @@
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("std.zig");
-const Blake3 = std.crypto.Blake3;
+const Blake3 = std.crypto.hash.Blake3;
const fs = std.fs;
const base64 = std.base64;
const ArrayList = std.ArrayList;
lib/std/crypto.zig
@@ -3,60 +3,68 @@
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
-pub const Md5 = @import("crypto/md5.zig").Md5;
-pub const Sha1 = @import("crypto/sha1.zig").Sha1;
-
-const sha2 = @import("crypto/sha2.zig");
-pub const Sha224 = sha2.Sha224;
-pub const Sha256 = sha2.Sha256;
-pub const Sha384 = sha2.Sha384;
-pub const Sha512 = sha2.Sha512;
-
-const sha3 = @import("crypto/sha3.zig");
-pub const Sha3_224 = sha3.Sha3_224;
-pub const Sha3_256 = sha3.Sha3_256;
-pub const Sha3_384 = sha3.Sha3_384;
-pub const Sha3_512 = sha3.Sha3_512;
-
-pub const gimli = @import("crypto/gimli.zig");
-
-const blake2 = @import("crypto/blake2.zig");
-pub const Blake2s224 = blake2.Blake2s224;
-pub const Blake2s256 = blake2.Blake2s256;
-pub const Blake2b384 = blake2.Blake2b384;
-pub const Blake2b512 = blake2.Blake2b512;
-
-pub const Blake3 = @import("crypto/blake3.zig").Blake3;
-
-const hmac = @import("crypto/hmac.zig");
-pub const HmacMd5 = hmac.HmacMd5;
-pub const HmacSha1 = hmac.HmacSha1;
-pub const HmacSha256 = hmac.HmacSha256;
-pub const HmacBlake2s256 = hmac.HmacBlake2s256;
-
-pub const chacha20 = @import("crypto/chacha20.zig");
-pub const chaCha20IETF = chacha20.chaCha20IETF;
-pub const chaCha20With64BitNonce = chacha20.chaCha20With64BitNonce;
-pub const xChaCha20IETF = chacha20.xChaCha20IETF;
-
-pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
-
-const import_aes = @import("crypto/aes.zig");
-pub const AES128 = import_aes.AES128;
-pub const AES256 = import_aes.AES256;
-
-pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
-pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
-pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
-pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
-pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
+/// Hash functions.
+pub const hash = struct {
+ pub const Md5 = @import("crypto/md5.zig").Md5;
+ pub const Sha1 = @import("crypto/sha1.zig").Sha1;
+ pub const sha2 = @import("crypto/sha2.zig");
+ pub const sha3 = @import("crypto/sha3.zig");
+ pub const blake2 = @import("crypto/blake2.zig");
+ pub const Blake3 = @import("crypto/blake3.zig").Blake3;
+ pub const Gimli = @import("crypto/gimli.zig").Hash;
+};
+
+/// Authentication (MAC) functions.
+pub const auth = struct {
+ pub const hmac = @import("crypto/hmac.zig");
+};
+
+/// Authenticated Encryption with Associated Data
pub const aead = struct {
- pub const Gimli = gimli.Aead;
+ const chacha20 = @import("crypto/chacha20.zig");
+
+ pub const Gimli = @import("crypto/gimli.zig").Aead;
pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
};
+/// MAC functions requiring single-use secret keys.
+pub const onetimeauth = struct {
+ pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
+};
+
+/// Core functions, that should rarely be used directly by applications.
+pub const core = struct {
+ pub const aes = @import("crypto/aes.zig");
+ pub const Gimli = @import("crypto/gimli.zig").State;
+};
+
+/// Elliptic-curve arithmetic.
+pub const ecc = struct {
+ pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
+ pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
+ pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
+};
+
+/// Diffie-Hellman key exchange functions.
+pub const dh = struct {
+ pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
+};
+
+/// Digital signature functions.
+pub const sign = struct {
+ pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
+};
+
+/// Stream ciphers. These do not provide any kind of authentication.
+/// Most applications should be using AEAD constructions instead of stream ciphers directly.
+pub const stream = struct {
+ pub const ChaCha20IETF = @import("crypto/chacha20.zig").ChaCha20IETF;
+ pub const XChaCha20IETF = @import("crypto/chacha20.zig").XChaCha20IETF;
+ pub const ChaCha20With64BitNonce = @import("crypto/chacha20.zig").ChaCha20With64BitNonce;
+};
+
const std = @import("std.zig");
pub const randomBytes = std.os.getrandom;
@@ -83,16 +91,21 @@ test "crypto" {
test "issue #4532: no index out of bounds" {
const types = [_]type{
- Md5,
- Sha1,
- Sha224,
- Sha256,
- Sha384,
- Sha512,
- Blake2s224,
- Blake2s256,
- Blake2b384,
- Blake2b512,
+ hash.Md5,
+ hash.Sha1,
+ hash.sha2.Sha224,
+ hash.sha2.Sha256,
+ hash.sha2.Sha384,
+ hash.sha2.Sha512,
+ hash.sha3.Sha3_224,
+ hash.sha3.Sha3_256,
+ hash.sha3.Sha3_384,
+ hash.sha3.Sha3_512,
+ hash.blake2.Blake2s224,
+ hash.blake2.Blake2s256,
+ hash.blake2.Blake2b384,
+ hash.blake2.Blake2b512,
+ hash.Gimli,
};
inline for (types) |Hasher| {
lib/std/rand.zig
@@ -737,12 +737,12 @@ test "xoroshiro sequence" {
// CSPRNG
pub const Gimli = struct {
random: Random,
- state: std.crypto.gimli.State,
+ state: std.crypto.core.Gimli,
pub fn init(init_s: u64) Gimli {
var self = Gimli{
.random = Random{ .fillFn = fill },
- .state = std.crypto.gimli.State{
+ .state = std.crypto.core.Gimli{
.data = [_]u32{0} ** (std.crypto.gimli.State.BLOCKBYTES / 4),
},
};
lib/std/zig.zig
@@ -26,7 +26,7 @@ pub fn hashSrc(src: []const u8) SrcHash {
std.mem.copy(u8, &out, src);
std.mem.set(u8, out[src.len..], 0);
} else {
- std.crypto.Blake3.hash(src, &out);
+ std.crypto.hash.Blake3.hash(src, &out);
}
return out;
}
tools/process_headers.zig
@@ -313,7 +313,7 @@ pub fn main() !void {
var max_bytes_saved: usize = 0;
var total_bytes: usize = 0;
- var hasher = std.crypto.Sha256.init();
+ var hasher = std.crypto.hash.sha2.Sha256.init();
for (libc_targets) |libc_target| {
const dest_target = DestTarget{