commit 21a3e430c87ebfdb5e12aad01306e85a25fdfb4c
parent fba7b1d030eeedf1b75a26a2f838ace246287142
Author: illiliti <illiliti@dimension.sh>
Date: Sun, 14 Aug 2022 21:17:58 +0300
crypto::chacha20: add hchacha20
Signed-off-by: illiliti <illiliti@dimension.sh>
Diffstat:
2 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/crypto/chacha/+test.ha b/crypto/chacha/+test.ha
@@ -191,3 +191,26 @@ const xcipher: [_]u8 = [
assert(bytes::equal(result[11..], xcipher[128..135]));
};
+// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03#section-2.2.1
+@test fn hchacha20() void = {
+ const key: [_]u8 = [
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f,
+ ];
+ const nonce: [_]u8 = [
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00,
+ 0x00, 0x00, 0x31, 0x41, 0x59, 0x27,
+ ];
+ const expected: [_]u8 = [
+ 0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, 0xd3, 0x0e,
+ 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73, 0xa0, 0xf9, 0xe4, 0xd5,
+ 0x8a, 0x74, 0xa8, 0x53, 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3,
+ 0xec, 0xdc,
+ ];
+
+ let out: [32]u8 = [0...];
+ hchacha20(&out, &key, &nonce);
+ assert(bytes::equal(out, expected));
+};
diff --git a/crypto/chacha/chacha20.ha b/crypto/chacha/chacha20.ha
@@ -80,7 +80,28 @@ export fn xchacha20_init(
key: *[KEYSIZE]u8,
nonce: *[XNONCESIZE]u8
) void = {
+ let dkey: [32]u8 = [0...];
+ // XXX: https://todo.sr.ht/~sircmpwn/hare/719
+ let hnonce: [16]u8 = [0...];
+ hnonce[..] = nonce[..16];
+ hchacha20(&dkey, key, &hnonce);
+
+ let dnonce: [NONCESIZE]u8 = [0...];
+ dnonce[4..] = nonce[16..];
+
+ chacha20_init(s, h, &dkey, &dnonce);
+
+ bytes::zero(dkey);
+ bytes::zero(dnonce);
+ bytes::zero(hnonce);
+};
+
+// Derives a new key from 'key' and 'nonce' as used during XChaCha20
+// initialization. This function may only be used for specific purposes
+// such as X25519 key derivation. Do not use if in doubt.
+export fn hchacha20(out: *[32]u8, key: *[32]u8, nonce: *[16]u8) void = {
let state: [16]u32 = [0...];
+ defer bytes::zero((state: []u8: *[*]u8)[..BLOCKSIZE]);
state[0] = magic[0];
state[1] = magic[1];
@@ -99,20 +120,16 @@ export fn xchacha20_init(
state[14] = endian::legetu32(nonce[8..12]);
state[15] = endian::legetu32(nonce[12..16]);
- hblock(state[..], &state, s.rounds);
-
- let dkey: [32]u8 = [0...];
- dkey[..16] = (state: []u8: *[*]u8)[0..16];
- dkey[16..] = (state: []u8: *[*]u8)[48..64];
-
- let dnonce: [NONCESIZE]u8 = [0...];
- dnonce[4..] = nonce[16..];
-
- chacha20_init(s, h, &dkey, &dnonce);
+ hblock(state[..], &state, 20);
- bytes::zero((state: []u8: *[*]u8)[..BLOCKSIZE]);
- bytes::zero(dkey);
- bytes::zero(dnonce);
+ endian::leputu32(out[0..4], state[0]);
+ endian::leputu32(out[4..8], state[1]);
+ endian::leputu32(out[8..12], state[2]);
+ endian::leputu32(out[12..16], state[3]);
+ endian::leputu32(out[16..20], state[12]);
+ endian::leputu32(out[20..24], state[13]);
+ endian::leputu32(out[24..28], state[14]);
+ endian::leputu32(out[28..32], state[15]);
};
// Advances the key stream to "seek" to a future state by 'counter' times