summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2016-08-21 23:00:16 +0200
committerIlya Etingof <etingof@gmail.com>2016-08-21 23:00:16 +0200
commit6eed8eff24910727316a25b6a180822174d2bcab (patch)
tree594d374b428a0be01d15e57a7ec2b26ab713de32
parent9efc0872d799ad2ba31a64b3e7f72c7f5625831a (diff)
downloadpysnmp-git-6eed8eff24910727316a25b6a180822174d2bcab.tar.gz
Reeder key localization for AES192/256 encryption implemented
-rw-r--r--CHANGES.txt6
-rw-r--r--pysnmp/entity/config.py8
-rw-r--r--pysnmp/proto/secmod/eso/priv/aes192.py19
-rw-r--r--pysnmp/proto/secmod/eso/priv/aes256.py17
-rw-r--r--pysnmp/proto/secmod/eso/priv/aesbase.py36
-rw-r--r--pysnmp/proto/secmod/rfc3414/service.py2
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):