diff options
-rw-r--r-- | CHANGES.txt | 6 | ||||
-rw-r--r-- | pysnmp/entity/config.py | 8 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aes192.py | 19 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aes256.py | 17 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aesbase.py | 36 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 2 |
6 files changed, 84 insertions, 4 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 7f6977e9..305ba88c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,12 @@ Github `repo <https://github.com/etingof/pysnmp>`_ MIB objects. A side effect of this change is that additional var-binds can only be added prior to .resolveMibObjects() is run. +- Non-standard (but apparently used by many vendors) Reeder AES192/256 + key localization algorithm implemented and set as default for + usmAesCfb192Protocol and usmAesCfb256Protocol identifiers. + Original and more standard implementation can still be used + with the usmAesBlumenthalCfb192Protocol and + usmAesBlumenthalCfb192Protocol IDs respectively. - Fix to NotificationType to make additional var-binds overriding MIB objects implicitly included through NOTIFICATION-TYPE OBJECTS. - Fix to SNMP engine boots counter persistence on Python 3. diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index 10acd25b..13e284f1 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -29,8 +29,10 @@ usmNoAuthProtocol = noauth.NoAuth.serviceID usmDESPrivProtocol = des.Des.serviceID usm3DESEDEPrivProtocol = des3.Des3.serviceID usmAesCfb128Protocol = aes.Aes.serviceID -usmAesCfb192Protocol = aes192.Aes192.serviceID -usmAesCfb256Protocol = aes256.Aes256.serviceID +usmAesBlumenthalCfb192Protocol = aes192.Aes192.serviceID # semi-standard but not widely used +usmAesBlumenthalCfb256Protocol = aes256.Aes256.serviceID # semi-standard but not widely used +usmAesCfb192Protocol = aes192.AesReeder192.serviceID # non-standard but used by many vendors +usmAesCfb256Protocol = aes256.AesReeder256.serviceID # non-standard but used by many vendors usmNoPrivProtocol = nopriv.NoPriv.serviceID # Auth services @@ -44,6 +46,8 @@ privServices = {des.Des.serviceID: des.Des(), aes.Aes.serviceID: aes.Aes(), aes192.Aes192.serviceID: aes192.Aes192(), aes256.Aes256.serviceID: aes256.Aes256(), + aes192.AesReeder192.serviceID: aes192.AesReeder192(), # non-standard + aes256.AesReeder256.serviceID: aes256.AesReeder256(), # non-standard nopriv.NoPriv.serviceID: nopriv.NoPriv()} diff --git a/pysnmp/proto/secmod/eso/priv/aes192.py b/pysnmp/proto/secmod/eso/priv/aes192.py index 0de69551..7ff2fb25 100644 --- a/pysnmp/proto/secmod/eso/priv/aes192.py +++ b/pysnmp/proto/secmod/eso/priv/aes192.py @@ -8,9 +8,26 @@ from pysnmp.proto.secmod.eso.priv import aesbase class Aes192(aesbase.AbstractAes): - """AES 192/256 bit encryption (Internet draft) + """AES 192 bit encryption (Internet draft) + + Reeder AES encryption: http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 """ serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 1) # cusmAESCfb192PrivProtocol keySize = 24 + + +class AesReeder192(aesbase.AbstractAesReeder): + """AES 192 bit encryption (Internet draft) + + Reeder AES encryption with non-standard key localization algorithm + borrowed from Reeder 3DES draft: + + http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 + https://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00 + + Known to be used by many vendors including Cisco and others. + """ + serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 101) # cusmAESCfb192PrivProtocol (non-standard) + keySize = 24 diff --git a/pysnmp/proto/secmod/eso/priv/aes256.py b/pysnmp/proto/secmod/eso/priv/aes256.py index c6ec1ab9..6a3885fa 100644 --- a/pysnmp/proto/secmod/eso/priv/aes256.py +++ b/pysnmp/proto/secmod/eso/priv/aes256.py @@ -8,9 +8,24 @@ from pysnmp.proto.secmod.eso.priv import aesbase class Aes256(aesbase.AbstractAes): - """AES 192/256 bit encryption (Internet draft) + """AES 256 bit encryption (Internet draft) http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 """ serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 2) # cusmAESCfb256PrivProtocol keySize = 32 + + +class AesReeder256(aesbase.AbstractAesReeder): + """AES 256 bit encryption (Internet draft) + + Reeder AES encryption with non-standard key localization algorithm + borrowed from Reeder 3DES draft: + + http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 + https://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00 + + Known to be used by many vendors including Cisco and others. + """ + serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 102) # cusmAESCfb256PrivProtocol (non-standard) + keySize = 32 diff --git a/pysnmp/proto/secmod/eso/priv/aesbase.py b/pysnmp/proto/secmod/eso/priv/aesbase.py index bd0a19ec..fd484265 100644 --- a/pysnmp/proto/secmod/eso/priv/aesbase.py +++ b/pysnmp/proto/secmod/eso/priv/aesbase.py @@ -41,3 +41,39 @@ class AbstractAes(aes.Aes): 'Unknown auth protocol %s' % (authProtocol,) ) return localPrivKey[:self.keySize] + + +class AbstractAesReeder(AbstractAes): + """AES encryption with non-standard key localization. + + Cisco devices do not use: + + https://tools.itef.org/pdf/draft_bluementhal-aes-usm-04.txt + + for key localization instead, they use the procedure for 3DES key localization + specified in: + + https://tools.itef.org/pdf/draft_reeder_snmpv3-usm-3desede-00.pdf + + The difference between the two is that the Reeder draft does key extension by repeating + the steps in the password to key algorithm (hash phrase, then localize with SNMPEngine ID). + """ + + # 2.1 of https://tools.itef.org/pdf/draft_bluementhal-aes-usm-04.txt + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + # now extend this key if too short by repeating steps that includes the hashPassphrase step + while len(localPrivKey) < self.keySize: + newKey = hashPassphraseMD5(localPrivKey) # this is the difference between reeder and bluementhal + localPrivKey += localizeKeyMD5(newKey, snmpEngineID) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + while len(localPrivKey < self.keySize): + newKey = hashPassphraseSHA(localPrivKey) + localPrivKey += localizeKeySHA(newKey, snmpEngineID) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:self.keySize] diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index 415ee827..401558f5 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -46,6 +46,8 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): aes.Aes.serviceID: aes.Aes(), aes192.Aes192.serviceID: aes192.Aes192(), aes256.Aes256.serviceID: aes256.Aes256(), + aes192.AesReeder192.serviceID: aes192.AesReeder192(), # non-standard + aes256.AesReeder256.serviceID: aes256.AesReeder256(), # non-standard nopriv.NoPriv.serviceID: nopriv.NoPriv()} def __init__(self): |