mirror of
https://github.com/ziglang/zig.git
synced 2024-11-16 09:03:12 +00:00
Merge pull request #8609 from jedisct1/timingSafeCompare
Add std.crypto.utils.timingSafeCompare
This commit is contained in:
commit
1c0259f11e
@ -1,7 +1,11 @@
|
||||
const std = @import("../std.zig");
|
||||
const debug = std.debug;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
const Endian = std.builtin.Endian;
|
||||
const Order = std.math.Order;
|
||||
|
||||
/// 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).
|
||||
/// For all other applications, use mem.eql() instead.
|
||||
@ -38,6 +42,41 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: Endian) Order {
|
||||
debug.assert(a.len == b.len);
|
||||
const bits = switch (@typeInfo(T)) {
|
||||
.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"),
|
||||
};
|
||||
comptime const Cext = std.meta.Int(.unsigned, bits + 1);
|
||||
var gt: T = 0;
|
||||
var eq: T = 1;
|
||||
if (endian == .Little) {
|
||||
var i = a.len;
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
const x1 = a[i];
|
||||
const x2 = b[i];
|
||||
gt |= @truncate(T, (@as(Cext, x2) -% @as(Cext, x1)) >> bits) & eq;
|
||||
eq &= @truncate(T, (@as(Cext, (x2 ^ x1)) -% 1) >> bits);
|
||||
}
|
||||
} else {
|
||||
for (a) |x1, i| {
|
||||
const x2 = b[i];
|
||||
gt |= @truncate(T, (@as(Cext, x2) -% @as(Cext, x1)) >> bits) & eq;
|
||||
eq &= @truncate(T, (@as(Cext, (x2 ^ x1)) -% 1) >> bits);
|
||||
}
|
||||
}
|
||||
if (gt != 0) {
|
||||
return Order.gt;
|
||||
} else if (eq != 0) {
|
||||
return Order.eq;
|
||||
}
|
||||
return Order.lt;
|
||||
}
|
||||
|
||||
/// Sets a slice to zeroes.
|
||||
/// Prevents the store from being optimized out.
|
||||
pub fn secureZero(comptime T: type, s: []T) void {
|
||||
@ -70,6 +109,19 @@ test "crypto.utils.timingSafeEql (vectors)" {
|
||||
testing.expect(timingSafeEql(std.meta.Vector(100, u8), v1, v3));
|
||||
}
|
||||
|
||||
test "crypto.utils.timingSafeCompare" {
|
||||
var a = [_]u8{10} ** 32;
|
||||
var b = [_]u8{10} ** 32;
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .eq);
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .eq);
|
||||
a[31] = 1;
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .lt);
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .lt);
|
||||
a[0] = 20;
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .gt);
|
||||
testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .lt);
|
||||
}
|
||||
|
||||
test "crypto.utils.secureZero" {
|
||||
var a = [_]u8{0xfe} ** 8;
|
||||
var b = [_]u8{0xfe} ** 8;
|
||||
|
Loading…
Reference in New Issue
Block a user