feature. See also
. The project being documented here (as the example) is the Zig library itself.
chacha20.ChaChaPoly1305
fn ChaChaPoly1305(comptime rounds_nb: usize) type
File
Code
fn ChaChaPoly1305(comptime rounds_nb: usize) type {
return struct {
pub const tag_length = 16;
pub const nonce_length = 12;
pub const key_length = 32;
pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void {
assert(c.len == m.len);
assert(m.len <= 64 * (@as(u39, 1 << 32) - 1));
var polyKey: [32]u8 = @splat(0);
ChaChaIETF(rounds_nb).xor(polyKey[0..], polyKey[0..], 0, k, npub);
ChaChaIETF(rounds_nb).xor(c[0..m.len], m, 1, k, npub);
var mac = Poly1305.init(polyKey[0..]);
mac.update(ad);
if (ad.len % 16 != 0) {
const zeros: [16]u8 = @splat(0);
const padding = 16 - (ad.len % 16);
mac.update(zeros[0..padding]);
}
mac.update(c[0..m.len]);
if (m.len % 16 != 0) {
const zeros: [16]u8 = @splat(0);
const padding = 16 - (m.len % 16);
mac.update(zeros[0..padding]);
}
var lens: [16]u8 = undefined;
mem.writeInt(u64, lens[0..8], ad.len, .little);
mem.writeInt(u64, lens[8..16], m.len, .little);
mac.update(lens[0..]);
mac.final(tag);
}
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
assert(c.len == m.len);
var polyKey: [32]u8 = @splat(0);
ChaChaIETF(rounds_nb).xor(polyKey[0..], polyKey[0..], 0, k, npub);
var mac = Poly1305.init(polyKey[0..]);
mac.update(ad);
if (ad.len % 16 != 0) {
const zeros: [16]u8 = @splat(0);
const padding = 16 - (ad.len % 16);
mac.update(zeros[0..padding]);
}
mac.update(c);
if (c.len % 16 != 0) {
const zeros: [16]u8 = @splat(0);
const padding = 16 - (c.len % 16);
mac.update(zeros[0..padding]);
}
var lens: [16]u8 = undefined;
mem.writeInt(u64, lens[0..8], ad.len, .little);
mem.writeInt(u64, lens[8..16], c.len, .little);
mac.update(lens[0..]);
var computed_tag: [16]u8 = undefined;
mac.final(computed_tag[0..]);
const verify = crypto.timing_safe.eql([tag_length]u8, computed_tag, tag);
if (!verify) {
crypto.secureZero(u8, &computed_tag);
@memset(m, undefined);
return error.AuthenticationFailed;
}
ChaChaIETF(rounds_nb).xor(m[0..c.len], c, 1, k, npub);
}
};
}