diff --git a/README.md b/README.md index a32d996..684b920 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ crypto_sign_sk_to_seed(sk) crypto_sign_verify_detached(sig, msg, pk) crypto_stream_chacha20_xor(message, nonce, key) crypto_stream_chacha20_xor_ic(message, nonce, initial_counter, key) +crypto_stream_xchacha20_xor(message, nonce, key) +crypto_stream_xchacha20_xor_ic(message, nonce, initial_counter, key) crypto_stream(cnt, nonce=None, key=None) crypto_stream_xor(msg, cnt, nonce=None, key=None) randombytes(size) @@ -215,6 +217,8 @@ crypto_stream_KEYBYTES crypto_stream_NONCEBYTES crypto_stream_chacha20_NONCEBYTES crypto_stream_chacha20_KEYBYTES +crypto_stream_xchacha20_NONCEBYTES +crypto_stream_xchacha20_KEYBYTES crypto_core_ristretto255_BYTES crypto_core_ristretto255_HASHBYTES crypto_core_ristretto255_SCALARBYTES diff --git a/pysodium/__init__.py b/pysodium/__init__.py index 89c7eed..605347b 100755 --- a/pysodium/__init__.py +++ b/pysodium/__init__.py @@ -120,6 +120,8 @@ def wrapper(*args, **kwargs): crypto_stream_NONCEBYTES = sodium.crypto_stream_noncebytes() crypto_stream_chacha20_NONCEBYTES = sodium.crypto_stream_chacha20_noncebytes() crypto_stream_chacha20_KEYBYTES = sodium.crypto_stream_chacha20_keybytes() +crypto_stream_xchacha20_NONCEBYTES = sodium.crypto_stream_xchacha20_noncebytes() +crypto_stream_xchacha20_KEYBYTES = sodium.crypto_stream_xchacha20_keybytes() crypto_generichash_KEYBYTES_MAX = sodium.crypto_generichash_keybytes_max() crypto_generichash_BYTES = sodium.crypto_generichash_bytes() crypto_generichash_BYTES_MIN = sodium.crypto_generichash_bytes_min() @@ -335,6 +337,33 @@ def crypto_stream_chacha20_xor_ic(message, nonce, initial_counter, key): return c.raw +# crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *k) +def crypto_stream_xchacha20_xor(message, nonce, key): + if len(nonce) != crypto_stream_xchacha20_NONCEBYTES: raise ValueError("truncated nonce") + if len(key) != crypto_stream_xchacha20_KEYBYTES: raise ValueError("truncated key") + + mlen = ctypes.c_longlong(len(message)) + + c = ctypes.create_string_buffer(len(message)) + + __check(sodium.crypto_stream_xchacha20_xor(c, message, mlen, nonce, key)) + + return c.raw + +# crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, unsigned long long mlen, const unsigned char *n, uint64_t ic, const unsigned char *k) +def crypto_stream_xchacha20_xor_ic(message, nonce, initial_counter, key): + if len(nonce) != crypto_stream_xchacha20_NONCEBYTES: raise ValueError("truncated nonce") + if len(key) != crypto_stream_xchacha20_KEYBYTES: raise ValueError("truncated key") + + mlen = ctypes.c_longlong(len(message)) + ic = ctypes.c_uint64(initial_counter) + + c = ctypes.create_string_buffer(len(message)) + + __check(sodium.crypto_stream_xchacha20_xor_ic(c, message, mlen, nonce, ic, key)) + + return c.raw + # crypto_aead_chacha20poly1305_encrypt(unsigned char *c, unsigned long long *clen, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k); def crypto_aead_chacha20poly1305_encrypt(message, ad, nonce, key): if len(nonce) != crypto_aead_chacha20poly1305_NONCEBYTES: raise ValueError("truncated nonce") diff --git a/test/test_pysodium.py b/test/test_pysodium.py index a7fdcad..22752d7 100755 --- a/test/test_pysodium.py +++ b/test/test_pysodium.py @@ -381,6 +381,22 @@ def test_crypto_stream_chacha20_xor_ic(self): output = pysodium.crypto_stream_chacha20_xor_ic(input_, nonce, ic, key) self.assertEqual(binascii.unhexlify(b"9db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9"), output) + def test_crypto_stream_xchacha20_xor(self): + # test vectors taken from: + # https://github.com/jedisct1/libsodium/blob/609e42be75589f91179d218e24f5e35a7124abfd/test/default/xchacha20.c#L102 + key = binascii.unhexlify("9d23bd4149cb979ccf3c5c94dd217e9808cb0e50cd0f67812235eaaf601d6232") + nonce = binascii.unhexlify("c047548266b7c370d33566a2425cbf30d82d1eaf5294109e") + out = binascii.unhexlify("a21209096594de8c5667b1d13ad93f744106d054df210e4782cd396fec692d3515a20bf351eec011a92c367888bc464c32f0807acd6c203a247e0db854148468e9f96bee4cf718d68d5f637cbd5a376457788e6fae90fc31097cfc") + output = pysodium.crypto_stream_xchacha20_xor(out, nonce, key) + self.assertEqual(b'\x00'*len(output), output) + + def test_crypto_stream_xchacha20_xor_ic(self): + key = binascii.unhexlify("9d23bd4149cb979ccf3c5c94dd217e9808cb0e50cd0f67812235eaaf601d6232") + nonce = binascii.unhexlify("c047548266b7c370d33566a2425cbf30d82d1eaf5294109e") + out = binascii.unhexlify("a21209096594de8c5667b1d13ad93f744106d054df210e4782cd396fec692d3515a20bf351eec011a92c367888bc464c32f0807acd6c203a247e0db854148468e9f96bee4cf718d68d5f637cbd5a376457788e6fae90fc31097cfc") + output = pysodium.crypto_stream_xchacha20_xor_ic(out, nonce, 0, key) + self.assertEqual(b'\x00'*len(output), output) + def test_crypto_blake2b(self): message = binascii.unhexlify(b'54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67') key = binascii.unhexlify(b'000102030405060708090a0b0c0d0e0f')