mirror of
https://github.com/Legrandin/pycryptodome.git
synced 2025-12-08 05:19:46 +00:00
Support for XChaCha20 and XChaCha20-Poly1305
This commit is contained in:
parent
14528bd87a
commit
c09ed08d76
9 changed files with 271 additions and 67 deletions
|
|
@ -8,6 +8,7 @@ New features
|
|||
------------
|
||||
|
||||
* Add support for loading PEM files encrypted with AES256-CBC.
|
||||
* Add support for XChaCha20 and XChaCha20-Poly1305.
|
||||
|
||||
3.8.2 (30 May 2019)
|
||||
+++++++++++++++++++++++
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ with respect to the last official version of PyCrypto (2.6.1):
|
|||
automatic generation of random nonces and IVs, simplified CTR cipher mode,
|
||||
and more)
|
||||
* SHA-3 (including SHAKE XOFs), truncated SHA-512 and BLAKE2 hash algorithms
|
||||
* Salsa20 and ChaCha20 stream ciphers
|
||||
* Salsa20 and ChaCha20/XChaCha20 stream ciphers
|
||||
* Poly1305 MAC
|
||||
* ChaCha20-Poly1305 authenticated cipher
|
||||
* ChaCha20-Poly1305 and XChaCha20-Poly1305 authenticated ciphers
|
||||
* scrypt and HKDF
|
||||
* Deterministic (EC)DSA
|
||||
* Password-protected PKCS#8 key containers
|
||||
|
|
|
|||
|
|
@ -57,9 +57,28 @@ _raw_chacha20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._chacha20",
|
|||
unsigned long block_high,
|
||||
unsigned long block_low,
|
||||
unsigned offset);
|
||||
int hchacha20( const uint8_t key[32],
|
||||
const uint8_t nonce16[16],
|
||||
uint8_t subkey[32]);
|
||||
""")
|
||||
|
||||
|
||||
def _HChaCha20(key, nonce):
|
||||
|
||||
assert(len(key) == 32)
|
||||
assert(len(nonce) == 16)
|
||||
|
||||
subkey = bytearray(32)
|
||||
result = _raw_chacha20_lib.hchacha20(
|
||||
c_uint8_ptr(key),
|
||||
c_uint8_ptr(nonce),
|
||||
c_uint8_ptr(subkey))
|
||||
if result:
|
||||
raise ValueError("Error %d when deriving subkey with HChaCha20" % result)
|
||||
|
||||
return subkey
|
||||
|
||||
|
||||
class ChaCha20Cipher(object):
|
||||
"""ChaCha20 cipher object. Do not create it directly. Use :py:func:`new` instead.
|
||||
|
||||
|
|
@ -70,13 +89,23 @@ class ChaCha20Cipher(object):
|
|||
block_size = 1
|
||||
|
||||
def __init__(self, key, nonce):
|
||||
"""Initialize a ChaCha20 cipher object
|
||||
"""Initialize a ChaCha20/XChaCha20 cipher object
|
||||
|
||||
See also `new()` at the module level."""
|
||||
|
||||
# XChaCha20 requires a key derivation with HChaCha20
|
||||
# See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03
|
||||
if len(nonce) == 24:
|
||||
key = _HChaCha20(key, nonce[:16])
|
||||
nonce = b'\x00' * 4 + nonce[16:]
|
||||
self._name = "XChaCha20"
|
||||
else:
|
||||
self._name = "ChaCha20"
|
||||
|
||||
self.nonce = _copy_bytes(None, None, nonce)
|
||||
|
||||
self._next = ( self.encrypt, self.decrypt )
|
||||
|
||||
self._state = VoidPointer()
|
||||
result = _raw_chacha20_lib.chacha20_init(
|
||||
self._state.address_of(),
|
||||
|
|
@ -85,7 +114,8 @@ class ChaCha20Cipher(object):
|
|||
self.nonce,
|
||||
c_size_t(len(nonce)))
|
||||
if result:
|
||||
raise ValueError("Error %d instantiating a ChaCha20 cipher")
|
||||
raise ValueError("Error %d instantiating a %s cipher" % (result,
|
||||
self._name))
|
||||
self._state = SmartPointer(self._state.get(),
|
||||
_raw_chacha20_lib.chacha20_destroy)
|
||||
|
||||
|
|
@ -128,7 +158,7 @@ class ChaCha20Cipher(object):
|
|||
c_uint8_ptr(ciphertext),
|
||||
c_size_t(len(plaintext)))
|
||||
if result:
|
||||
raise ValueError("Error %d while encrypting with ChaCha20" % result)
|
||||
raise ValueError("Error %d while encrypting with %s" % (result, self._name))
|
||||
|
||||
if output is None:
|
||||
return get_raw_buffer(ciphertext)
|
||||
|
|
@ -176,7 +206,7 @@ class ChaCha20Cipher(object):
|
|||
offset
|
||||
)
|
||||
if result:
|
||||
raise ValueError("Error %d while seeking with ChaCha20" % result)
|
||||
raise ValueError("Error %d while seeking with %s" % (result, self._name))
|
||||
|
||||
|
||||
def _derive_Poly1305_key_pair(key, nonce):
|
||||
|
|
@ -209,14 +239,16 @@ def _derive_Poly1305_key_pair(key, nonce):
|
|||
|
||||
|
||||
def new(**kwargs):
|
||||
"""Create a new ChaCha20 cipher
|
||||
"""Create a new ChaCha20 or XChaCha20 cipher
|
||||
|
||||
Keyword Args:
|
||||
key (bytes/bytearray/memoryview): The secret key to use.
|
||||
It must be 32 bytes long.
|
||||
nonce (bytes/bytearray/memoryview): A mandatory value that
|
||||
must never be reused for any other encryption
|
||||
done with this key. It must be 8 or 12 bytes long.
|
||||
done with this key.
|
||||
For ChaCha20, it must be 8 or 12 bytes long.
|
||||
For XChaCha20, it must be 24 bytes long.
|
||||
|
||||
If not provided, 8 bytes will be randomly generated
|
||||
(you can find them back in the ``nonce`` attribute).
|
||||
|
|
@ -234,9 +266,10 @@ def new(**kwargs):
|
|||
nonce = get_random_bytes(8)
|
||||
|
||||
if len(key) != 32:
|
||||
raise ValueError("ChaCha20 key must be 32 bytes long")
|
||||
if len(nonce) not in (8, 12):
|
||||
raise ValueError("ChaCha20 nonce must be 8 or 12 bytes long")
|
||||
raise ValueError("ChaCha20/XChaCha20 key must be 32 bytes long")
|
||||
|
||||
if len(nonce) not in (8, 12, 24):
|
||||
raise ValueError("Nonce must be 8/12 bytes(ChaCha20) or 24 bytes (XChaCha20)")
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unknown parameters: " + str(kwargs))
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ from typing import Union, overload
|
|||
|
||||
Buffer = Union[bytes, bytearray, memoryview]
|
||||
|
||||
def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ...
|
||||
|
||||
class ChaCha20Cipher:
|
||||
block_size: int
|
||||
nonce: bytes
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
from binascii import unhexlify
|
||||
|
||||
from Crypto.Cipher import ChaCha20
|
||||
from Crypto.Cipher.ChaCha20 import _HChaCha20
|
||||
from Crypto.Hash import Poly1305, BLAKE2s
|
||||
|
||||
from Crypto.Random import get_random_bytes
|
||||
|
|
@ -280,14 +281,17 @@ class ChaCha20Poly1305Cipher(object):
|
|||
|
||||
|
||||
def new(**kwargs):
|
||||
"""Create a new ChaCha20-Poly1305 AEAD cipher.
|
||||
"""Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher.
|
||||
|
||||
:keyword key: The secret key to use. It must be 32 bytes long.
|
||||
:type key: byte string
|
||||
|
||||
:keyword nonce:
|
||||
A value that must never be reused for any other encryption
|
||||
done with this key. It must be 8 or 12 bytes long.
|
||||
done with this key.
|
||||
|
||||
For ChaCha20-Poly1305, it must be 8 or 12 bytes long.
|
||||
For XChaCha20-Poly1305, it must be 24 bytes long.
|
||||
|
||||
If not provided, 12 ``bytes`` will be generated randomly
|
||||
(you can find them back in the ``nonce`` attribute).
|
||||
|
|
@ -310,8 +314,13 @@ def new(**kwargs):
|
|||
if nonce is None:
|
||||
nonce = get_random_bytes(12)
|
||||
|
||||
if len(nonce) not in (8, 12):
|
||||
raise ValueError("Nonce must be 8 or 12 bytes long")
|
||||
if len(nonce) in (8, 12):
|
||||
pass
|
||||
elif len(nonce) == 24:
|
||||
key = _HChaCha20(key, nonce[:16])
|
||||
nonce = b'\x00\x00\x00\x00' + nonce[16:]
|
||||
else:
|
||||
raise ValueError("Nonce must be 8, 12 or 24 bytes long")
|
||||
|
||||
if not is_buffer(nonce):
|
||||
raise TypeError("nonce must be bytes, bytearray or memoryview")
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class Poly1305_MAC(object):
|
|||
def __init__(self, r, s, data):
|
||||
|
||||
if len(r) != 16:
|
||||
raise ValueError("Paramater r is not 16 bytes long")
|
||||
raise ValueError("Parameter r is not 16 bytes long")
|
||||
if len(s) != 16:
|
||||
raise ValueError("Parameter s is not 16 bytes long")
|
||||
|
||||
|
|
|
|||
|
|
@ -243,6 +243,66 @@ class ChaCha20Test(unittest.TestCase):
|
|||
assert(ct == ct_expect)
|
||||
|
||||
|
||||
class XChaCha20Test(unittest.TestCase):
|
||||
|
||||
# From https://tools.ietf.org/html/draft-arciszewski-xchacha-03
|
||||
|
||||
def test_hchacha20(self):
|
||||
# Section 2.2.1
|
||||
|
||||
from Crypto.Cipher.ChaCha20 import _HChaCha20
|
||||
|
||||
key = b"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f"
|
||||
key = unhexlify(key.replace(b":", b""))
|
||||
|
||||
nonce = b"00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27"
|
||||
nonce = unhexlify(nonce.replace(b":", b""))
|
||||
|
||||
subkey = _HChaCha20(key, nonce)
|
||||
|
||||
expected = b"82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc"
|
||||
expected = unhexlify(expected.replace(b" ", b""))
|
||||
|
||||
self.assertEqual(subkey, expected)
|
||||
|
||||
def test_encrypt(self):
|
||||
# Section A.3.2
|
||||
|
||||
pt = b"""
|
||||
5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973
|
||||
20616c736f206b6e6f776e2061732074686520417369617469632077696c6420
|
||||
646f672c2072656420646f672c20616e642077686973746c696e6720646f672e
|
||||
2049742069732061626f7574207468652073697a65206f662061204765726d61
|
||||
6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061
|
||||
206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c
|
||||
757369766520616e6420736b696c6c6564206a756d70657220697320636c6173
|
||||
736966696564207769746820776f6c7665732c20636f796f7465732c206a6163
|
||||
6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963
|
||||
2066616d696c792043616e696461652e"""
|
||||
pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b""))
|
||||
|
||||
key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f")
|
||||
iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555658")
|
||||
|
||||
ct = b"""
|
||||
7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87
|
||||
ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05
|
||||
3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f
|
||||
7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201
|
||||
12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc
|
||||
047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63
|
||||
d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73
|
||||
c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4
|
||||
d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683
|
||||
8a9c71f70b5b5907a66f7ea49aadc409"""
|
||||
ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b""))
|
||||
|
||||
cipher = ChaCha20.new(key=key, nonce=iv)
|
||||
cipher.seek(64) # Counter = 1
|
||||
ct_test = cipher.encrypt(pt)
|
||||
self.assertEqual(ct, ct_test)
|
||||
|
||||
|
||||
class ByteArrayTest(unittest.TestCase):
|
||||
"""Verify we can encrypt or decrypt bytearrays"""
|
||||
|
||||
|
|
@ -439,6 +499,7 @@ class TestOutput(unittest.TestCase):
|
|||
def get_tests(config={}):
|
||||
tests = []
|
||||
tests += list_test_cases(ChaCha20Test)
|
||||
tests += list_test_cases(XChaCha20Test)
|
||||
tests.append(ChaCha20_AGL_NIR())
|
||||
tests.append(ByteArrayTest())
|
||||
|
||||
|
|
|
|||
|
|
@ -328,6 +328,44 @@ class ChaCha20Poly1305Tests(unittest.TestCase):
|
|||
del test_memoryview
|
||||
|
||||
|
||||
class XChaCha20Poly1305Tests(unittest.TestCase):
|
||||
|
||||
def test_encrypt(self):
|
||||
# From https://tools.ietf.org/html/draft-arciszewski-xchacha-03
|
||||
# Section A.3.1
|
||||
|
||||
pt = b"""
|
||||
4c616469657320616e642047656e746c656d656e206f662074686520636c6173
|
||||
73206f66202739393a204966204920636f756c64206f6666657220796f75206f
|
||||
6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73
|
||||
637265656e20776f756c642062652069742e"""
|
||||
pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b""))
|
||||
|
||||
aad = unhexlify(b"50515253c0c1c2c3c4c5c6c7")
|
||||
key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f")
|
||||
iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555657")
|
||||
|
||||
ct = b"""
|
||||
bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb
|
||||
731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452
|
||||
2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9
|
||||
21f9664c97637da9768812f615c68b13b52e"""
|
||||
ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b""))
|
||||
|
||||
tag = unhexlify(b"c0875924c1c7987947deafd8780acf49")
|
||||
|
||||
cipher = ChaCha20_Poly1305.new(key=key, nonce=iv)
|
||||
cipher.update(aad)
|
||||
ct_test, tag_test = cipher.encrypt_and_digest(pt)
|
||||
|
||||
self.assertEqual(ct, ct_test)
|
||||
self.assertEqual(tag, tag_test)
|
||||
|
||||
cipher = ChaCha20_Poly1305.new(key=key, nonce=iv)
|
||||
cipher.update(aad)
|
||||
cipher.decrypt_and_verify(ct, tag)
|
||||
|
||||
|
||||
class ChaCha20Poly1305FSMTests(unittest.TestCase):
|
||||
|
||||
key_256 = get_tag_random("key_256", 32)
|
||||
|
|
@ -726,6 +764,7 @@ def get_tests(config={}):
|
|||
|
||||
tests = []
|
||||
tests += list_test_cases(ChaCha20Poly1305Tests)
|
||||
tests += list_test_cases(XChaCha20Poly1305Tests)
|
||||
tests += list_test_cases(ChaCha20Poly1305FSMTests)
|
||||
tests += [TestVectorsRFC()]
|
||||
tests += [TestVectorsWycheproof(wycheproof_warnings)]
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ EXPORT_SYM int chacha20_init(stream_state **pState,
|
|||
if (NULL == key || keySize != KEY_SIZE)
|
||||
return ERR_KEY_SIZE;
|
||||
|
||||
if (nonceSize != 8 && nonceSize != 12)
|
||||
if (nonceSize != 8 && nonceSize != 12 && nonceSize != 16)
|
||||
return ERR_NONCE_SIZE;
|
||||
|
||||
*pState = hs = (stream_state*) calloc(1, sizeof(stream_state));
|
||||
|
|
@ -89,15 +89,30 @@ EXPORT_SYM int chacha20_init(stream_state **pState,
|
|||
for (i=0; i<32/4; i++) {
|
||||
hs->h[4+i] = LOAD_U32_LITTLE(key + 4*i);
|
||||
}
|
||||
|
||||
|
||||
switch (nonceSize) {
|
||||
case 8: {
|
||||
/** h[12] remains 0 (offset) **/
|
||||
if (nonceSize == 8) {
|
||||
/** h[13] remains 0 (offset) **/
|
||||
hs->h[14] = LOAD_U32_LITTLE(nonce + 0);
|
||||
hs->h[15] = LOAD_U32_LITTLE(nonce + 4);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
/** h[12] remains 0 (offset) **/
|
||||
hs->h[13] = LOAD_U32_LITTLE(nonce + 0);
|
||||
hs->h[14] = LOAD_U32_LITTLE(nonce + 4);
|
||||
hs->h[15] = LOAD_U32_LITTLE(nonce + 8);
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
hs->h[12] = LOAD_U32_LITTLE(nonce + 0);
|
||||
hs->h[13] = LOAD_U32_LITTLE(nonce + 4);
|
||||
hs->h[14] = LOAD_U32_LITTLE(nonce + 8);
|
||||
hs->h[15] = LOAD_U32_LITTLE(nonce + 12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hs->nonceSize = nonceSize;
|
||||
|
|
@ -114,12 +129,11 @@ EXPORT_SYM int chacha20_destroy(stream_state *state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chacha20_core(stream_state *state)
|
||||
static int chacha20_core(stream_state *state, uint32_t h[16])
|
||||
{
|
||||
unsigned i;
|
||||
uint32_t h[16];
|
||||
|
||||
memcpy(h, state->h, sizeof h);
|
||||
memcpy(h, state->h, sizeof state->h);
|
||||
|
||||
for (i=0; i<10; i++) {
|
||||
/** Column round **/
|
||||
|
|
@ -134,27 +148,36 @@ static int chacha20_core(stream_state *state)
|
|||
QR(h[3], h[4], h[ 9], h[14]);
|
||||
}
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
h[i] += state->h[i];
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
STORE_U32_LITTLE(state->keyStream + 4*i, h[i]);
|
||||
uint32_t sum;
|
||||
|
||||
sum = h[i] + state->h[i];
|
||||
STORE_U32_LITTLE(state->keyStream + 4*i, sum);
|
||||
}
|
||||
|
||||
state->usedKeyStream = 0;
|
||||
|
||||
if (state->nonceSize == 8) {
|
||||
switch (state->nonceSize) {
|
||||
case 8: {
|
||||
/** Nonce is 64 bits, counter is two words **/
|
||||
if (++state->h[12] == 0) {
|
||||
if (++state->h[13] == 0) {
|
||||
return ERR_MAX_DATA;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
/** Nonce is 96 bits, counter is one word **/
|
||||
if (++state->h[12] == 0) {
|
||||
return ERR_MAX_DATA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
/** Nonce is 128 bits, there is no counter (HChaCha20) **/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -171,11 +194,12 @@ EXPORT_SYM int chacha20_encrypt(stream_state *state,
|
|||
while (len>0) {
|
||||
unsigned keyStreamToUse;
|
||||
unsigned i;
|
||||
uint32_t h[16];
|
||||
|
||||
if (state->usedKeyStream == sizeof state->keyStream) {
|
||||
int result;
|
||||
|
||||
result = chacha20_core(state);
|
||||
result = chacha20_core(state, h);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
|
@ -197,6 +221,7 @@ EXPORT_SYM int chacha20_seek(stream_state *state,
|
|||
unsigned offset)
|
||||
{
|
||||
int result;
|
||||
uint32_t h[16];
|
||||
|
||||
if (NULL == state)
|
||||
return ERR_NULL;
|
||||
|
|
@ -216,14 +241,48 @@ EXPORT_SYM int chacha20_seek(stream_state *state,
|
|||
state->h[12] = (uint32_t)block_low;
|
||||
}
|
||||
|
||||
result = chacha20_core(state);
|
||||
result = chacha20_core(state, h);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
state->usedKeyStream = offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on https://tools.ietf.org/html/draft-arciszewski-xchacha-03
|
||||
*/
|
||||
EXPORT_SYM int hchacha20(const uint8_t key[KEY_SIZE],
|
||||
const uint8_t nonce16[16], /* First 16 bytes of the 24 byte nonce */
|
||||
uint8_t subkey[KEY_SIZE])
|
||||
{
|
||||
stream_state *pState;
|
||||
uint32_t h[16];
|
||||
|
||||
if (NULL == key || NULL == nonce16 || NULL == subkey) {
|
||||
return ERR_NULL;
|
||||
}
|
||||
|
||||
chacha20_init(&pState, key, KEY_SIZE, nonce16, 16);
|
||||
if (NULL == pState)
|
||||
return ERR_MEMORY;
|
||||
|
||||
chacha20_core(pState, h);
|
||||
/* We only keep first and last row from the new state */
|
||||
STORE_U32_LITTLE(subkey + 0, h[0]);
|
||||
STORE_U32_LITTLE(subkey + 4, h[1]);
|
||||
STORE_U32_LITTLE(subkey + 8, h[2]);
|
||||
STORE_U32_LITTLE(subkey + 12, h[3]);
|
||||
STORE_U32_LITTLE(subkey + 16, h[12]);
|
||||
STORE_U32_LITTLE(subkey + 20, h[13]);
|
||||
STORE_U32_LITTLE(subkey + 24, h[14]);
|
||||
STORE_U32_LITTLE(subkey + 28, h[15]);
|
||||
chacha20_destroy(pState);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PROFILE
|
||||
int main(void)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue