Add sodium:aes-256-gcm and openssl:ocb AEAD mode (#784)
* Add sodium:aes-256-gcm and openssl:ocb AEAD mode Use sodium_increment for nonce_increment if avaiable * Fix pep8 * Fix python3 test code
This commit is contained in:
parent
d6b40efa5d
commit
74f8f8cb85
5 changed files with 295 additions and 90 deletions
|
@ -14,11 +14,12 @@
|
|||
from __future__ import absolute_import, division, print_function, \
|
||||
with_statement
|
||||
|
||||
from ctypes import create_string_buffer
|
||||
from ctypes import c_int, create_string_buffer, byref, c_void_p
|
||||
|
||||
import hashlib
|
||||
from struct import pack, unpack
|
||||
|
||||
from shadowsocks.crypto import util
|
||||
from shadowsocks.crypto import hkdf
|
||||
from shadowsocks.common import ord, chr
|
||||
|
||||
|
@ -42,22 +43,58 @@ CIPHER_NONCE_LEN = {
|
|||
'aes-128-gcm': 12,
|
||||
'aes-192-gcm': 12,
|
||||
'aes-256-gcm': 12,
|
||||
'aes-128-ocb': 12, # requires openssl 1.1
|
||||
'aes-192-ocb': 12,
|
||||
'aes-256-ocb': 12,
|
||||
'chacha20-poly1305': 12,
|
||||
'chacha20-ietf-poly1305': 12,
|
||||
'xchacha20-ietf-poly1305': 24,
|
||||
'sodium:aes-256-gcm': 12,
|
||||
}
|
||||
|
||||
CIPHER_TAG_LEN = {
|
||||
'aes-128-gcm': 16,
|
||||
'aes-192-gcm': 16,
|
||||
'aes-256-gcm': 16,
|
||||
'aes-128-ocb': 16, # requires openssl 1.1
|
||||
'aes-192-ocb': 16,
|
||||
'aes-256-ocb': 16,
|
||||
'chacha20-poly1305': 16,
|
||||
'chacha20-ietf-poly1305': 16,
|
||||
'xchacha20-ietf-poly1305': 16,
|
||||
'sodium:aes-256-gcm': 16,
|
||||
}
|
||||
|
||||
SUBKEY_INFO = b"ss-subkey"
|
||||
|
||||
libsodium = None
|
||||
sodium_loaded = False
|
||||
|
||||
|
||||
def load_sodium():
|
||||
"""
|
||||
Load libsodium helpers for nonce increment
|
||||
:return: None
|
||||
"""
|
||||
global libsodium, sodium_loaded
|
||||
|
||||
libsodium = util.find_library('sodium', 'sodium_increment',
|
||||
'libsodium')
|
||||
if libsodium is None:
|
||||
return
|
||||
|
||||
if libsodium.sodium_init() < 0:
|
||||
libsodium = None
|
||||
return
|
||||
|
||||
libsodium.sodium_increment.restype = c_void_p
|
||||
libsodium.sodium_increment.argtypes = (
|
||||
c_void_p, c_int
|
||||
)
|
||||
|
||||
sodium_loaded = True
|
||||
return
|
||||
|
||||
|
||||
def nonce_increment(nonce, nlen):
|
||||
"""
|
||||
|
@ -119,12 +156,28 @@ class AeadCryptoBase(object):
|
|||
self.encrypt_once = self.aead_encrypt
|
||||
self.decrypt_once = self.aead_decrypt
|
||||
|
||||
# load libsodium for nonce increment
|
||||
if not sodium_loaded:
|
||||
load_sodium()
|
||||
|
||||
def nonce_increment(self):
|
||||
"""
|
||||
AEAD ciphers need nonce to be unique per key
|
||||
TODO: cache and check unique
|
||||
:return: None
|
||||
"""
|
||||
global libsodium, sodium_loaded
|
||||
if sodium_loaded:
|
||||
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen))
|
||||
else:
|
||||
nonce_increment(self._nonce, self._nlen)
|
||||
|
||||
def cipher_ctx_init(self):
|
||||
"""
|
||||
Increase nonce to make it unique for the same key
|
||||
:return: void
|
||||
:return: None
|
||||
"""
|
||||
nonce_increment(self._nonce, self._nlen)
|
||||
self.nonce_increment()
|
||||
# print("".join("%02x" % ord(b) for b in self._nonce))
|
||||
|
||||
def aead_encrypt(self, data):
|
||||
|
@ -132,7 +185,7 @@ class AeadCryptoBase(object):
|
|||
Encrypt data with authenticate tag
|
||||
|
||||
:param data: plain text
|
||||
:return: cipher text with tag
|
||||
:return: str [payload][tag] cipher text with tag
|
||||
"""
|
||||
raise Exception("Must implement aead_encrypt method")
|
||||
|
||||
|
@ -141,23 +194,21 @@ class AeadCryptoBase(object):
|
|||
Encrypt a chunk for TCP chunks
|
||||
|
||||
:param data: str
|
||||
:return: (str, int)
|
||||
:return: str [len][tag][payload][tag]
|
||||
"""
|
||||
plen = len(data)
|
||||
l = AEAD_CHUNK_SIZE_LEN + plen + self._tlen * 2
|
||||
# l = AEAD_CHUNK_SIZE_LEN + plen + self._tlen * 2
|
||||
|
||||
# network byte order
|
||||
ctext = self.aead_encrypt(pack("!H", plen & AEAD_CHUNK_SIZE_MASK))
|
||||
if len(ctext) != AEAD_CHUNK_SIZE_LEN + self._tlen:
|
||||
ctext = [self.aead_encrypt(pack("!H", plen & AEAD_CHUNK_SIZE_MASK))]
|
||||
if len(ctext[0]) != AEAD_CHUNK_SIZE_LEN + self._tlen:
|
||||
raise Exception("size length invalid")
|
||||
|
||||
ctext.append(self.aead_encrypt(data))
|
||||
if len(ctext[1]) != plen + self._tlen:
|
||||
raise Exception("data length invalid")
|
||||
|
||||
self.cipher_ctx_init()
|
||||
ctext += self.aead_encrypt(data)
|
||||
if len(ctext) != l:
|
||||
raise Exception("data length invalid")
|
||||
|
||||
self.cipher_ctx_init()
|
||||
return ctext, l
|
||||
return b''.join(ctext)
|
||||
|
||||
def encrypt(self, data):
|
||||
"""
|
||||
|
@ -169,25 +220,24 @@ class AeadCryptoBase(object):
|
|||
"""
|
||||
plen = len(data)
|
||||
if plen <= AEAD_CHUNK_SIZE_MASK:
|
||||
ctext, _ = self.encrypt_chunk(data)
|
||||
ctext = self.encrypt_chunk(data)
|
||||
return ctext
|
||||
ctext, clen = b"", 0
|
||||
ctext = []
|
||||
while plen > 0:
|
||||
mlen = plen if plen < AEAD_CHUNK_SIZE_MASK \
|
||||
else AEAD_CHUNK_SIZE_MASK
|
||||
r, l = self.encrypt_chunk(data[:mlen])
|
||||
ctext += r
|
||||
clen += l
|
||||
c = self.encrypt_chunk(data[:mlen])
|
||||
ctext.append(c)
|
||||
data = data[mlen:]
|
||||
plen -= mlen
|
||||
|
||||
return ctext
|
||||
return b''.join(ctext)
|
||||
|
||||
def aead_decrypt(self, data):
|
||||
"""
|
||||
Decrypt data and authenticate tag
|
||||
|
||||
:param data: str cipher text with tag
|
||||
:param data: str [len][tag][payload][tag] cipher text with tag
|
||||
:return: str plain text
|
||||
"""
|
||||
raise Exception("Must implement aead_decrypt method")
|
||||
|
@ -196,7 +246,7 @@ class AeadCryptoBase(object):
|
|||
"""
|
||||
Decrypt chunk size
|
||||
|
||||
:param data: str encrypted msg
|
||||
:param data: str [size][tag] encrypted chunk payload len
|
||||
:return: (int, str) msg length and remaining encrypted data
|
||||
"""
|
||||
if self._chunk['mlen'] > 0:
|
||||
|
@ -213,7 +263,6 @@ class AeadCryptoBase(object):
|
|||
if plen & AEAD_CHUNK_SIZE_MASK != plen or plen <= 0:
|
||||
raise Exception('Invalid message length')
|
||||
|
||||
self.cipher_ctx_init()
|
||||
return plen, data[hlen:]
|
||||
|
||||
def decrypt_chunk_payload(self, plen, data):
|
||||
|
@ -221,7 +270,7 @@ class AeadCryptoBase(object):
|
|||
Decrypted encrypted msg payload
|
||||
|
||||
:param plen: int payload length
|
||||
:param data: str encrypted data
|
||||
:param data: str [payload][tag][[len][tag]....] encrypted data
|
||||
:return: (str, str) plain text and remaining encrypted data
|
||||
"""
|
||||
data = self._chunk['data'] + data
|
||||
|
@ -237,15 +286,13 @@ class AeadCryptoBase(object):
|
|||
if len(plaintext) != plen:
|
||||
raise Exception("plaintext length invalid")
|
||||
|
||||
self.cipher_ctx_init()
|
||||
|
||||
return plaintext, data[plen + self._tlen:]
|
||||
|
||||
def decrypt_chunk(self, data):
|
||||
"""
|
||||
Decrypt a TCP chunk
|
||||
|
||||
:param data: str encrypted msg
|
||||
:param data: str [len][tag][payload][tag][[len][tag]...] encrypted msg
|
||||
:return: (str, str) decrypted msg and remaining encrypted data
|
||||
"""
|
||||
plen, data = self.decrypt_chunk_size(data)
|
||||
|
@ -261,11 +308,13 @@ class AeadCryptoBase(object):
|
|||
:param data: str
|
||||
:return: str
|
||||
"""
|
||||
ptext, left = self.decrypt_chunk(data)
|
||||
ptext = []
|
||||
pnext, left = self.decrypt_chunk(data)
|
||||
ptext.append(pnext)
|
||||
while len(left) > 0:
|
||||
pnext, left = self.decrypt_chunk(left)
|
||||
ptext += pnext
|
||||
return ptext
|
||||
ptext.append(pnext)
|
||||
return b''.join(ptext)
|
||||
|
||||
|
||||
def test_nonce_increment():
|
||||
|
|
|
@ -23,20 +23,24 @@ from ctypes import c_char_p, c_int, c_long, byref,\
|
|||
from shadowsocks import common
|
||||
from shadowsocks.crypto import util
|
||||
from shadowsocks.crypto.aead import AeadCryptoBase, EVP_CTRL_AEAD_SET_IVLEN, \
|
||||
nonce_increment, EVP_CTRL_AEAD_GET_TAG, EVP_CTRL_AEAD_SET_TAG
|
||||
EVP_CTRL_AEAD_GET_TAG, EVP_CTRL_AEAD_SET_TAG
|
||||
|
||||
__all__ = ['ciphers']
|
||||
|
||||
libcrypto = None
|
||||
loaded = False
|
||||
libsodium = None
|
||||
|
||||
buf = None
|
||||
buf_size = 2048
|
||||
|
||||
ctx_cleanup = None
|
||||
|
||||
CIPHER_ENC_UNCHANGED = -1
|
||||
|
||||
|
||||
def load_openssl():
|
||||
global loaded, libcrypto, buf, ctx_cleanup
|
||||
global loaded, libcrypto, libsodium, buf, ctx_cleanup
|
||||
|
||||
libcrypto = util.find_library(('crypto', 'eay32'),
|
||||
'EVP_get_cipherbyname',
|
||||
|
@ -140,10 +144,13 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
|||
super(OpenSSLAeadCrypto, self).__init__(cipher_name)
|
||||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op)
|
||||
|
||||
key_ptr = c_char_p(self._skey)
|
||||
r = libcrypto.EVP_CipherInit_ex(
|
||||
self._ctx,
|
||||
self._cipher, None,
|
||||
None, None, c_int(op)
|
||||
self._cipher,
|
||||
None,
|
||||
key_ptr, None,
|
||||
c_int(op)
|
||||
)
|
||||
if not r:
|
||||
self.clean()
|
||||
|
@ -165,21 +172,19 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
|||
Need init cipher context after EVP_CipherFinal_ex to reuse context
|
||||
:return: void
|
||||
"""
|
||||
key_ptr = c_char_p(self._skey)
|
||||
iv_ptr = c_char_p(self._nonce.raw)
|
||||
|
||||
r = libcrypto.EVP_CipherInit_ex(
|
||||
self._ctx,
|
||||
None, None,
|
||||
key_ptr, iv_ptr,
|
||||
None,
|
||||
None,
|
||||
None, iv_ptr,
|
||||
c_int(CIPHER_ENC_UNCHANGED)
|
||||
)
|
||||
if not r:
|
||||
self.clean()
|
||||
raise Exception('can not initialize cipher context')
|
||||
|
||||
nonce_increment(self._nonce, self._nlen)
|
||||
# print("".join("%02x" % ord(b) for b in self._nonce))
|
||||
AeadCryptoBase.nonce_increment(self)
|
||||
|
||||
def set_tag(self, tag):
|
||||
"""
|
||||
|
@ -225,7 +230,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
|||
)
|
||||
if not r:
|
||||
# print(self._nonce.raw, r, cipher_out_len)
|
||||
raise Exception('Verify data failed')
|
||||
raise Exception('Finalize cipher failed')
|
||||
return buf.raw[:cipher_out_len.value]
|
||||
|
||||
def aead_encrypt(self, data):
|
||||
|
@ -236,6 +241,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
|||
:return: cipher text with tag
|
||||
"""
|
||||
ctext = self.update(data) + self.final() + self.get_tag()
|
||||
self.cipher_ctx_init()
|
||||
return ctext
|
||||
|
||||
def aead_decrypt(self, data):
|
||||
|
@ -251,6 +257,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
|||
|
||||
self.set_tag(data[clen - self._tlen:])
|
||||
plaintext = self.update(data[:clen - self._tlen]) + self.final()
|
||||
self.cipher_ctx_init()
|
||||
return plaintext
|
||||
|
||||
|
||||
|
@ -305,6 +312,7 @@ ciphers = {
|
|||
|
||||
def run_method(method):
|
||||
|
||||
print(method, ': [stream]', 32)
|
||||
cipher = OpenSSLStreamCrypto(method, b'k' * 32, b'i' * 16, 1)
|
||||
decipher = OpenSSLStreamCrypto(method, b'k' * 32, b'i' * 16, 0)
|
||||
|
||||
|
@ -313,6 +321,13 @@ def run_method(method):
|
|||
|
||||
def run_aead_method(method, key_len=16):
|
||||
|
||||
print(method, ': [payload][tag]', key_len)
|
||||
cipher = libcrypto.EVP_get_cipherbyname(common.to_bytes(method))
|
||||
if not cipher:
|
||||
cipher = load_cipher(common.to_bytes(method))
|
||||
if not cipher:
|
||||
print('cipher not avaiable, please upgrade openssl')
|
||||
return
|
||||
key_len = int(key_len)
|
||||
cipher = OpenSSLAeadCrypto(method, b'k' * key_len, b'i' * key_len, 1)
|
||||
decipher = OpenSSLAeadCrypto(method, b'k' * key_len, b'i' * key_len, 0)
|
||||
|
@ -320,18 +335,46 @@ def run_aead_method(method, key_len=16):
|
|||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def run_aead_method_chunk(method, key_len=16):
|
||||
|
||||
print(method, ': chunk([size][tag][payload][tag]', key_len)
|
||||
cipher = libcrypto.EVP_get_cipherbyname(common.to_bytes(method))
|
||||
if not cipher:
|
||||
cipher = load_cipher(common.to_bytes(method))
|
||||
if not cipher:
|
||||
print('cipher not avaiable, please upgrade openssl')
|
||||
return
|
||||
key_len = int(key_len)
|
||||
cipher = OpenSSLAeadCrypto(method, b'k' * key_len, b'i' * key_len, 1)
|
||||
decipher = OpenSSLAeadCrypto(method, b'k' * key_len, b'i' * key_len, 0)
|
||||
|
||||
cipher.encrypt_once = cipher.encrypt
|
||||
decipher.decrypt_once = decipher.decrypt
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_aes_128_cfb():
|
||||
run_method('aes-128-cfb')
|
||||
|
||||
|
||||
def test_aes_gcm(bits=128):
|
||||
method = "aes-{0}-gcm".format(bits)
|
||||
print(method, int(bits / 8))
|
||||
run_aead_method(method, bits / 8)
|
||||
|
||||
|
||||
def test_aes_256_gcm():
|
||||
test_aes_gcm(256)
|
||||
def test_aes_ocb(bits=128):
|
||||
method = "aes-{0}-ocb".format(bits)
|
||||
run_aead_method(method, bits / 8)
|
||||
|
||||
|
||||
def test_aes_gcm_chunk(bits=128):
|
||||
method = "aes-{0}-gcm".format(bits)
|
||||
run_aead_method_chunk(method, bits / 8)
|
||||
|
||||
|
||||
def test_aes_ocb_chunk(bits=128):
|
||||
method = "aes-{0}-ocb".format(bits)
|
||||
run_aead_method_chunk(method, bits / 8)
|
||||
|
||||
|
||||
def test_aes_256_cfb():
|
||||
|
@ -360,7 +403,16 @@ def test_rc4():
|
|||
|
||||
if __name__ == '__main__':
|
||||
test_aes_128_cfb()
|
||||
test_aes_256_cfb()
|
||||
test_aes_gcm(128)
|
||||
test_aes_gcm(192)
|
||||
test_aes_gcm(256)
|
||||
test_aes_256_gcm()
|
||||
test_aes_gcm_chunk(128)
|
||||
test_aes_gcm_chunk(192)
|
||||
test_aes_gcm_chunk(256)
|
||||
test_aes_ocb(128)
|
||||
test_aes_ocb(192)
|
||||
test_aes_ocb(256)
|
||||
test_aes_ocb_chunk(128)
|
||||
test_aes_ocb_chunk(192)
|
||||
test_aes_ocb_chunk(256)
|
||||
|
|
|
@ -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 import aead
|
||||
from shadowsocks.crypto.aead import AeadCryptoBase
|
||||
|
||||
__all__ = ['ciphers']
|
||||
|
@ -28,6 +29,7 @@ __all__ = ['ciphers']
|
|||
libsodium = None
|
||||
loaded = False
|
||||
|
||||
buf = None
|
||||
buf_size = 2048
|
||||
|
||||
# for salsa20 and chacha20 and chacha20-ietf
|
||||
|
@ -37,10 +39,20 @@ BLOCK_SIZE = 64
|
|||
def load_libsodium():
|
||||
global loaded, libsodium, buf
|
||||
|
||||
libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic',
|
||||
'libsodium')
|
||||
if libsodium is None:
|
||||
raise Exception('libsodium not found')
|
||||
if not aead.sodium_loaded:
|
||||
aead.load_sodium()
|
||||
|
||||
if aead.sodium_loaded:
|
||||
libsodium = aead.libsodium
|
||||
else:
|
||||
print('load libsodium again')
|
||||
libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic',
|
||||
'libsodium')
|
||||
if libsodium is None:
|
||||
raise Exception('libsodium not found')
|
||||
|
||||
if libsodium.sodium_init() < 0:
|
||||
raise Exception('libsodium init failed')
|
||||
|
||||
libsodium.crypto_stream_salsa20_xor_ic.restype = c_int
|
||||
libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p,
|
||||
|
@ -116,10 +128,26 @@ def load_libsodium():
|
|||
c_char_p, c_char_p
|
||||
)
|
||||
|
||||
libsodium.sodium_increment.restype = c_void_p
|
||||
libsodium.sodium_increment.argtypes = (
|
||||
c_void_p, c_int
|
||||
)
|
||||
# aes-256-gcm, same api structure as above
|
||||
libsodium.crypto_aead_aes256gcm_is_available.restype = c_int
|
||||
|
||||
if libsodium.crypto_aead_aes256gcm_is_available():
|
||||
libsodium.crypto_aead_aes256gcm_encrypt.restype = c_int
|
||||
libsodium.crypto_aead_aes256gcm_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_aes256gcm_decrypt.restype = c_int
|
||||
libsodium.crypto_aead_aes256gcm_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
|
||||
)
|
||||
|
||||
buf = create_string_buffer(buf_size)
|
||||
loaded = True
|
||||
|
@ -192,11 +220,15 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
|||
crypto_aead_xchacha20poly1305_ietf_decrypt
|
||||
else:
|
||||
raise Exception('Unknown cipher')
|
||||
elif cipher_name == 'sodium:aes-256-gcm':
|
||||
if hasattr(libsodium, 'crypto_aead_aes256gcm_encrypt'):
|
||||
self.encryptor = libsodium.crypto_aead_aes256gcm_encrypt
|
||||
self.decryptor = libsodium.crypto_aead_aes256gcm_decrypt
|
||||
else:
|
||||
raise Exception('Unknown cipher')
|
||||
|
||||
def cipher_ctx_init(self):
|
||||
|
||||
global libsodium
|
||||
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen))
|
||||
# print("".join("%02x" % ord(b) for b in self._nonce))
|
||||
|
||||
|
@ -216,6 +248,7 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
|||
if cipher_out_len.value != plen + self._tlen:
|
||||
raise Exception("Encrypt failed")
|
||||
|
||||
self.cipher_ctx_init()
|
||||
return buf.raw[:cipher_out_len.value]
|
||||
|
||||
def aead_decrypt(self, data):
|
||||
|
@ -238,6 +271,7 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
|||
if cipher_out_len.value != clen - self._tlen:
|
||||
raise Exception("Encrypt failed")
|
||||
|
||||
self.cipher_ctx_init()
|
||||
return buf.raw[:cipher_out_len.value]
|
||||
|
||||
|
||||
|
@ -248,10 +282,13 @@ ciphers = {
|
|||
'chacha20-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
'chacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
'xchacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||
'sodium:aes-256-gcm': (32, 32, SodiumAeadCrypto),
|
||||
}
|
||||
|
||||
|
||||
def test_salsa20():
|
||||
|
||||
print("Test salsa20")
|
||||
cipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 1)
|
||||
decipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 0)
|
||||
|
||||
|
@ -260,6 +297,7 @@ def test_salsa20():
|
|||
|
||||
def test_chacha20():
|
||||
|
||||
print("Test chacha20")
|
||||
cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1)
|
||||
decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0)
|
||||
|
||||
|
@ -268,6 +306,7 @@ def test_chacha20():
|
|||
|
||||
def test_chacha20_ietf():
|
||||
|
||||
print("Test chacha20-ietf")
|
||||
cipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 1)
|
||||
decipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 0)
|
||||
|
||||
|
@ -276,7 +315,7 @@ def test_chacha20_ietf():
|
|||
|
||||
def test_chacha20_poly1305():
|
||||
|
||||
print("Test chacha20-poly1305")
|
||||
print("Test chacha20-poly1305 [payload][tag]")
|
||||
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
|
@ -285,9 +324,23 @@ def test_chacha20_poly1305():
|
|||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_chacha20_poly1305_chunk():
|
||||
|
||||
print("Test chacha20-poly1305 chunk [size][tag][payload][tag]")
|
||||
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
cipher.encrypt_once = cipher.encrypt
|
||||
decipher.decrypt_once = decipher.decrypt
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_chacha20_ietf_poly1305():
|
||||
|
||||
print("Test chacha20-ietf-poly1305")
|
||||
print("Test chacha20-ietf-poly1305 [payload][tag]")
|
||||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
|
@ -296,9 +349,52 @@ def test_chacha20_ietf_poly1305():
|
|||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_chacha20_ietf_poly1305_chunk():
|
||||
|
||||
print("Test chacha20-ietf-poly1305 chunk [size][tag][payload][tag]")
|
||||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
cipher.encrypt_once = cipher.encrypt
|
||||
decipher.decrypt_once = decipher.decrypt
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_aes_256_gcm():
|
||||
|
||||
print("Test sodium:aes-256-gcm [payload][tag]")
|
||||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
def test_aes_256_gcm_chunk():
|
||||
|
||||
print("Test sodium:aes-256-gcm chunk [size][tag][payload][tag]")
|
||||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||
b'k' * 32, b'i' * 32, 1)
|
||||
decipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||
b'k' * 32, b'i' * 32, 0)
|
||||
|
||||
cipher.encrypt_once = cipher.encrypt
|
||||
decipher.decrypt_once = decipher.decrypt
|
||||
|
||||
util.run_cipher(cipher, decipher)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_chacha20()
|
||||
test_salsa20()
|
||||
test_chacha20_ietf()
|
||||
test_chacha20_poly1305()
|
||||
test_chacha20_poly1305_chunk()
|
||||
test_chacha20_ietf_poly1305()
|
||||
test_chacha20_ietf_poly1305_chunk()
|
||||
test_aes_256_gcm()
|
||||
test_aes_256_gcm_chunk()
|
||||
|
|
|
@ -114,25 +114,27 @@ def run_cipher(cipher, decipher):
|
|||
rounds = 1 * 1024
|
||||
plain = urandom(block_size * rounds)
|
||||
|
||||
results = []
|
||||
cipher_results = []
|
||||
pos = 0
|
||||
print('test start')
|
||||
start = time.time()
|
||||
while pos < len(plain):
|
||||
l = random.randint(100, 32768)
|
||||
c = cipher.encrypt(plain[pos:pos + l])
|
||||
results.append(c)
|
||||
# print(pos, l)
|
||||
c = cipher.encrypt_once(plain[pos:pos + l])
|
||||
cipher_results.append(c)
|
||||
pos += l
|
||||
pos = 0
|
||||
c = b''.join(results)
|
||||
results = []
|
||||
while pos < len(c):
|
||||
l = random.randint(100, 32768)
|
||||
results.append(decipher.decrypt(c[pos:pos + l]))
|
||||
# c = b''.join(cipher_results)
|
||||
plain_results = []
|
||||
for c in cipher_results:
|
||||
# l = random.randint(100, 32768)
|
||||
l = len(c)
|
||||
plain_results.append(decipher.decrypt_once(c))
|
||||
pos += l
|
||||
end = time.time()
|
||||
print('speed: %d bytes/s' % (block_size * rounds / (end - start)))
|
||||
assert b''.join(results) == plain
|
||||
assert b''.join(plain_results) == plain
|
||||
|
||||
|
||||
def test_find_library():
|
||||
|
|
|
@ -362,18 +362,21 @@ Proxy options:
|
|||
-l LOCAL_PORT local port, default: 1080
|
||||
-k PASSWORD password
|
||||
-m METHOD encryption method, default: aes-256-cfb
|
||||
supported method:
|
||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||
*xchacha20-ietf-poly1305,
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
||||
es-128-ctr, aes-192-ctr, aes-256-ctr,
|
||||
camellia-128-cfb, camellia-192-cfb,
|
||||
camellia-256-cfb,
|
||||
salsa20, chacha20, chacha20-ietf,
|
||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||
rc2-cfb, seed-cfb,
|
||||
rc4, rc4-md5, table.
|
||||
Sodium:
|
||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||
*xchacha20-ietf-poly1305,
|
||||
sodium:aes-256-gcm,
|
||||
salsa20, chacha20, chacha20-ietf.
|
||||
OpenSSL:(* v1.1)
|
||||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb,
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
||||
aes-128-ctr, aes-192-ctr, aes-256-ctr,
|
||||
camellia-128-cfb, camellia-192-cfb,
|
||||
camellia-256-cfb,
|
||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||
rc2-cfb, seed-cfb,
|
||||
rc4, rc4-md5, table.
|
||||
-t TIMEOUT timeout in seconds, default: 300
|
||||
-a ONE_TIME_AUTH one time auth
|
||||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
|
||||
|
@ -404,18 +407,21 @@ Proxy options:
|
|||
-p SERVER_PORT server port, default: 8388
|
||||
-k PASSWORD password
|
||||
-m METHOD encryption method, default: aes-256-cfb
|
||||
supported method:
|
||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||
*xchacha20-ietf-poly1305,
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
||||
es-128-ctr, aes-192-ctr, aes-256-ctr,
|
||||
camellia-128-cfb, camellia-192-cfb,
|
||||
camellia-256-cfb,
|
||||
salsa20, chacha20, chacha20-ietf,
|
||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||
rc2-cfb, seed-cfb,
|
||||
rc4, rc4-md5, table.
|
||||
Sodium:
|
||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||
*xchacha20-ietf-poly1305,
|
||||
sodium:aes-256-gcm,
|
||||
salsa20, chacha20, chacha20-ietf.
|
||||
OpenSSL:(* v1.1)
|
||||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb,
|
||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
||||
aes-128-ctr, aes-192-ctr, aes-256-ctr,
|
||||
camellia-128-cfb, camellia-192-cfb,
|
||||
camellia-256-cfb,
|
||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||
rc2-cfb, seed-cfb,
|
||||
rc4, rc4-md5, table.
|
||||
-t TIMEOUT timeout in seconds, default: 300
|
||||
-a ONE_TIME_AUTH one time auth
|
||||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
|
||||
|
|
Loading…
Reference in a new issue