diff --git a/.travis.yml b/.travis.yml index 5f1fe20..416ed49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,13 +8,12 @@ matrix: - os: linux dist: trusty python: '2.7' -# pycryptodomex seems to fail on AES import -# - os: linux -# dist: trusty -# python: '3.2' -# - os: linux -# dist: trusty -# python: '3.3' + - os: linux + dist: trusty + python: '3.2' + - os: linux + dist: trusty + python: '3.3' - os: linux dist: trusty python: '3.4' diff --git a/CHANGES.txt b/CHANGES.txt index 383018a..c1ebcaf 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -2,7 +2,7 @@ Revision 0.4.5, released XX-01-2019 ----------------------------------- -No changes so far +- Trunk encryption (and therefore `pycryptodomex` package) made optional Revision 0.4.4, released 30-12-2018 ----------------------------------- diff --git a/optional-requirements.txt b/optional-requirements.txt new file mode 100644 index 0000000..1a668a6 --- /dev/null +++ b/optional-requirements.txt @@ -0,0 +1 @@ +pycryptodomex diff --git a/requirements.txt b/requirements.txt index ff34a5b..ad24313 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ -pycryptodomex pysnmp>=4.4.3,<5.0.0 diff --git a/snmpfwd/trunking/crypto.py b/snmpfwd/trunking/crypto.py index b1d6ca3..bf3b365 100644 --- a/snmpfwd/trunking/crypto.py +++ b/snmpfwd/trunking/crypto.py @@ -4,30 +4,53 @@ # Copyright (c) 2014-2019, Ilya Etingof # License: http://snmplabs.com/snmpfwd/license.html # -from Cryptodome import Random -from Cryptodome.Cipher import AES -from pyasn1.compat.octets import int2oct, oct2int, str2octs +try: + from Cryptodome import Random + from Cryptodome.Cipher import AES + from pyasn1.compat.octets import int2oct, oct2int, str2octs -class AESCipher(object): - @staticmethod - def pad(s, BS=16): - return s + (BS - len(s) % BS) * int2oct(BS - len(s) % BS) +except ImportError: - @staticmethod - def unpad(s): - return s[0:-oct2int(s[-1])] + from snmpfwd.error import SnmpfwdError - def encrypt(self, key, raw): - raw = self.pad(raw) - iv = Random.new().read(AES.block_size) - cipher = AES.new(str2octs(key), AES.MODE_CBC, iv) - return iv + cipher.encrypt(raw) - def decrypt(self, key, enc): - iv = enc[:16] - cipher = AES.new(str2octs(key), AES.MODE_CBC, iv) - return self.unpad(cipher.decrypt(enc[16:])) + class NoCipher(object): + msg = ('Trunk encryption is not available. Make sure ' + 'to install the `pycryptodomex` package') -encrypt = AESCipher().encrypt -decrypt = AESCipher().decrypt + def encrypt(self, key, raw): + raise SnmpfwdError(self.msg) + + def decrypt(self, key, raw): + raise SnmpfwdError(self.msg) + + Cipher = NoCipher + +else: + + class AESCipher(object): + @staticmethod + def pad(s, BS=16): + return s + (BS - len(s) % BS) * int2oct(BS - len(s) % BS) + + @staticmethod + def unpad(s): + return s[0:-oct2int(s[-1])] + + def encrypt(self, key, raw): + raw = self.pad(raw) + iv = Random.new().read(AES.block_size) + cipher = AES.new(str2octs(key), AES.MODE_CBC, iv) + return iv + cipher.encrypt(raw) + + def decrypt(self, key, enc): + iv = enc[:16] + cipher = AES.new(str2octs(key), AES.MODE_CBC, iv) + return self.unpad(cipher.decrypt(enc[16:])) + + Cipher = AESCipher + + +encrypt = Cipher().encrypt +decrypt = Cipher().decrypt