diff options
author | elie <elie> | 2011-01-16 23:59:08 +0000 |
---|---|---|
committer | elie <elie> | 2011-01-16 23:59:08 +0000 |
commit | 9cd30024f0e8638c4905bdd433d19d68e1f91246 (patch) | |
tree | 98368e3038cc39da43377097376ef51de9fd3441 | |
parent | e095034ca1a3355dafb5e5958d1aa69acc140c03 (diff) | |
download | pysnmp-9cd30024f0e8638c4905bdd433d19d68e1f91246.tar.gz |
extended Security Options (3DESEDE, AES192, AES256) privacy protocols
implemented.
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | examples/v3arch/agent/cmdrsp.py | 4 | ||||
-rw-r--r-- | pysnmp/entity/config.py | 66 | ||||
-rw-r--r-- | pysnmp/entity/rfc3413/oneliner/cmdgen.py | 3 | ||||
-rw-r--r-- | pysnmp/entity/rfc3413/oneliner/ntforg.py | 3 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/__init__.py | 0 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/__init__.py | 0 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aes192.py | 27 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aes256.py | 27 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/des3.py | 158 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/base.py | 7 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py | 7 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/hmacsha.py | 7 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/noauth.py | 7 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/priv/base.py | 8 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/priv/des.py | 26 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/priv/nopriv.py | 6 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 39 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3826/priv/aes.py | 25 | ||||
-rw-r--r-- | setup.py | 2 |
20 files changed, 364 insertions, 60 deletions
@@ -1,6 +1,8 @@ Revision 4.1.16a ---------------- +- Extended Security Options (3DESEDE, AES192, AES256) privacy + protocols implemented. - The error-indication codes moved from literals to objects for reliability and clarity diff --git a/examples/v3arch/agent/cmdrsp.py b/examples/v3arch/agent/cmdrsp.py index 51d473a..9e2e9b2 100644 --- a/examples/v3arch/agent/cmdrsp.py +++ b/examples/v3arch/agent/cmdrsp.py @@ -41,7 +41,11 @@ config.addV1System(snmpEngine, 'test-agent', 'public') config.addV3User( snmpEngine, 'test-user', config.usmHMACMD5AuthProtocol, 'authkey1', +# config.usmHMACSHAAuthProtocol, 'authkey1', config.usmDESPrivProtocol, 'privkey1' +# config.usm3DESEDEPrivProtocol, 'privkey1' +# config.usmAesCfb192Protocol, 'privkey1' +# config.usmAesCfb256Protocol, 'privkey1' # config.usmAesCfb128Protocol, 'privkey1' ) diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index e6fed2b..1ffb04b 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -9,11 +9,11 @@ try: except ImportError: # UNIX-specific -- may not be always available pass from pysnmp.proto import rfc3412 -from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.entity import engine from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha, noauth from pysnmp.proto.secmod.rfc3414.priv import des, nopriv from pysnmp.proto.secmod.rfc3826.priv import aes +from pysnmp.proto.secmod.eso.priv import des3, aes192, aes256 from pysnmp.smi.error import NotWritableError from pysnmp import error @@ -30,9 +30,29 @@ usmNoAuthProtocol = noauth.NoAuth.serviceID # Privacy protocol usmDESPrivProtocol = des.Des.serviceID +usm3DESEDEPrivProtocol = des3.Des3.serviceID usmAesCfb128Protocol = aes.Aes.serviceID +usmAesCfb192Protocol = aes192.Aes192.serviceID +usmAesCfb256Protocol = aes256.Aes256.serviceID usmNoPrivProtocol = nopriv.NoPriv.serviceID +# Auth services +authServices = { + hmacmd5.HmacMd5.serviceID: hmacmd5.HmacMd5(), + hmacsha.HmacSha.serviceID: hmacsha.HmacSha(), + noauth.NoAuth.serviceID: noauth.NoAuth() + } + +# Privacy services +privServices = { + des.Des.serviceID: des.Des(), + des3.Des3.serviceID: des3.Des3(), + aes.Aes.serviceID: aes.Aes(), + aes192.Aes192.serviceID: aes192.Aes192(), + aes256.Aes256.serviceID: aes256.Aes256(), + nopriv.NoPriv.serviceID: nopriv.NoPriv() + } + def __cookV1SystemInfo(snmpEngine, securityName): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') @@ -117,47 +137,23 @@ def addV3User(snmpEngine, securityName, ) # Localize keys - if authProtocol == usmHMACMD5AuthProtocol: - hashedAuthPassphrase = localkey.hashPassphraseMD5( + if authServices.has_key(authProtocol): + hashedAuthPassphrase = authServices[authProtocol].hashPassphrase( authKey and authKey or '' ) - localAuthKey = localkey.localizeKeyMD5( + localAuthKey = authServices[authProtocol].localizeKey( hashedAuthPassphrase, snmpEngineID ) - elif authProtocol == usmHMACSHAAuthProtocol: - hashedAuthPassphrase = localkey.hashPassphraseSHA( - authKey and authKey or '' - ) - localAuthKey = localkey.localizeKeySHA( - hashedAuthPassphrase, snmpEngineID - ) - elif authProtocol == usmNoAuthProtocol: - hashedAuthPassphrase = localAuthKey = None else: raise error.PySnmpError('Unknown auth protocol %s' % (authProtocol,)) - if privProtocol == usmDESPrivProtocol or \ - privProtocol == usmAesCfb128Protocol: - if authProtocol == usmHMACMD5AuthProtocol: - hashedPrivPassphrase = localkey.hashPassphraseMD5( - privKey and privKey or '' - ) - localPrivKey = localkey.localizeKeyMD5( - hashedPrivPassphrase, snmpEngineID - ) - elif authProtocol == usmHMACSHAAuthProtocol: - hashedPrivPassphrase = localkey.hashPassphraseSHA( - privKey and privKey or '' - ) - localPrivKey = localkey.localizeKeySHA( - hashedPrivPassphrase, snmpEngineID - ) - else: - raise error.PySnmpError( - 'Unknown auth protocol %s' % (authProtocol,) - ) - elif privProtocol == usmNoPrivProtocol: - hashedPrivPassphrase = localPrivKey = None + if privServices.has_key(privProtocol): + hashedPrivPassphrase = privServices[privProtocol].hashPassphrase( + authProtocol, privKey and privKey or '' + ) + localPrivKey = privServices[privProtocol].localizeKey( + authProtocol, hashedPrivPassphrase, snmpEngineID + ) else: raise error.PySnmpError( 'Unknown priv protocol %s' % (privProtocol,) diff --git a/pysnmp/entity/rfc3413/oneliner/cmdgen.py b/pysnmp/entity/rfc3413/oneliner/cmdgen.py index d49a6e5..1204c67 100644 --- a/pysnmp/entity/rfc3413/oneliner/cmdgen.py +++ b/pysnmp/entity/rfc3413/oneliner/cmdgen.py @@ -13,7 +13,10 @@ usmNoAuthProtocol = config.usmNoAuthProtocol # Privacy protocol usmDESPrivProtocol = config.usmDESPrivProtocol +usm3DESEDEPrivProtocol = config.usm3DESEDEPrivProtocol usmAesCfb128Protocol = config.usmAesCfb128Protocol +usmAesCfb192Protocol = config.usmAesCfb192Protocol +usmAesCfb256Protocol = config.usmAesCfb256Protocol usmNoPrivProtocol = config.usmNoPrivProtocol nextID = nextid.Integer(0xffffffffL) diff --git a/pysnmp/entity/rfc3413/oneliner/ntforg.py b/pysnmp/entity/rfc3413/oneliner/ntforg.py index 45a5a25..3c78b63 100644 --- a/pysnmp/entity/rfc3413/oneliner/ntforg.py +++ b/pysnmp/entity/rfc3413/oneliner/ntforg.py @@ -10,7 +10,10 @@ usmNoAuthProtocol = cmdgen.usmNoAuthProtocol # Privacy protocol usmDESPrivProtocol = cmdgen.usmDESPrivProtocol +usm3DESEDEPrivProtocol = cmdgen.usm3DESEDEPrivProtocol usmAesCfb128Protocol = cmdgen.usmAesCfb128Protocol +usmAesCfb192Protocol = cmdgen.usmAesCfb192Protocol +usmAesCfb256Protocol = cmdgen.usmAesCfb256Protocol usmNoPrivProtocol = cmdgen.usmNoPrivProtocol # Credentials diff --git a/pysnmp/proto/secmod/eso/__init__.py b/pysnmp/proto/secmod/eso/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pysnmp/proto/secmod/eso/__init__.py diff --git a/pysnmp/proto/secmod/eso/priv/__init__.py b/pysnmp/proto/secmod/eso/priv/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pysnmp/proto/secmod/eso/priv/__init__.py diff --git a/pysnmp/proto/secmod/eso/priv/aes192.py b/pysnmp/proto/secmod/eso/priv/aes192.py new file mode 100644 index 0000000..abfff5c --- /dev/null +++ b/pysnmp/proto/secmod/eso/priv/aes192.py @@ -0,0 +1,27 @@ +# AES 192/256 bit encryption (Internet draft) +# http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 +from pysnmp.proto.secmod.rfc3826.priv import aes +from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc3414 import localkey + +class Aes192(aes.Aes): + serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 1) # cusmAESCfb192PrivProtocol + keySize = 24 + + # 3.1.2.1 + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeyMD5( + localPrivKey, snmpEngineID + ) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeySHA( + localPrivKey, snmpEngineID + ) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:24] diff --git a/pysnmp/proto/secmod/eso/priv/aes256.py b/pysnmp/proto/secmod/eso/priv/aes256.py new file mode 100644 index 0000000..874c83a --- /dev/null +++ b/pysnmp/proto/secmod/eso/priv/aes256.py @@ -0,0 +1,27 @@ +# AES 192/256 bit encryption (Internet draft) +# http://tools.ietf.org/html/draft-blumenthal-aes-usm-04 +from pysnmp.proto.secmod.rfc3826.priv import aes +from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc3414 import localkey + +class Aes256(aes.Aes): + serviceID = (1, 3, 6, 1, 4, 1, 9, 12, 6, 1, 2) # cusmAESCfb256PrivProtocol + keySize = 32 + + # 3.1.2.1 + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeyMD5( + localPrivKey, snmpEngineID + ) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeySHA( + localPrivKey, snmpEngineID + ) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:32] diff --git a/pysnmp/proto/secmod/eso/priv/des3.py b/pysnmp/proto/secmod/eso/priv/des3.py new file mode 100644 index 0000000..5a1a154 --- /dev/null +++ b/pysnmp/proto/secmod/eso/priv/des3.py @@ -0,0 +1,158 @@ +# Reeder 3DES-EDE for USM (Internet draft) +# http://www.snmp.com/eso/draft-reeder-snmpv3-usm-3desede-00.txt +import random, string +from pysnmp.proto.secmod.rfc3414.priv import base +from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc3414 import localkey +from pyasn1.type import univ +from pysnmp.proto import error + +try: + from sys import version_info +except ImportError: + version_info = ( 0, 0 ) # a really early version + +try: + from Crypto.Cipher import DES3 +except ImportError: + DES3 = None + +random.seed() + +# 5.1.1 + +class Des3(base.AbstractEncryptionService): + serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 3) # usm3DESEDEPrivProtocol + if version_info < (2, 3): + _localInt = long(random.random()*0xffffffffL) + else: + _localInt = random.randrange(0, 0xffffffffL) + + def hashPassphrase(self, authProtocol, privKey): + if authProtocol == hmacmd5.HmacMd5.serviceID: + return localkey.hashPassphraseMD5(privKey) + elif authProtocol == hmacsha.HmacSha.serviceID: + return localkey.hashPassphraseSHA(privKey) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeyMD5( + localPrivKey, snmpEngineID + ) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + localPrivKey = localPrivKey + localkey.localizeKeySHA( + localPrivKey, snmpEngineID + ) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:32] # key+IV + + # 5.1.1.1 + def __getEncryptionKey(self, privKey, snmpEngineBoots): + # 5.1.1.1.1 + des3Key = privKey[:24] + preIV = privKey[24:32] + + securityEngineBoots = long(snmpEngineBoots) + + salt = [ + securityEngineBoots>>24&0xff, + securityEngineBoots>>16&0xff, + securityEngineBoots>>8&0xff, + securityEngineBoots&0xff, + self._localInt>>24&0xff, + self._localInt>>16&0xff, + self._localInt>>8&0xff, + self._localInt&0xff + ] + if self._localInt == 0xffffffffL: + self._localInt = 0 + else: + self._localInt = self._localInt + 1 + + # salt not yet hashed XXX + + return des3Key, \ + string.join(map(chr, salt), ''), \ + string.join(map(lambda x,y: chr(x^ord(y)), salt, preIV), '') + + def __getDecryptionKey(self, privKey, salt): + return privKey[:24], string.join( + map(lambda x,y: chr(ord(x)^ord(y)), salt, privKey[24:32]), '' + ) + + # 5.1.1.2 + def encryptData(self, encryptKey, privParameters, dataToEncrypt): + if DES3 is None: + raise error.StatusInformation( + errorIndication=errind.encryptionError + ) + + snmpEngineBoots, snmpEngineTime, salt = privParameters + + des3Key, salt, iv = self.__getEncryptionKey( + str(encryptKey), snmpEngineBoots + ) + + des3Obj = DES3.new(des3Key, DES3.MODE_CBC, iv) + + privParameters = univ.OctetString(salt) + + plaintext = dataToEncrypt + '\x00' * (8 - len(dataToEncrypt) % 8) + cipherblock = iv + ciphertext = '' + while plaintext: + cipherblock = des3Obj.encrypt( + string.join(map(lambda x,y: chr(ord(x)^ord(y)), cipherblock, plaintext[:8]), '') + ) + ciphertext = ciphertext + cipherblock + plaintext = plaintext[8:] + + return univ.OctetString(ciphertext), privParameters + + # 5.1.1.3 + def decryptData(self, decryptKey, privParameters, encryptedData): + if DES3 is None: + raise error.StatusInformation( + errorIndication=errind.decryptionError + ) + snmpEngineBoots, snmpEngineTime, salt = privParameters + + if len(salt) != 8: + raise error.StatusInformation( + errorIndication=errind.decryptionError + ) + + salt = str(salt) + + des3Key, iv = self.__getDecryptionKey(str(decryptKey), salt) + + if len(encryptedData) % 8 != 0: + raise error.StatusInformation( + errorIndication=errind.decryptionError + ) + + des3Obj = DES3.new(des3Key, DES3.MODE_CBC, iv) + + plaintext = '' + ciphertext = str(encryptedData) + cipherblock = iv + while ciphertext: + plaintext = plaintext + string.join(map( + lambda x,y: chr(ord(x)^ord(y)), + cipherblock, + des3Obj.decrypt(ciphertext[:8]) + ), '') + cipherblock = ciphertext[:8] + ciphertext = ciphertext[8:] + + return plaintext + diff --git a/pysnmp/proto/secmod/rfc3414/auth/base.py b/pysnmp/proto/secmod/rfc3414/auth/base.py index 9b83458..8cefe1b 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/base.py +++ b/pysnmp/proto/secmod/rfc3414/auth/base.py @@ -2,6 +2,13 @@ from pysnmp.proto import errind, error class AbstractAuthenticationService: serviceID = None + + def hashPassphrase(self, authKey): + raise error.ProtocolError(errind.noAuthentication) + + def localizeKey(self, authKey, snmpEngineID): + raise error.ProtocolError(errind.noAuthentication) + # 7.2.4.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): raise error.ProtocolError(errind.noAuthentication) diff --git a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py index da98506..54efbef 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py @@ -5,6 +5,7 @@ except ImportError: md5 = md5.new import string from pysnmp.proto.secmod.rfc3414.auth import base +from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.proto import errind, error _twelveZeros = '\x00'*12 @@ -17,6 +18,12 @@ class HmacMd5(base.AbstractAuthenticationService): __ipad = [0x36]*64 __opad = [0x5C]*64 + def hashPassphrase(self, authKey): + return localkey.hashPassphraseMD5(authKey) + + def localizeKey(self, authKey, snmpEngineID): + return localkey.localizeKeyMD5(authKey, snmpEngineID) + # 6.3.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): # Here we expect calling secmod to indicate where the digest diff --git a/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py b/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py index 9b5e5e3..f813109 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py @@ -5,6 +5,7 @@ except ImportError: sha1 = sha.new import string from pysnmp.proto.secmod.rfc3414.auth import base +from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.proto import errind, error _twelveZeros = '\x00'*12 @@ -17,6 +18,12 @@ class HmacSha(base.AbstractAuthenticationService): __ipad = [0x36]*64 __opad = [0x5C]*64 + def hashPassphrase(self, authKey): + return localkey.hashPassphraseSHA(authKey) + + def localizeKey(self, authKey, snmpEngineID): + return localkey.localizeKeySHA(authKey, snmpEngineID) + # 7.3.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): # 7.3.1.1 diff --git a/pysnmp/proto/secmod/rfc3414/auth/noauth.py b/pysnmp/proto/secmod/rfc3414/auth/noauth.py index 59f3dec..e44b515 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/noauth.py +++ b/pysnmp/proto/secmod/rfc3414/auth/noauth.py @@ -3,6 +3,13 @@ from pysnmp.proto import errind, error class NoAuth(base.AbstractAuthenticationService): serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 1) # usmNoAuthProtocol + + def hashPassphrase(self, authKey): + return + + def localizeKey(self, authKey, snmpEngineID): + return + # 7.2.4.2 def authenticateOutgoingMsg(self, authKey, wholeMsg): raise error.StatusInformation(errorIndication=errind.noAuthentication) diff --git a/pysnmp/proto/secmod/rfc3414/priv/base.py b/pysnmp/proto/secmod/rfc3414/priv/base.py index d981319..8b71ddb 100644 --- a/pysnmp/proto/secmod/rfc3414/priv/base.py +++ b/pysnmp/proto/secmod/rfc3414/priv/base.py @@ -2,8 +2,16 @@ from pysnmp.proto import error class AbstractEncryptionService: serviceID = None + + def hashPassphrase(self, authProtocol, privKey): + raise error.ProtocolError('no encryption') + + def localizeKey(self, authProtocol, privKey, snmpEngineID): + raise error.ProtocolError('no encryption') + def encryptData(self, encryptKey, privParameters, dataToEncrypt): raise error.ProtocolError('no encryption') def decryptData(self, decryptKey, privParameters, encryptedData): raise error.ProtocolError('no encryption') + diff --git a/pysnmp/proto/secmod/rfc3414/priv/des.py b/pysnmp/proto/secmod/rfc3414/priv/des.py index f59b833..1f9d7ed 100644 --- a/pysnmp/proto/secmod/rfc3414/priv/des.py +++ b/pysnmp/proto/secmod/rfc3414/priv/des.py @@ -1,5 +1,7 @@ import random, string from pysnmp.proto.secmod.rfc3414.priv import base +from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc3414 import localkey from pyasn1.type import univ from pysnmp.proto import error @@ -23,6 +25,28 @@ class Des(base.AbstractEncryptionService): _localInt = long(random.random()*0xffffffffL) else: _localInt = random.randrange(0, 0xffffffffL) + + def hashPassphrase(self, authProtocol, privKey): + if authProtocol == hmacmd5.HmacMd5.serviceID: + return localkey.hashPassphraseMD5(privKey) + elif authProtocol == hmacsha.HmacSha.serviceID: + return localkey.hashPassphraseSHA(privKey) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:32] # key+IV + # 8.1.1.1 def __getEncryptionKey(self, privKey, snmpEngineBoots): desKey = privKey[:8] @@ -53,7 +77,7 @@ class Des(base.AbstractEncryptionService): return privKey[:8], string.join( map(lambda x,y: chr(ord(x)^ord(y)), salt, privKey[8:16]), '' ) - + # 8.2.4.1 def encryptData(self, encryptKey, privParameters, dataToEncrypt): if DES is None: diff --git a/pysnmp/proto/secmod/rfc3414/priv/nopriv.py b/pysnmp/proto/secmod/rfc3414/priv/nopriv.py index cce2c4e..f7b6092 100644 --- a/pysnmp/proto/secmod/rfc3414/priv/nopriv.py +++ b/pysnmp/proto/secmod/rfc3414/priv/nopriv.py @@ -3,6 +3,12 @@ from pysnmp.proto import errind, error class NoPriv(base.AbstractEncryptionService): serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 1) # usmNoPrivProtocol + def hashPassphrase(self, authProtocol, privKey): + return + + def localizeKey(self, authProtocol, privKey, snmpEngineID): + return + def encryptData(self, encryptKey, privParameters, dataToEncrypt): raise error.StatusInformation(errorIndication=errind.noEncryption) diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index b26f167..5b3e134 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -3,7 +3,7 @@ from pysnmp.proto.secmod.base import AbstractSecurityModel from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha, noauth from pysnmp.proto.secmod.rfc3414.priv import des, nopriv from pysnmp.proto.secmod.rfc3826.priv import aes -from pysnmp.proto.secmod.rfc3414 import localkey +from pysnmp.proto.secmod.eso.priv import des3, aes192, aes256 from pysnmp.smi.error import NoSuchInstanceError from pysnmp.proto import rfc1155, errind, error from pyasn1.type import univ, namedtype, constraint @@ -30,11 +30,13 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): hmacmd5.HmacMd5.serviceID: hmacmd5.HmacMd5(), hmacsha.HmacSha.serviceID: hmacsha.HmacSha(), noauth.NoAuth.serviceID: noauth.NoAuth() - } privServices = { des.Des.serviceID: des.Des(), + des3.Des3.serviceID: des3.Des3(), aes.Aes.serviceID: aes.Aes(), + aes192.Aes192.serviceID: aes192.Aes192(), + aes256.Aes256.serviceID: aes256.Aes256(), nopriv.NoPriv.serviceID: nopriv.NoPriv() } _securityParametersSpec = UsmSecurityParameters() @@ -142,16 +144,12 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (1,) + tblIdx ) - if usmUserAuthProtocol.syntax == hmacsha.HmacSha.serviceID: - localAuthKey = localkey.localizeKeySHA( - pysnmpUsmKeyAuth.syntax, securityEngineID - ) - elif usmUserAuthProtocol.syntax == hmacmd5.HmacMd5.serviceID: - localAuthKey = localkey.localizeKeyMD5( - pysnmpUsmKeyAuth.syntax, securityEngineID + if self.authServices.has_key(usmUserAuthProtocol.syntax): + localizeKey = self.authServices[usmUserAuthProtocol.syntax].localizeKey + localAuthKey = localizeKey( + pysnmpUsmKeyAuth.syntax, + securityEngineID ) - elif usmUserAuthProtocol.syntax == noauth.NoAuth.serviceID: - localAuthKey = None else: raise error.StatusInformation( errorIndication = errind.unsupportedAuthProtocol @@ -161,18 +159,13 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (2,) + tblIdx ) - if usmUserPrivProtocol.syntax == des.Des.serviceID or \ - usmUserPrivProtocol.syntax == aes.Aes.serviceID: - if usmUserAuthProtocol.syntax == hmacsha.HmacSha.serviceID: - localPrivKey = localkey.localizeKeySHA( - pysnmpUsmKeyPriv.syntax, securityEngineID - ) - else: - localPrivKey = localkey.localizeKeyMD5( - pysnmpUsmKeyPriv.syntax, securityEngineID - ) - elif usmUserPrivProtocol.syntax == nopriv.NoPriv.serviceID: - localPrivKey = None + if self.privServices.has_key(usmUserPrivProtocol.syntax): + localizeKey = self.privServices[usmUserPrivProtocol.syntax].localizeKey + localPrivKey = localizeKey( + usmUserAuthProtocol.syntax, + pysnmpUsmKeyPriv.syntax, + securityEngineID + ) else: raise error.StatusInformation( errorIndication = errind.unsupportedPrivProtocol diff --git a/pysnmp/proto/secmod/rfc3826/priv/aes.py b/pysnmp/proto/secmod/rfc3826/priv/aes.py index 89f7460..d927577 100644 --- a/pysnmp/proto/secmod/rfc3826/priv/aes.py +++ b/pysnmp/proto/secmod/rfc3826/priv/aes.py @@ -1,5 +1,7 @@ import random, string from pysnmp.proto.secmod.rfc3414.priv import base +from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc3414 import localkey from pyasn1.type import univ from pysnmp.proto import errind, error @@ -21,6 +23,7 @@ random.seed() class Aes(base.AbstractEncryptionService): serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 4) # usmAesCfb128Protocol + keySize = 16 if version_info < (2, 3): _localInt = long(random.random()*0xffffffffffffffffL) else: @@ -73,9 +76,29 @@ class Aes(base.AbstractEncryptionService): ord(salt[7]) ] - return privKey[:16], string.join(map(chr, iv), '') + return privKey[:self.keySize], string.join(map(chr, iv), '') + def hashPassphrase(self, authProtocol, privKey): + if authProtocol == hmacmd5.HmacMd5.serviceID: + return localkey.hashPassphraseMD5(privKey) + elif authProtocol == hmacsha.HmacSha.serviceID: + return localkey.hashPassphraseSHA(privKey) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + def localizeKey(self, authProtocol, privKey, snmpEngineID): + if authProtocol == hmacmd5.HmacMd5.serviceID: + localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + elif authProtocol == hmacsha.HmacSha.serviceID: + localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + else: + raise error.ProtocolError( + 'Unknown auth protocol %s' % (authProtocol,) + ) + return localPrivKey[:16] + # 3.2.4.1 def encryptData(self, encryptKey, privParameters, dataToEncrypt): if AES is None: @@ -58,6 +58,8 @@ params.update( { 'pysnmp.proto.secmod.rfc3414.priv', 'pysnmp.proto.secmod.rfc3826', 'pysnmp.proto.secmod.rfc3826.priv', + 'pysnmp.proto.secmod.eso', + 'pysnmp.proto.secmod.eso.priv', 'pysnmp.proto.acmod', 'pysnmp.proto.proxy', 'pysnmp.proto.api' ], |