hare

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

commit 0d5ea5ca58a34b3b0d9cd6dd60e5387000b4445a
parent 565a111af32cffedb2a62446b9edf24a602614da
Author: illiliti <illiliti@dimension.sh>
Date:   Fri, 16 Jun 2023 05:55:20 +0300

crypto::salsa20: add hsalsa20

Signed-off-by: illiliti <illiliti@dimension.sh>

Diffstat:
Mcrypto/salsa/+test.ha | 24++++++++++++++++++++++++
Mcrypto/salsa/salsa20.ha | 38++++++++++++++++++++++++--------------
2 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/crypto/salsa/+test.ha b/crypto/salsa/+test.ha @@ -176,3 +176,27 @@ use io; io::writeall(&c, msg)!; assert(bytes::equal(cipher, result)); }; + +// taken from naclcrypto-20090310.pdf +@test fn hsalsa20() void = { + const key: [_]u8 = [ + 0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, + 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, + 0xac, 0x64, 0x74, 0xf2, 0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, + 0x83, 0x89, + ]; + const nonce: [_]u8 = [ + 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, + 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6, + ]; + const expected: [_]u8 = [ + 0xdc, 0x90, 0x8d, 0xda, 0x0b, 0x93, 0x44, 0xa9, 0x53, 0x62, + 0x9b, 0x73, 0x38, 0x20, 0x77, 0x88, 0x80, 0xf3, 0xce, 0xb4, + 0x21, 0xbb, 0x61, 0xb9, 0x1c, 0xbd, 0x4c, 0x3e, 0x66, 0x25, + 0x6c, 0xe4, + ]; + + let out: [32]u8 = [0...]; + hsalsa20(&out, &key, &nonce); + assert(bytes::equal(out, expected)); +}; diff --git a/crypto/salsa/salsa20.ha b/crypto/salsa/salsa20.ha @@ -96,24 +96,34 @@ export fn xsalsa20_init( assert(len(key) == KEYSIZE); assert(len(nonce) == XNONCESIZE); + let dkey: [32]u8 = [0...]; + defer bytes::zero(dkey); + hsalsa20(&dkey, key, nonce[..16]); + salsa20_init(s, h, &dkey, nonce[16..]: *[NONCESIZE]u8); +}; + +// Derives a new key from 'key' and 'nonce' as used during XSalsa20 +// initialization. This function may only be used for specific purposes +// such as X25519 key derivation. Do not use if in doubt. +export fn hsalsa20(out: []u8, key: []u8, nonce: []u8) void = { + assert(len(out) == KEYSIZE); + assert(len(key) == KEYSIZE); + assert(len(nonce) == 16); + let state: [16]u32 = [0...]; + defer bytes::zero((state: []u8: *[*]u8)[..BLOCKSIZE]); + init(&state, key, nonce[0..8]: *[8]u8, nonce[8..16]: *[8]u8); hblock(state[..], &state, 20); - let dkey: [32]u8 = [0...]; - endian::leputu32(dkey[0..4], state[0]); - endian::leputu32(dkey[4..8], state[5]); - endian::leputu32(dkey[8..12], state[10]); - endian::leputu32(dkey[12..16], state[15]); - endian::leputu32(dkey[16..20], state[6]); - endian::leputu32(dkey[20..24], state[7]); - endian::leputu32(dkey[24..28], state[8]); - endian::leputu32(dkey[28..], state[9]); - - salsa20_init(s, h, &dkey, nonce[16..]: *[NONCESIZE]u8); - - bytes::zero((state[..]: *[*]u8)[..64]); - bytes::zero(dkey); + endian::leputu32(out[0..4], state[0]); + endian::leputu32(out[4..8], state[5]); + endian::leputu32(out[8..12], state[10]); + endian::leputu32(out[12..16], state[15]); + endian::leputu32(out[16..20], state[6]); + endian::leputu32(out[20..24], state[7]); + endian::leputu32(out[24..28], state[8]); + endian::leputu32(out[28..32], state[9]); }; // Advances the key stream to "seek" to a future state by 'counter' times