mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-23 16:07:52 +00:00
core/crypto/chacha20: Change API terminology to be consistent with AES
This commit is contained in:
@@ -7,10 +7,10 @@ import "core:mem"
|
||||
|
||||
// KEY_SIZE is the (X)ChaCha20 key size in bytes.
|
||||
KEY_SIZE :: 32
|
||||
// NONCE_SIZE is the ChaCha20 nonce size in bytes.
|
||||
NONCE_SIZE :: 12
|
||||
// XNONCE_SIZE is the XChaCha20 nonce size in bytes.
|
||||
XNONCE_SIZE :: 24
|
||||
// IV_SIZE is the ChaCha20 IV size in bytes.
|
||||
IV_SIZE :: 12
|
||||
// XIV_SIZE is the XChaCha20 IV size in bytes.
|
||||
XIV_SIZE :: 24
|
||||
|
||||
// MAX_CTR_IETF is the maximum counter value for the IETF flavor ChaCha20.
|
||||
MAX_CTR_IETF :: 0xffffffff
|
||||
@@ -40,17 +40,17 @@ Context :: struct {
|
||||
}
|
||||
|
||||
// init inititializes a Context for ChaCha20 with the provided key and
|
||||
// nonce.
|
||||
// iv.
|
||||
//
|
||||
// WARNING: This ONLY handles ChaCha20. XChaCha20 sub-key and nonce
|
||||
// WARNING: This ONLY handles ChaCha20. XChaCha20 sub-key and IV
|
||||
// derivation is expected to be handled by the caller, so that the
|
||||
// HChaCha call can be suitably accelerated.
|
||||
init :: proc "contextless" (ctx: ^Context, key, nonce: []byte, is_xchacha: bool) {
|
||||
if len(key) != KEY_SIZE || len(nonce) != NONCE_SIZE {
|
||||
init :: proc "contextless" (ctx: ^Context, key, iv: []byte, is_xchacha: bool) {
|
||||
if len(key) != KEY_SIZE || len(iv) != IV_SIZE {
|
||||
intrinsics.trap()
|
||||
}
|
||||
|
||||
k, n := key, nonce
|
||||
k, n := key, iv
|
||||
|
||||
ctx._s[0] = SIGMA_0
|
||||
ctx._s[1] = SIGMA_1
|
||||
@@ -99,7 +99,7 @@ reset :: proc(ctx: ^Context) {
|
||||
}
|
||||
|
||||
check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
// Enforce the maximum consumed keystream per IV.
|
||||
//
|
||||
// While all modern "standard" definitions of ChaCha20 use
|
||||
// the IETF 32-bit counter, for XChaCha20 most common
|
||||
@@ -108,7 +108,7 @@ check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) {
|
||||
// Honestly, the answer here is "use a MRAE primitive", but
|
||||
// go with "common" practice in the case of XChaCha20.
|
||||
|
||||
ERR_CTR_EXHAUSTED :: "crypto/chacha20: maximum (X)ChaCha20 keystream per nonce reached"
|
||||
ERR_CTR_EXHAUSTED :: "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached"
|
||||
|
||||
if ctx._is_ietf_flavor {
|
||||
if u64(ctx._s[12]) + u64(nr_blocks) > MAX_CTR_IETF {
|
||||
|
||||
@@ -5,7 +5,7 @@ import "core:encoding/endian"
|
||||
import "core:math/bits"
|
||||
|
||||
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
// Enforce the maximum consumed keystream per IV.
|
||||
_chacha20.check_counter_limit(ctx, nr_blocks)
|
||||
|
||||
dst, src := dst, src
|
||||
@@ -220,7 +220,7 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int)
|
||||
}
|
||||
}
|
||||
|
||||
hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
|
||||
x0, x1, x2, x3 := _chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3
|
||||
x4 := endian.unchecked_get_u32le(key[0:4])
|
||||
x5 := endian.unchecked_get_u32le(key[4:8])
|
||||
@@ -230,10 +230,10 @@ hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
x9 := endian.unchecked_get_u32le(key[20:24])
|
||||
x10 := endian.unchecked_get_u32le(key[24:28])
|
||||
x11 := endian.unchecked_get_u32le(key[28:32])
|
||||
x12 := endian.unchecked_get_u32le(nonce[0:4])
|
||||
x13 := endian.unchecked_get_u32le(nonce[4:8])
|
||||
x14 := endian.unchecked_get_u32le(nonce[8:12])
|
||||
x15 := endian.unchecked_get_u32le(nonce[12:16])
|
||||
x12 := endian.unchecked_get_u32le(iv[0:4])
|
||||
x13 := endian.unchecked_get_u32le(iv[4:8])
|
||||
x14 := endian.unchecked_get_u32le(iv[8:12])
|
||||
x15 := endian.unchecked_get_u32le(iv[12:16])
|
||||
|
||||
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
|
||||
// quarterround(x, 0, 4, 8, 12)
|
||||
|
||||
@@ -227,7 +227,7 @@ is_performant :: proc "contextless" () -> bool {
|
||||
|
||||
@(enable_target_feature = TARGET_SIMD_FEATURES)
|
||||
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
// Enforce the maximum consumed keystream per IV.
|
||||
_chacha20.check_counter_limit(ctx, nr_blocks)
|
||||
|
||||
dst_v := ([^]simd.u32x4)(raw_data(dst))
|
||||
@@ -454,11 +454,11 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int)
|
||||
}
|
||||
|
||||
@(enable_target_feature = TARGET_SIMD_FEATURES)
|
||||
hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
|
||||
v0 := simd.u32x4{_chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3}
|
||||
v1 := intrinsics.unaligned_load((^simd.u32x4)(&key[0]))
|
||||
v2 := intrinsics.unaligned_load((^simd.u32x4)(&key[16]))
|
||||
v3 := intrinsics.unaligned_load((^simd.u32x4)(&nonce[0]))
|
||||
v3 := intrinsics.unaligned_load((^simd.u32x4)(&iv[0]))
|
||||
|
||||
when ODIN_ENDIAN == .Big {
|
||||
v1 = _byteswap_u32x4(v1)
|
||||
|
||||
@@ -198,7 +198,7 @@ _store_simd256_x1 :: #force_inline proc "contextless" (
|
||||
|
||||
@(enable_target_feature = "sse2,ssse3,avx,avx2")
|
||||
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Enforce the maximum consumed keystream per nonce.
|
||||
// Enforce the maximum consumed keystream per IV.
|
||||
_chacha20.check_counter_limit(ctx, nr_blocks)
|
||||
|
||||
dst_v := ([^]simd.u32x8)(raw_data(dst))
|
||||
@@ -311,9 +311,9 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int)
|
||||
}
|
||||
|
||||
@(enable_target_feature = "sse2,ssse3,avx")
|
||||
hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
|
||||
// We can just enable AVX and call the simd128 code as going
|
||||
// wider has 0 performance benefit, but VEX encoded instructions
|
||||
// is nice.
|
||||
#force_inline chacha_simd128.hchacha20(dst, key, nonce)
|
||||
#force_inline chacha_simd128.hchacha20(dst, key, iv)
|
||||
}
|
||||
@@ -12,6 +12,6 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int)
|
||||
panic("crypto/chacha20: simd256 implementation unsupported")
|
||||
}
|
||||
|
||||
hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
|
||||
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
|
||||
intrinsics.trap()
|
||||
}
|
||||
@@ -13,10 +13,10 @@ import "core:mem"
|
||||
|
||||
// KEY_SIZE is the (X)ChaCha20 key size in bytes.
|
||||
KEY_SIZE :: _chacha20.KEY_SIZE
|
||||
// NONCE_SIZE is the ChaCha20 nonce size in bytes.
|
||||
NONCE_SIZE :: _chacha20.NONCE_SIZE
|
||||
// XNONCE_SIZE is the XChaCha20 nonce size in bytes.
|
||||
XNONCE_SIZE :: _chacha20.XNONCE_SIZE
|
||||
// IV_SIZE is the ChaCha20 IV size in bytes.
|
||||
IV_SIZE :: _chacha20.IV_SIZE
|
||||
// XIV_SIZE is the XChaCha20 IV size in bytes.
|
||||
XIV_SIZE :: _chacha20.XIV_SIZE
|
||||
|
||||
// Context is a ChaCha20 or XChaCha20 instance.
|
||||
Context :: struct {
|
||||
@@ -25,27 +25,27 @@ Context :: struct {
|
||||
}
|
||||
|
||||
// init inititializes a Context for ChaCha20 or XChaCha20 with the provided
|
||||
// key and nonce.
|
||||
init :: proc(ctx: ^Context, key, nonce: []byte, impl := Implementation.Simd256) {
|
||||
// key and iv.
|
||||
init :: proc(ctx: ^Context, key, iv: []byte, impl := Implementation.Simd256) {
|
||||
if len(key) != KEY_SIZE {
|
||||
panic("crypto/chacha20: invalid (X)ChaCha20 key size")
|
||||
}
|
||||
if l := len(nonce); l != NONCE_SIZE && l != XNONCE_SIZE {
|
||||
panic("crypto/chacha20: invalid (X)ChaCha20 nonce size")
|
||||
if l := len(iv); l != IV_SIZE && l != XIV_SIZE {
|
||||
panic("crypto/chacha20: invalid (X)ChaCha20 IV size")
|
||||
}
|
||||
|
||||
k, n := key, nonce
|
||||
k, n := key, iv
|
||||
|
||||
init_impl(ctx, impl)
|
||||
|
||||
is_xchacha := len(nonce) == XNONCE_SIZE
|
||||
is_xchacha := len(iv) == XIV_SIZE
|
||||
if is_xchacha {
|
||||
sub_nonce: [NONCE_SIZE]byte
|
||||
sub_iv: [IV_SIZE]byte
|
||||
sub_key := ctx._state._buffer[:KEY_SIZE]
|
||||
hchacha20(sub_key, k, n, ctx._impl)
|
||||
k = sub_key
|
||||
copy(sub_nonce[4:], n[16:])
|
||||
n = sub_nonce[:]
|
||||
copy(sub_iv[4:], n[16:])
|
||||
n = sub_iv[:]
|
||||
}
|
||||
|
||||
_chacha20.init(&ctx._state, k, n, is_xchacha)
|
||||
|
||||
@@ -40,13 +40,13 @@ stream_blocks :: proc(ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
}
|
||||
|
||||
@(private)
|
||||
hchacha20 :: proc "contextless" (dst, key, nonce: []byte, impl: Implementation) {
|
||||
hchacha20 :: proc "contextless" (dst, key, iv: []byte, impl: Implementation) {
|
||||
switch impl {
|
||||
case .Simd256:
|
||||
simd256.hchacha20(dst, key, nonce)
|
||||
simd256.hchacha20(dst, key, iv)
|
||||
case .Simd128:
|
||||
simd128.hchacha20(dst, key, nonce)
|
||||
simd128.hchacha20(dst, key, iv)
|
||||
case .Portable:
|
||||
ref.hchacha20(dst, key, nonce)
|
||||
ref.hchacha20(dst, key, iv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@ import "core:mem"
|
||||
|
||||
// KEY_SIZE is the chacha20poly1305 key size in bytes.
|
||||
KEY_SIZE :: chacha20.KEY_SIZE
|
||||
// NONCE_SIZE is the chacha20poly1305 nonce size in bytes.
|
||||
NONCE_SIZE :: chacha20.NONCE_SIZE
|
||||
// XNONCE_SIZE is the xchacha20poly1305 nonce size in bytes.
|
||||
XNONCE_SIZE :: chacha20.XNONCE_SIZE
|
||||
// IV_SIZE is the chacha20poly1305 IV size in bytes.
|
||||
IV_SIZE :: chacha20.IV_SIZE
|
||||
// XIV_SIZE is the xchacha20poly1305 IV size in bytes.
|
||||
XIV_SIZE :: chacha20.XIV_SIZE
|
||||
// TAG_SIZE is the chacha20poly1305 tag size in bytes.
|
||||
TAG_SIZE :: poly1305.TAG_SIZE
|
||||
|
||||
@@ -28,13 +28,13 @@ TAG_SIZE :: poly1305.TAG_SIZE
|
||||
_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1)
|
||||
|
||||
@(private)
|
||||
_validate_common_slice_sizes :: proc (tag, nonce, aad, text: []byte, is_xchacha: bool) {
|
||||
_validate_common_slice_sizes :: proc (tag, iv, aad, text: []byte, is_xchacha: bool) {
|
||||
if len(tag) != TAG_SIZE {
|
||||
panic("crypto/chacha20poly1305: invalid destination tag size")
|
||||
}
|
||||
expected_nonce_len := is_xchacha ? XNONCE_SIZE : NONCE_SIZE
|
||||
if len(nonce) != expected_nonce_len {
|
||||
panic("crypto/chacha20poly1305: invalid nonce size")
|
||||
expected_iv_len := is_xchacha ? XIV_SIZE : IV_SIZE
|
||||
if len(iv) != expected_iv_len {
|
||||
panic("crypto/chacha20poly1305: invalid IV size")
|
||||
}
|
||||
|
||||
#assert(size_of(int) == 8 || size_of(int) <= 4)
|
||||
@@ -92,21 +92,21 @@ init_xchacha :: proc(ctx: ^Context, key: []byte, impl := chacha20.Implementation
|
||||
}
|
||||
|
||||
// seal encrypts the plaintext and authenticates the aad and ciphertext,
|
||||
// with the provided Context and nonce, stores the output in dst and tag.
|
||||
// with the provided Context and iv, stores the output in dst and tag.
|
||||
//
|
||||
// dst and plaintext MUST alias exactly or not at all.
|
||||
seal :: proc(ctx: ^Context, dst, tag, nonce, aad, plaintext: []byte) {
|
||||
seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) {
|
||||
ciphertext := dst
|
||||
_validate_common_slice_sizes(tag, nonce, aad, plaintext, ctx._is_xchacha)
|
||||
_validate_common_slice_sizes(tag, iv, aad, plaintext, ctx._is_xchacha)
|
||||
if len(ciphertext) != len(plaintext) {
|
||||
panic("crypto/chacha20poly1305: invalid destination ciphertext size")
|
||||
}
|
||||
|
||||
stream_ctx: chacha20.Context = ---
|
||||
chacha20.init(&stream_ctx, ctx._key[:], nonce, ctx._impl)
|
||||
chacha20.init(&stream_ctx, ctx._key[:],iv, ctx._impl)
|
||||
stream_ctx._state._is_ietf_flavor = true
|
||||
|
||||
// otk = poly1305_key_gen(key, nonce)
|
||||
// otk = poly1305_key_gen(key, iv)
|
||||
otk: [poly1305.KEY_SIZE]byte = ---
|
||||
chacha20.keystream_bytes(&stream_ctx, otk[:])
|
||||
mac_ctx: poly1305.Context = ---
|
||||
@@ -123,7 +123,7 @@ seal :: proc(ctx: ^Context, dst, tag, nonce, aad, plaintext: []byte) {
|
||||
poly1305.update(&mac_ctx, aad)
|
||||
_update_mac_pad16(&mac_ctx, aad_len)
|
||||
|
||||
// ciphertext = chacha20_encrypt(key, 1, nonce, plaintext)
|
||||
// ciphertext = chacha20_encrypt(key, 1, iv, plaintext)
|
||||
chacha20.seek(&stream_ctx, 1)
|
||||
chacha20.xor_bytes(&stream_ctx, ciphertext, plaintext)
|
||||
chacha20.reset(&stream_ctx) // Don't need the stream context anymore.
|
||||
@@ -144,14 +144,14 @@ seal :: proc(ctx: ^Context, dst, tag, nonce, aad, plaintext: []byte) {
|
||||
}
|
||||
|
||||
// open authenticates the aad and ciphertext, and decrypts the ciphertext,
|
||||
// with the provided Context, nonce, and tag, and stores the output in dst,
|
||||
// with the provided Context, iv, and tag, and stores the output in dst,
|
||||
// returning true iff the authentication was successful. If authentication
|
||||
// fails, the destination buffer will be zeroed.
|
||||
//
|
||||
// dst and plaintext MUST alias exactly or not at all.
|
||||
open :: proc(ctx: ^Context, dst, nonce, aad, ciphertext, tag: []byte) -> bool {
|
||||
open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool {
|
||||
plaintext := dst
|
||||
_validate_common_slice_sizes(tag, nonce, aad, ciphertext, ctx._is_xchacha)
|
||||
_validate_common_slice_sizes(tag, iv, aad, ciphertext, ctx._is_xchacha)
|
||||
if len(ciphertext) != len(plaintext) {
|
||||
panic("crypto/chacha20poly1305: invalid destination plaintext size")
|
||||
}
|
||||
@@ -161,10 +161,10 @@ open :: proc(ctx: ^Context, dst, nonce, aad, ciphertext, tag: []byte) -> bool {
|
||||
// points where needed.
|
||||
|
||||
stream_ctx: chacha20.Context = ---
|
||||
chacha20.init(&stream_ctx, ctx._key[:], nonce, ctx._impl)
|
||||
chacha20.init(&stream_ctx, ctx._key[:], iv, ctx._impl)
|
||||
stream_ctx._state._is_ietf_flavor = true
|
||||
|
||||
// otk = poly1305_key_gen(key, nonce)
|
||||
// otk = poly1305_key_gen(key, iv)
|
||||
otk: [poly1305.KEY_SIZE]byte = ---
|
||||
chacha20.keystream_bytes(&stream_ctx, otk[:])
|
||||
defer chacha20.reset(&stream_ctx)
|
||||
@@ -199,7 +199,7 @@ open :: proc(ctx: ^Context, dst, nonce, aad, ciphertext, tag: []byte) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// plaintext = chacha20_decrypt(key, 1, nonce, ciphertext)
|
||||
// plaintext = chacha20_decrypt(key, 1, iv, ciphertext)
|
||||
chacha20.seek(&stream_ctx, 1)
|
||||
chacha20.xor_bytes(&stream_ctx, plaintext, ciphertext)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user