mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
std.crypto: better names for everything in utils
std.crypto has quite a few instances of breaking naming conventions. This is the beginning of an effort to address that. Deprecates `std.crypto.utils`.
This commit is contained in:
parent
ae5bf2faab
commit
54151428e5
@ -5053,7 +5053,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||||||
It may have any alignment, and it may have any element type.</p>
|
It may have any alignment, and it may have any element type.</p>
|
||||||
<p>{#syntax#}elem{#endsyntax#} is coerced to the element type of {#syntax#}dest{#endsyntax#}.</p>
|
<p>{#syntax#}elem{#endsyntax#} is coerced to the element type of {#syntax#}dest{#endsyntax#}.</p>
|
||||||
<p>For securely zeroing out sensitive contents from memory, you should use
|
<p>For securely zeroing out sensitive contents from memory, you should use
|
||||||
{#syntax#}std.crypto.utils.secureZero{#endsyntax#}</p>
|
{#syntax#}std.crypto.secureZero{#endsyntax#}</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@min#}
|
{#header_open|@min#}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
|
||||||
|
pub const timing_safe = @import("crypto/timing_safe.zig");
|
||||||
|
|
||||||
/// Authenticated Encryption with Associated Data
|
/// Authenticated Encryption with Associated Data
|
||||||
pub const aead = struct {
|
pub const aead = struct {
|
||||||
pub const aegis = struct {
|
pub const aegis = struct {
|
||||||
@ -180,8 +182,6 @@ pub const nacl = struct {
|
|||||||
pub const SealedBox = salsa20.SealedBox;
|
pub const SealedBox = salsa20.SealedBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const utils = @import("crypto/utils.zig");
|
|
||||||
|
|
||||||
/// Finite-field arithmetic.
|
/// Finite-field arithmetic.
|
||||||
pub const ff = @import("crypto/ff.zig");
|
pub const ff = @import("crypto/ff.zig");
|
||||||
|
|
||||||
@ -301,7 +301,8 @@ test {
|
|||||||
_ = nacl.SecretBox;
|
_ = nacl.SecretBox;
|
||||||
_ = nacl.SealedBox;
|
_ = nacl.SealedBox;
|
||||||
|
|
||||||
_ = utils;
|
_ = secureZero;
|
||||||
|
_ = timing_safe;
|
||||||
_ = ff;
|
_ = ff;
|
||||||
_ = random;
|
_ = random;
|
||||||
_ = errors;
|
_ = errors;
|
||||||
@ -353,3 +354,36 @@ test "issue #4532: no index out of bounds" {
|
|||||||
try std.testing.expectEqual(out1, out2);
|
try std.testing.expectEqual(out1, out2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets a slice to zeroes.
|
||||||
|
/// Prevents the store from being optimized out.
|
||||||
|
pub inline fn secureZero(comptime T: type, s: []volatile T) void {
|
||||||
|
@memset(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test secureZero {
|
||||||
|
var a = [_]u8{0xfe} ** 8;
|
||||||
|
var b = [_]u8{0xfe} ** 8;
|
||||||
|
|
||||||
|
@memset(&a, 0);
|
||||||
|
secureZero(u8, &b);
|
||||||
|
|
||||||
|
try std.testing.expectEqualSlices(u8, &a, &b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deprecated in favor of `std.crypto`. To be removed after Zig 0.14.0 is released.
|
||||||
|
///
|
||||||
|
/// As a reminder, never use "utils" in a namespace (in any programming language).
|
||||||
|
/// https://ziglang.org/documentation/0.13.0/#Avoid-Redundancy-in-Names
|
||||||
|
pub const utils = struct {
|
||||||
|
/// Deprecated in favor of `std.crypto.secureZero`.
|
||||||
|
pub const secureZero = std.crypto.secureZero;
|
||||||
|
/// Deprecated in favor of `std.crypto.timing_safe.eql`.
|
||||||
|
pub const timingSafeEql = timing_safe.eql;
|
||||||
|
/// Deprecated in favor of `std.crypto.timing_safe.compare`.
|
||||||
|
pub const timingSafeCompare = timing_safe.compare;
|
||||||
|
/// Deprecated in favor of `std.crypto.timing_safe.add`.
|
||||||
|
pub const timingSafeAdd = timing_safe.add;
|
||||||
|
/// Deprecated in favor of `std.crypto.timing_safe.sub`.
|
||||||
|
pub const timingSafeSub = timing_safe.sub;
|
||||||
|
};
|
||||||
|
|||||||
@ -208,9 +208,9 @@ fn Aegis128LGeneric(comptime tag_bits: u9) type {
|
|||||||
blocks[4] = blocks[4].xorBlocks(AesBlock.fromBytes(dst[16..32]));
|
blocks[4] = blocks[4].xorBlocks(AesBlock.fromBytes(dst[16..32]));
|
||||||
}
|
}
|
||||||
var computed_tag = state.mac(tag_bits, ad.len, m.len);
|
var computed_tag = state.mac(tag_bits, ad.len, m.len);
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
@ -390,9 +390,9 @@ fn Aegis256Generic(comptime tag_bits: u9) type {
|
|||||||
blocks[0] = blocks[0].xorBlocks(AesBlock.fromBytes(&dst));
|
blocks[0] = blocks[0].xorBlocks(AesBlock.fromBytes(&dst));
|
||||||
}
|
}
|
||||||
var computed_tag = state.mac(tag_bits, ad.len, m.len);
|
var computed_tag = state.mac(tag_bits, ad.len, m.len);
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,9 +95,9 @@ fn AesGcm(comptime Aes: anytype) type {
|
|||||||
computed_tag[i] ^= x;
|
computed_tag[i] ^= x;
|
||||||
}
|
}
|
||||||
|
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -234,9 +234,9 @@ fn AesOcb(comptime Aes: anytype) type {
|
|||||||
var e = xorBlocks(xorBlocks(sum, offset), lx.dol);
|
var e = xorBlocks(xorBlocks(sum, offset), lx.dol);
|
||||||
aes_enc_ctx.encrypt(&e, &e);
|
aes_enc_ctx.encrypt(&e, &e);
|
||||||
var computed_tag = xorBlocks(e, hash(aes_enc_ctx, &lx, ad));
|
var computed_tag = xorBlocks(e, hash(aes_enc_ctx, &lx, ad));
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,7 +152,7 @@ pub fn State(comptime endian: std.builtin.Endian) type {
|
|||||||
|
|
||||||
/// Clear the entire state, disabling compiler optimizations.
|
/// Clear the entire state, disabling compiler optimizations.
|
||||||
pub fn secureZero(self: *Self) void {
|
pub fn secureZero(self: *Self) void {
|
||||||
std.crypto.utils.secureZero(u64, &self.st);
|
std.crypto.secureZero(u64, &self.st);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a reduced-round permutation to the state.
|
/// Apply a reduced-round permutation to the state.
|
||||||
|
|||||||
@ -9,7 +9,6 @@ const pwhash = crypto.pwhash;
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const HmacSha512 = crypto.auth.hmac.sha2.HmacSha512;
|
const HmacSha512 = crypto.auth.hmac.sha2.HmacSha512;
|
||||||
const Sha512 = crypto.hash.sha2.Sha512;
|
const Sha512 = crypto.hash.sha2.Sha512;
|
||||||
const utils = crypto.utils;
|
|
||||||
|
|
||||||
const phc_format = @import("phc_encoding.zig");
|
const phc_format = @import("phc_encoding.zig");
|
||||||
|
|
||||||
@ -446,7 +445,7 @@ pub fn bcrypt(
|
|||||||
state.expand0(passwordZ);
|
state.expand0(passwordZ);
|
||||||
state.expand0(salt[0..]);
|
state.expand0(salt[0..]);
|
||||||
}
|
}
|
||||||
utils.secureZero(u8, &password_buf);
|
crypto.secureZero(u8, &password_buf);
|
||||||
|
|
||||||
var cdata = [6]u32{ 0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274 }; // "OrpheanBeholderScryDoubt"
|
var cdata = [6]u32{ 0x4f727068, 0x65616e42, 0x65686f6c, 0x64657253, 0x63727944, 0x6f756274 }; // "OrpheanBeholderScryDoubt"
|
||||||
k = 0;
|
k = 0;
|
||||||
@ -556,8 +555,8 @@ const pbkdf_prf = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// zap
|
// zap
|
||||||
crypto.utils.secureZero(u32, &cdata);
|
crypto.secureZero(u32, &cdata);
|
||||||
crypto.utils.secureZero(u32, &state.subkeys);
|
crypto.secureZero(u32, &state.subkeys);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -714,9 +714,9 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type {
|
|||||||
var computed_tag: [16]u8 = undefined;
|
var computed_tag: [16]u8 = undefined;
|
||||||
mac.final(computed_tag[0..]);
|
mac.final(computed_tag[0..]);
|
||||||
|
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -225,12 +225,12 @@ pub fn Uint(comptime max_bits: comptime_int) type {
|
|||||||
|
|
||||||
/// Returns `true` if both integers are equal.
|
/// Returns `true` if both integers are equal.
|
||||||
pub fn eql(x: Self, y: Self) bool {
|
pub fn eql(x: Self, y: Self) bool {
|
||||||
return crypto.utils.timingSafeEql([max_limbs_count]Limb, x.limbs_buffer, y.limbs_buffer);
|
return crypto.timing_safe.eql([max_limbs_count]Limb, x.limbs_buffer, y.limbs_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compares two integers.
|
/// Compares two integers.
|
||||||
pub fn compare(x: Self, y: Self) math.Order {
|
pub fn compare(x: Self, y: Self) math.Order {
|
||||||
return crypto.utils.timingSafeCompare(
|
return crypto.timing_safe.compare(
|
||||||
Limb,
|
Limb,
|
||||||
x.limbsConst(),
|
x.limbsConst(),
|
||||||
y.limbsConst(),
|
y.limbsConst(),
|
||||||
|
|||||||
@ -3,7 +3,6 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const utils = std.crypto.utils;
|
|
||||||
|
|
||||||
const Precomp = u128;
|
const Precomp = u128;
|
||||||
|
|
||||||
@ -403,7 +402,7 @@ fn Hash(comptime endian: std.builtin.Endian, comptime shift_key: bool) type {
|
|||||||
st.pad();
|
st.pad();
|
||||||
mem.writeInt(u128, out[0..16], st.acc, endian);
|
mem.writeInt(u128, out[0..16], st.acc, endian);
|
||||||
|
|
||||||
utils.secureZero(u8, @as([*]u8, @ptrCast(st))[0..@sizeOf(Self)]);
|
std.crypto.secureZero(u8, @as([*]u8, @ptrCast(st))[0..@sizeOf(Self)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the GHASH of a message.
|
/// Compute the GHASH of a message.
|
||||||
|
|||||||
@ -158,9 +158,9 @@ pub const IsapA128A = struct {
|
|||||||
/// Contents of `m` are undefined if an error is returned.
|
/// Contents of `m` are undefined if an error is returned.
|
||||||
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
|
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
|
||||||
var computed_tag = mac(c, ad, npub, key);
|
var computed_tag = mac(c, ad, npub, key);
|
||||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
crypto.utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,7 +132,7 @@ pub fn KeccakF(comptime f: u11) type {
|
|||||||
|
|
||||||
/// Clear the entire state, disabling compiler optimizations.
|
/// Clear the entire state, disabling compiler optimizations.
|
||||||
pub fn secureZero(self: *Self) void {
|
pub fn secureZero(self: *Self) void {
|
||||||
std.crypto.utils.secureZero(T, &self.st);
|
std.crypto.secureZero(T, &self.st);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn round(self: *Self, rc: T) void {
|
inline fn round(self: *Self, rc: T) void {
|
||||||
|
|||||||
@ -1508,7 +1508,7 @@ fn Mat(comptime K: u8) type {
|
|||||||
|
|
||||||
// Returns `true` if a ≠ b.
|
// Returns `true` if a ≠ b.
|
||||||
fn ctneq(comptime len: usize, a: [len]u8, b: [len]u8) u1 {
|
fn ctneq(comptime len: usize, a: [len]u8, b: [len]u8) u1 {
|
||||||
return 1 - @intFromBool(crypto.utils.timingSafeEql([len]u8, a, b));
|
return 1 - @intFromBool(crypto.timing_safe.eql([len]u8, a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy src into dst given b = 1.
|
// Copy src into dst given b = 1.
|
||||||
|
|||||||
@ -57,7 +57,7 @@ pub fn Field(comptime params: FieldParams) type {
|
|||||||
mem.writeInt(std.meta.Int(.unsigned, encoded_length * 8), &fos, field_order, .little);
|
mem.writeInt(std.meta.Int(.unsigned, encoded_length * 8), &fos, field_order, .little);
|
||||||
break :fos fos;
|
break :fos fos;
|
||||||
};
|
};
|
||||||
if (crypto.utils.timingSafeCompare(u8, &s, &field_order_s, .little) != .lt) {
|
if (crypto.timing_safe.compare(u8, &s, &field_order_s, .little) != .lt) {
|
||||||
return error.NonCanonical;
|
return error.NonCanonical;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const utils = std.crypto.utils;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const mulWide = std.math.mulWide;
|
const mulWide = std.math.mulWide;
|
||||||
|
|
||||||
@ -185,7 +184,7 @@ pub const Poly1305 = struct {
|
|||||||
mem.writeInt(u64, out[0..8], st.h[0], .little);
|
mem.writeInt(u64, out[0..8], st.h[0], .little);
|
||||||
mem.writeInt(u64, out[8..16], st.h[1], .little);
|
mem.writeInt(u64, out[8..16], st.h[1], .little);
|
||||||
|
|
||||||
utils.secureZero(u8, @as([*]u8, @ptrCast(st))[0..@sizeOf(Poly1305)]);
|
std.crypto.secureZero(u8, @as([*]u8, @ptrCast(st))[0..@sizeOf(Poly1305)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
|
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ const crypto = std.crypto;
|
|||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const utils = std.crypto.utils;
|
|
||||||
|
|
||||||
const Poly1305 = crypto.onetimeauth.Poly1305;
|
const Poly1305 = crypto.onetimeauth.Poly1305;
|
||||||
const Blake2b = crypto.hash.blake2.Blake2b;
|
const Blake2b = crypto.hash.blake2.Blake2b;
|
||||||
@ -419,9 +418,9 @@ pub const XSalsa20Poly1305 = struct {
|
|||||||
var computed_tag: [tag_length]u8 = undefined;
|
var computed_tag: [tag_length]u8 = undefined;
|
||||||
mac.final(&computed_tag);
|
mac.final(&computed_tag);
|
||||||
|
|
||||||
const verify = utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
|
||||||
if (!verify) {
|
if (!verify) {
|
||||||
utils.secureZero(u8, &computed_tag);
|
crypto.secureZero(u8, &computed_tag);
|
||||||
@memset(m, undefined);
|
@memset(m, undefined);
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
@ -540,7 +539,7 @@ pub const SealedBox = struct {
|
|||||||
const nonce = createNonce(ekp.public_key, public_key);
|
const nonce = createNonce(ekp.public_key, public_key);
|
||||||
c[0..public_length].* = ekp.public_key;
|
c[0..public_length].* = ekp.public_key;
|
||||||
try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key);
|
try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key);
|
||||||
utils.secureZero(u8, ekp.secret_key[0..]);
|
crypto.secureZero(u8, ekp.secret_key[0..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a message using a key pair.
|
/// Decrypt a message using a key pair.
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
const std = @import("../std.zig");
|
//! Please see this accepted proposal for the long-term plans regarding
|
||||||
const debug = std.debug;
|
//! constant-time operations in Zig: https://github.com/ziglang/zig/issues/1776
|
||||||
const mem = std.mem;
|
|
||||||
const random = std.crypto.random;
|
|
||||||
const testing = std.testing;
|
|
||||||
|
|
||||||
|
const std = @import("../std.zig");
|
||||||
|
const assert = std.debug.assert;
|
||||||
const Endian = std.builtin.Endian;
|
const Endian = std.builtin.Endian;
|
||||||
const Order = std.math.Order;
|
const Order = std.math.Order;
|
||||||
|
|
||||||
/// Compares two arrays in constant time (for a given length) and returns whether they are equal.
|
/// Compares two arrays in constant time (for a given length) and returns whether they are equal.
|
||||||
/// This function was designed to compare short cryptographic secrets (MACs, signatures).
|
/// This function was designed to compare short cryptographic secrets (MACs, signatures).
|
||||||
/// For all other applications, use mem.eql() instead.
|
/// For all other applications, use mem.eql() instead.
|
||||||
pub fn timingSafeEql(comptime T: type, a: T, b: T) bool {
|
pub fn eql(comptime T: type, a: T, b: T) bool {
|
||||||
switch (@typeInfo(T)) {
|
switch (@typeInfo(T)) {
|
||||||
.Array => |info| {
|
.Array => |info| {
|
||||||
const C = info.child;
|
const C = info.child;
|
||||||
@ -45,8 +44,8 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool {
|
|||||||
|
|
||||||
/// Compare two integers serialized as arrays of the same size, in constant time.
|
/// Compare two integers serialized as arrays of the same size, in constant time.
|
||||||
/// Returns .lt if a<b, .gt if a>b and .eq if a=b
|
/// Returns .lt if a<b, .gt if a>b and .eq if a=b
|
||||||
pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: Endian) Order {
|
pub fn compare(comptime T: type, a: []const T, b: []const T, endian: Endian) Order {
|
||||||
debug.assert(a.len == b.len);
|
assert(a.len == b.len);
|
||||||
const bits = switch (@typeInfo(T)) {
|
const bits = switch (@typeInfo(T)) {
|
||||||
.Int => |cinfo| if (cinfo.signedness != .unsigned) @compileError("Elements to be compared must be unsigned") else cinfo.bits,
|
.Int => |cinfo| if (cinfo.signedness != .unsigned) @compileError("Elements to be compared must be unsigned") else cinfo.bits,
|
||||||
else => @compileError("Elements to be compared must be integers"),
|
else => @compileError("Elements to be compared must be integers"),
|
||||||
@ -80,9 +79,9 @@ pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: E
|
|||||||
|
|
||||||
/// Add two integers serialized as arrays of the same size, in constant time.
|
/// Add two integers serialized as arrays of the same size, in constant time.
|
||||||
/// The result is stored into `result`, and `true` is returned if an overflow occurred.
|
/// The result is stored into `result`, and `true` is returned if an overflow occurred.
|
||||||
pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T, endian: Endian) bool {
|
pub fn add(comptime T: type, a: []const T, b: []const T, result: []T, endian: Endian) bool {
|
||||||
const len = a.len;
|
const len = a.len;
|
||||||
debug.assert(len == b.len and len == result.len);
|
assert(len == b.len and len == result.len);
|
||||||
var carry: u1 = 0;
|
var carry: u1 = 0;
|
||||||
if (endian == .little) {
|
if (endian == .little) {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@ -107,9 +106,9 @@ pub fn timingSafeAdd(comptime T: type, a: []const T, b: []const T, result: []T,
|
|||||||
|
|
||||||
/// Subtract two integers serialized as arrays of the same size, in constant time.
|
/// Subtract two integers serialized as arrays of the same size, in constant time.
|
||||||
/// The result is stored into `result`, and `true` is returned if an underflow occurred.
|
/// The result is stored into `result`, and `true` is returned if an underflow occurred.
|
||||||
pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T, endian: Endian) bool {
|
pub fn sub(comptime T: type, a: []const T, b: []const T, result: []T, endian: Endian) bool {
|
||||||
const len = a.len;
|
const len = a.len;
|
||||||
debug.assert(len == b.len and len == result.len);
|
assert(len == b.len and len == result.len);
|
||||||
var borrow: u1 = 0;
|
var borrow: u1 = 0;
|
||||||
if (endian == .little) {
|
if (endian == .little) {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@ -132,50 +131,52 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,
|
|||||||
return @as(bool, @bitCast(borrow));
|
return @as(bool, @bitCast(borrow));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a slice to zeroes.
|
test eql {
|
||||||
/// Prevents the store from being optimized out.
|
const random = std.crypto.random;
|
||||||
pub inline fn secureZero(comptime T: type, s: []T) void {
|
const expect = std.testing.expect;
|
||||||
@memset(@as([]volatile T, s), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
test timingSafeEql {
|
|
||||||
var a: [100]u8 = undefined;
|
var a: [100]u8 = undefined;
|
||||||
var b: [100]u8 = undefined;
|
var b: [100]u8 = undefined;
|
||||||
random.bytes(a[0..]);
|
random.bytes(a[0..]);
|
||||||
random.bytes(b[0..]);
|
random.bytes(b[0..]);
|
||||||
try testing.expect(!timingSafeEql([100]u8, a, b));
|
try expect(!eql([100]u8, a, b));
|
||||||
a = b;
|
a = b;
|
||||||
try testing.expect(timingSafeEql([100]u8, a, b));
|
try expect(eql([100]u8, a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "timingSafeEql (vectors)" {
|
test "eql (vectors)" {
|
||||||
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||||
|
|
||||||
|
const random = std.crypto.random;
|
||||||
|
const expect = std.testing.expect;
|
||||||
var a: [100]u8 = undefined;
|
var a: [100]u8 = undefined;
|
||||||
var b: [100]u8 = undefined;
|
var b: [100]u8 = undefined;
|
||||||
random.bytes(a[0..]);
|
random.bytes(a[0..]);
|
||||||
random.bytes(b[0..]);
|
random.bytes(b[0..]);
|
||||||
const v1: @Vector(100, u8) = a;
|
const v1: @Vector(100, u8) = a;
|
||||||
const v2: @Vector(100, u8) = b;
|
const v2: @Vector(100, u8) = b;
|
||||||
try testing.expect(!timingSafeEql(@Vector(100, u8), v1, v2));
|
try expect(!eql(@Vector(100, u8), v1, v2));
|
||||||
const v3: @Vector(100, u8) = a;
|
const v3: @Vector(100, u8) = a;
|
||||||
try testing.expect(timingSafeEql(@Vector(100, u8), v1, v3));
|
try expect(eql(@Vector(100, u8), v1, v3));
|
||||||
}
|
}
|
||||||
|
|
||||||
test timingSafeCompare {
|
test compare {
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
var a = [_]u8{10} ** 32;
|
var a = [_]u8{10} ** 32;
|
||||||
var b = [_]u8{10} ** 32;
|
var b = [_]u8{10} ** 32;
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .big), .eq);
|
try expectEqual(compare(u8, &a, &b, .big), .eq);
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .little), .eq);
|
try expectEqual(compare(u8, &a, &b, .little), .eq);
|
||||||
a[31] = 1;
|
a[31] = 1;
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .big), .lt);
|
try expectEqual(compare(u8, &a, &b, .big), .lt);
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .little), .lt);
|
try expectEqual(compare(u8, &a, &b, .little), .lt);
|
||||||
a[0] = 20;
|
a[0] = 20;
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .big), .gt);
|
try expectEqual(compare(u8, &a, &b, .big), .gt);
|
||||||
try testing.expectEqual(timingSafeCompare(u8, &a, &b, .little), .lt);
|
try expectEqual(compare(u8, &a, &b, .little), .lt);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "timingSafe{Add,Sub}" {
|
test "add and sub" {
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||||
|
const random = std.crypto.random;
|
||||||
const len = 32;
|
const len = 32;
|
||||||
var a: [len]u8 = undefined;
|
var a: [len]u8 = undefined;
|
||||||
var b: [len]u8 = undefined;
|
var b: [len]u8 = undefined;
|
||||||
@ -186,21 +187,11 @@ test "timingSafe{Add,Sub}" {
|
|||||||
random.bytes(&a);
|
random.bytes(&a);
|
||||||
random.bytes(&b);
|
random.bytes(&b);
|
||||||
const endian = if (iterations % 2 == 0) Endian.big else Endian.little;
|
const endian = if (iterations % 2 == 0) Endian.big else Endian.little;
|
||||||
_ = timingSafeSub(u8, &a, &b, &c, endian); // a-b
|
_ = sub(u8, &a, &b, &c, endian); // a-b
|
||||||
_ = timingSafeAdd(u8, &c, &b, &c, endian); // (a-b)+b
|
_ = add(u8, &c, &b, &c, endian); // (a-b)+b
|
||||||
try testing.expectEqualSlices(u8, &c, &a);
|
try expectEqualSlices(u8, &c, &a);
|
||||||
const borrow = timingSafeSub(u8, &c, &a, &c, endian); // ((a-b)+b)-a
|
const borrow = sub(u8, &c, &a, &c, endian); // ((a-b)+b)-a
|
||||||
try testing.expectEqualSlices(u8, &c, &zero);
|
try expectEqualSlices(u8, &c, &zero);
|
||||||
try testing.expectEqual(borrow, false);
|
try expectEqual(borrow, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test secureZero {
|
|
||||||
var a = [_]u8{0xfe} ** 8;
|
|
||||||
var b = [_]u8{0xfe} ** 8;
|
|
||||||
|
|
||||||
@memset(a[0..], 0);
|
|
||||||
secureZero(u8, b[0..]);
|
|
||||||
|
|
||||||
try testing.expectEqualSlices(u8, a[0..], b[0..]);
|
|
||||||
}
|
|
||||||
@ -137,7 +137,7 @@ fn childAtForkHandler() callconv(.C) void {
|
|||||||
// The atfork handler is global, this function may be called after
|
// The atfork handler is global, this function may be called after
|
||||||
// fork()-ing threads that never initialized the CSPRNG context.
|
// fork()-ing threads that never initialized the CSPRNG context.
|
||||||
if (wipe_mem.len == 0) return;
|
if (wipe_mem.len == 0) return;
|
||||||
std.crypto.utils.secureZero(u8, wipe_mem);
|
std.crypto.secureZero(u8, wipe_mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fillWithCsprng(buffer: []u8) void {
|
fn fillWithCsprng(buffer: []u8) void {
|
||||||
@ -159,7 +159,7 @@ fn initAndFill(buffer: []u8) void {
|
|||||||
|
|
||||||
const ctx = @as(*Context, @ptrCast(wipe_mem.ptr));
|
const ctx = @as(*Context, @ptrCast(wipe_mem.ptr));
|
||||||
ctx.rng = Rng.init(seed);
|
ctx.rng = Rng.init(seed);
|
||||||
std.crypto.utils.secureZero(u8, &seed);
|
std.crypto.secureZero(u8, &seed);
|
||||||
|
|
||||||
// This is at the end so that accidental recursive dependencies result
|
// This is at the end so that accidental recursive dependencies result
|
||||||
// in stack overflows instead of invalid random data.
|
// in stack overflows instead of invalid random data.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user