Add AEAD ciphers support (#775)
* Add AEAD ciphers support, add manger api * fix test_encrypt_all * Add manager api requirements * #775 fix UDP decrypt_all issue * fix udp replay: decrypt_all return a list remove manager api * fix indent according pep8 * remove abc requirement * remove unused import * fix pep8 format * fix test_aes_256_gcm()
This commit is contained in:
@ -21,6 +21,7 @@ from ctypes import c_char_p, c_int, c_ulonglong, byref, c_ulong, \
|
||||
create_string_buffer, c_void_p
|
||||
|
||||
from shadowsocks.crypto import util
|
||||
from shadowsocks.crypto.aead import AeadCryptoBase
|
||||
|
||||
__all__ = ['ciphers']
|
||||
|
||||
@ -59,6 +60,67 @@ def load_libsodium():
|
||||
c_ulong,
|
||||
c_char_p)
|
||||
|
||||
# chacha20-poly1305
|
||||
libsodium.crypto_aead_chacha20poly1305_encrypt.restype = c_int
|
||||
libsodium.crypto_aead_chacha20poly1305_encrypt.argtypes = (
|
||||
c_void_p, c_void_p, # c, clen
|
||||
c_char_p, c_ulonglong, # m, mlen
|
||||
c_char_p, c_ulonglong, # ad, adlen
|
||||
c_char_p, # nsec, not used
|
||||
c_char_p, c_char_p # npub, k
|
||||
)
|
||||
libsodium.crypto_aead_chacha20poly1305_decrypt.restype = c_int
|
||||
libsodium.crypto_aead_chacha20poly1305_decrypt.argtypes = (
|
||||
c_void_p, c_void_p, # m, mlen
|
||||
c_char_p, # nsec, not used
|
||||
c_char_p, c_ulonglong, # c, clen
|
||||
c_char_p, c_ulonglong, # ad, adlen
|
||||
c_char_p, c_char_p # npub, k
|
||||
)
|
||||
|
||||
# chacha20-ietf-poly1305, same api structure as above
|
||||
libsodium.crypto_aead_chacha20poly1305_ietf_encrypt.restype = c_int
|
||||
libsodium.crypto_aead_chacha20poly1305_ietf_encrypt.argtypes = (
|
||||
c_void_p, c_void_p,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p,
|
||||
c_char_p, c_char_p
|
||||
)
|
||||
libsodium.crypto_aead_chacha20poly1305_ietf_decrypt.restype = c_int
|
||||
libsodium.crypto_aead_chacha20poly1305_ietf_decrypt.argtypes = (
|
||||
c_void_p, c_void_p,
|
||||
c_char_p,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_char_p
|
||||
)
|
||||
|
||||
# xchacha20-ietf-poly1305, same api structure as above
|
||||
if hasattr(libsodium, 'crypto_aead_xchacha20poly1305_ietf_encrypt'):
|
||||
libsodium.crypto_aead_xchacha20poly1305_ietf_encrypt.restype = c_int
|
||||
libsodium.crypto_aead_xchacha20poly1305_ietf_encrypt.argtypes = (
|
||||
c_void_p, c_void_p,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p,
|
||||
c_char_p, c_char_p
|
||||
)
|
||||
|
||||
libsodium.crypto_aead_xchacha20poly1305_ietf_decrypt.restype = c_int
|
||||
libsodium.crypto_aead_xchacha20poly1305_ietf_decrypt.argtypes = (
|
||||
c_void_p, c_void_p,
|
||||
c_char_p,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_ulonglong,
|
||||
c_char_p, c_char_p
|
||||
)
|
||||
|
||||
libsodium.sodium_increment.restype = c_void_p
|
||||
libsodium.sodium_increment.argtypes = (
|
||||
c_void_p, c_int
|
||||
)
|
||||
|
||||
buf = create_string_buffer(buf_size)
|
||||
loaded = True
|
||||
|
||||
@ -81,6 +143,10 @@ class SodiumCrypto(object):
|
||||
raise Exception('Unknown cipher')
|
||||
# byte counter, not block counter
|
||||
self.counter = 0
|
||||
self.encrypt = self.update
|
||||
self.decrypt = self.update
|
||||
self.encrypt_once = self.update
|
||||
self.decrypt_once = self.update
|
||||
|
||||
def update(self, data):
|
||||
global buf_size, buf
|
||||
@ -103,10 +169,85 @@ class SodiumCrypto(object):
|
||||
return buf.raw[padding:padding + l]
|
||||
|
||||
|
||||
class SodiumAeadCrypto(AeadCryptoBase):
|
||||
def __init__(self, cipher_name, key, iv, op):
|
||||
if not loaded:
|
||||
load_libsodium()
|
||||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op)
|
||||
|
||||
if cipher_name == 'chacha20-poly1305':
|
||||
self.encryptor = libsodium.crypto_aead_chacha20poly1305_encrypt
|
||||
self.decryptor = libsodium.crypto_aead_chacha20poly1305_decrypt
|
||||
elif cipher_name == 'chacha20-ietf-poly1305':
|
||||
self.encryptor = libsodium.\
|
||||
crypto_aead_chacha20poly1305_ietf_encrypt
|
||||
self.decryptor = libsodium.\
|
||||
crypto_aead_chacha20poly1305_ietf_decrypt
|
||||
elif cipher_name == 'xchacha20-ietf-poly1305':
|
||||
if hasattr(libsodium,
|
||||
'crypto_aead_xchacha20poly1305_ietf_encrypt'):
|
||||
self.encryptor = libsodium.\
|
||||
crypto_aead_xchacha20poly1305_ietf_encrypt
|
||||
self.decryptor = libsodium.\
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt
|
||||
else:
|
||||
raise Exception('Unknown cipher')
|
||||
else:
|
||||
raise Exception('Unknown cipher')
|
||||
|
||||
def cipher_ctx_init(self):
|
||||
|
||||
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen))
|
||||
# print("".join("%02x" % ord(b) for b in self._nonce))
|
||||
|
||||
def aead_encrypt(self, data):
|
||||
global buf, buf_size
|
||||
plen = len(data)
|
||||
if buf_size < plen + self._tlen:
|
||||
buf_size = (plen + self._tlen) * 2
|
||||
buf = create_string_buffer(buf_size)
|
||||
cipher_out_len = c_ulonglong(0)
|
||||
self.encryptor(
|
||||
byref(buf), byref(cipher_out_len),
|
||||
c_char_p(data), c_ulonglong(plen),
|
||||
None, c_ulonglong(0), None,
|
||||
c_char_p(self._nonce.raw), c_char_p(self._skey)
|
||||
)
|
||||
if cipher_out_len.value != plen + self._tlen:
|
||||
raise Exception("Encrypt failed")
|
||||
|
||||
return buf.raw[:cipher_out_len.value]
|
||||
|
||||
def aead_decrypt(self, data):
|
||||
global buf, buf_size
|
||||
clen = len(data)
|
||||
if buf_size < clen:
|
||||
buf_size = clen * 2
|
||||
buf = create_string_buffer(buf_size)
|
||||
cipher_out_len = c_ulonglong(0)
|
||||
r = self.decryptor(
|
||||
byref(buf), byref(cipher_out_len),
|
||||
None,
|
||||
c_char_p(data), c_ulonglong(clen),
|
||||
None, c_ulonglong(0),
|
||||
c_char_p(self._nonce.raw), c_char_p(self._skey)
|
||||
)
|
||||
if r != 0:
|
||||
raise Exception("Decrypt failed")
|
||||
|
||||
if cipher_out_len.value != clen - self._tlen:
|
||||
raise Exception("Encrypt failed")
|
||||
|
||||
return buf.raw[:cipher_out_len.value]
|
||||
|
||||
|
||||
ciphers = {
|
||||
'salsa20': (32, 8, SodiumCrypto),
|
||||
'chacha20': (32, 8, SodiumCrypto),
|
||||
'chacha20-ietf': (32, 12, SodiumCrypto),
|
||||
'chacha20-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
'chacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
'xchacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
}
|
||||
|
||||
|
||||
@ -133,7 +274,31 @@ def test_chacha20_ietf():
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_chacha20_poly1305():
|
||||
|
||||
print("Test chacha20-poly1305")
|
||||
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_chacha20_ietf_poly1305():
|
||||
|
||||
print("Test chacha20-ietf-poly1305")
|
||||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_chacha20()
|
||||
test_salsa20()
|
||||
test_chacha20_ietf()
|
||||
test_chacha20_poly1305()
|
||||
test_chacha20_ietf_poly1305()
|
||||
|
Reference in New Issue
Block a user