hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mcrypto/chacha/+test.ha | 23+++++++++++++++++++++++
Mcrypto/chacha/chacha20.ha | 43++++++++++++++++++++++++++++++-------------
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