diff options
author | verrio <verri@x25.pm> | 2017-08-02 23:38:14 +0000 |
---|---|---|
committer | Ilya Etingof <etingof@gmail.com> | 2017-08-03 01:38:14 +0200 |
commit | 130bdaa6e218c95806bd571b326a5d3e2ddcb1ef (patch) | |
tree | a379ae562ecd5ee4b9cc998ae666f9f8d247db73 /pysnmp/proto | |
parent | 801d47b63222f46dd403e145f9dcff6a03dd3337 (diff) | |
download | pysnmp-git-130bdaa6e218c95806bd571b326a5d3e2ddcb1ef.tar.gz |
add support for USM SHA-2 algorithms (RFC 7860) (#71)
Diffstat (limited to 'pysnmp/proto')
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/aesbase.py | 20 | ||||
-rw-r--r-- | pysnmp/proto/secmod/eso/priv/des3.py | 22 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/base.py | 3 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py | 3 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/auth/hmacsha.py | 3 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/localkey.py | 59 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/priv/des.py | 23 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 10 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3826/priv/aes.py | 23 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc7860/__init__.py | 1 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc7860/auth/__init__.py | 1 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py | 110 |
12 files changed, 211 insertions, 67 deletions
diff --git a/pysnmp/proto/secmod/eso/priv/aesbase.py b/pysnmp/proto/secmod/eso/priv/aesbase.py index 3f8408c2..43bb724b 100644 --- a/pysnmp/proto/secmod/eso/priv/aesbase.py +++ b/pysnmp/proto/secmod/eso/priv/aesbase.py @@ -6,6 +6,7 @@ # from pysnmp.proto.secmod.rfc3826.priv import aes from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc7860.auth import hmacsha2 from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.proto import error from math import ceil @@ -64,18 +65,19 @@ class AbstractAesReeder(aes.Aes): # 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 = localkey.hashPassphraseMD5(localPrivKey) # this is the difference between reeder and bluementhal - localPrivKey += localkey.localizeKeyMD5(newKey, snmpEngineID) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) - while len(localPrivKey) < self.keySize: - newKey = localkey.hashPassphraseSHA(localPrivKey) - localPrivKey += localkey.localizeKeySHA(newKey, snmpEngineID) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) + # now extend this key if too short by repeating steps that includes the hashPassphrase step + while len(localPrivKey) < self.keySize: + # this is the difference between reeder and bluementhal + newKey = localkey.hashPassphrase(localPrivKey, hashAlgo) + localPrivKey += localkey.localizeKey(newKey, snmpEngineID, hashAlgo) return localPrivKey[:self.keySize] diff --git a/pysnmp/proto/secmod/eso/priv/des3.py b/pysnmp/proto/secmod/eso/priv/des3.py index 07e48151..16d770e9 100644 --- a/pysnmp/proto/secmod/eso/priv/des3.py +++ b/pysnmp/proto/secmod/eso/priv/des3.py @@ -8,6 +8,7 @@ import random 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 pysnmp.proto.secmod.rfc7860.auth import hmacsha2 from pysnmp.proto import errind, error from pyasn1.type import univ from pyasn1.compat.octets import null @@ -43,31 +44,30 @@ class Des3(base.AbstractEncryptionService): def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.serviceID: - return localkey.hashPassphraseMD5(privKey) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - return localkey.hashPassphraseSHA(privKey) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + return localkey.hashPassphrase(privKey, hashAlgo) # 2.1 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 = localkey.hashPassphraseMD5(localPrivKey) - localPrivKey += localkey.localizeKeyMD5(newKey, snmpEngineID) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) - while len(localPrivKey) < self.keySize: - newKey = localkey.hashPassphraseSHA(localPrivKey) - localPrivKey += localkey.localizeKeySHA(newKey, snmpEngineID) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) return localPrivKey[:self.keySize] # 5.1.1.1 diff --git a/pysnmp/proto/secmod/rfc3414/auth/base.py b/pysnmp/proto/secmod/rfc3414/auth/base.py index e412adea..133416b8 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/base.py +++ b/pysnmp/proto/secmod/rfc3414/auth/base.py @@ -15,6 +15,9 @@ class AbstractAuthenticationService(object): def localizeKey(self, authKey, snmpEngineID): raise error.ProtocolError(errind.noAuthentication) + + def getTagLen(self): + raise error.ProtocolError(errind.noAuthentication) # 7.2.4.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): diff --git a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py index 35a95b32..13b27e10 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacmd5.py @@ -32,6 +32,9 @@ class HmacMd5(base.AbstractAuthenticationService): def localizeKey(self, authKey, snmpEngineID): return localkey.localizeKeyMD5(authKey, snmpEngineID) + def getTagLen(self): + return 12 + # 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 5bc3c457..16cb2149 100644 --- a/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py +++ b/pysnmp/proto/secmod/rfc3414/auth/hmacsha.py @@ -32,6 +32,9 @@ class HmacSha(base.AbstractAuthenticationService): def localizeKey(self, authKey, snmpEngineID): return localkey.localizeKeySHA(authKey, snmpEngineID) + def getTagLen(self): + return 12 + # 7.3.1 def authenticateOutgoingMsg(self, authKey, wholeMsg): # 7.3.1.1 diff --git a/pysnmp/proto/secmod/rfc3414/localkey.py b/pysnmp/proto/secmod/rfc3414/localkey.py index beb807a0..c5105821 100644 --- a/pysnmp/proto/secmod/rfc3414/localkey.py +++ b/pysnmp/proto/secmod/rfc3414/localkey.py @@ -15,12 +15,11 @@ except ImportError: from pyasn1.type import univ -# RFC3414: A.2.1 -def hashPassphraseMD5(passphrase): +def hashPassphrase(passphrase, hashFunc): passphrase = univ.OctetString(passphrase).asOctets() # noinspection PyDeprecation,PyCallingNonCallable - md = md5() - ringBuffer = passphrase * (passphrase and (64 // len(passphrase) + 1) or 1) + hasher = hashFunc() + ringBuffer = passphrase * (64 // len(passphrase) + 1) # noinspection PyTypeChecker ringBufferLen = len(ringBuffer) count = 0 @@ -28,54 +27,40 @@ def hashPassphraseMD5(passphrase): while count < 16384: e = mark + 64 if e < ringBufferLen: - md.update(ringBuffer[mark:e]) + hasher.update(ringBuffer[mark:e]) mark = e else: - md.update( + hasher.update( ringBuffer[mark:ringBufferLen] + ringBuffer[0:e - ringBufferLen] ) mark = e - ringBufferLen count += 1 - return md.digest() + return hasher.digest() +def passwordToKey(passphrase, snmpEngineId, hashFunc): + return localizeKey(hashPassphrase(passphrase, hashFunc), snmpEngineId, hashFunc) -def localizeKeyMD5(passKey, snmpEngineId): +def localizeKey(passKey, snmpEngineId, hashFunc): passKey = univ.OctetString(passKey).asOctets() # noinspection PyDeprecation,PyCallingNonCallable - return md5(passKey + snmpEngineId.asOctets() + passKey).digest() - - -def passwordToKeyMD5(passphrase, snmpEngineId): - return localizeKeyMD5(hashPassphraseMD5(passphrase), snmpEngineId) + return hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest() +# RFC3414: A.2.1 +def hashPassphraseMD5(passphrase): + return hashPassphrase(passphrase, md5) # RFC3414: A.2.2 def hashPassphraseSHA(passphrase): - passphrase = univ.OctetString(passphrase).asOctets() - md = sha1() - ringBuffer = passphrase * (64 // len(passphrase) + 1) - # noinspection PyTypeChecker - ringBufferLen = len(ringBuffer) - count = 0 - mark = 0 - while count < 16384: - e = mark + 64 - if e < ringBufferLen: - md.update(ringBuffer[mark:e]) - mark = e - else: - md.update( - ringBuffer[mark:ringBufferLen] + ringBuffer[0:e - ringBufferLen] - ) - mark = e - ringBufferLen - count += 1 - return md.digest() + return hashPassphrase(passphrase, sha1) +def passwordToKeyMD5(passphrase, snmpEngineId): + return localizeKey(hashPassphraseMD5(passphrase), snmpEngineId, md5) -def localizeKeySHA(passKey, snmpEngineId): - passKey = univ.OctetString(passKey).asOctets() - return sha1(passKey + snmpEngineId.asOctets() + passKey).digest() +def passwordToKeySHA(passphrase, snmpEngineId): + return localizeKey(hashPassphraseMD5(passphrase), snmpEngineId, sha1) +def localizeKeyMD5(passKey, snmpEngineId): + return localizeKey(passKey, snmpEngineId, md5) -def passwordToKeySHA(passphrase, snmpEngineId): - return localizeKeySHA(hashPassphraseSHA(passphrase), snmpEngineId) +def localizeKeySHA(passKey, snmpEngineId): + return localizeKey(passKey, snmpEngineId, sha1) diff --git a/pysnmp/proto/secmod/rfc3414/priv/des.py b/pysnmp/proto/secmod/rfc3414/priv/des.py index 57f47c33..e38239ad 100644 --- a/pysnmp/proto/secmod/rfc3414/priv/des.py +++ b/pysnmp/proto/secmod/rfc3414/priv/des.py @@ -8,6 +8,7 @@ import random 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 pysnmp.proto.secmod.rfc7860.auth import hmacsha2 from pysnmp.proto import errind, error from pyasn1.type import univ from sys import version_info @@ -16,6 +17,14 @@ try: from Crypto.Cipher import DES except ImportError: DES = None +try: + from hashlib import md5, sha1 +except ImportError: + import md5 + import sha + + md5 = md5.new + sha1 = sha.new random.seed() @@ -33,23 +42,29 @@ class Des(base.AbstractEncryptionService): def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.serviceID: - return localkey.hashPassphraseMD5(privKey) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - return localkey.hashPassphraseSHA(privKey) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + return localkey.hashPassphrase(privKey, hashAlgo) def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.serviceID: - localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) return localPrivKey[:self.keySize] # 8.1.1.1 diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index 4d7500b4..d0a88c9c 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -10,6 +10,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.rfc7860.auth import hmacsha2 from pysnmp.proto.secmod.eso.priv import des3, aes192, aes256 from pysnmp.smi.error import NoSuchInstanceError from pysnmp.proto import rfc1155, errind, error @@ -40,7 +41,12 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): securityModelID = 3 authServices = {hmacmd5.HmacMd5.serviceID: hmacmd5.HmacMd5(), hmacsha.HmacSha.serviceID: hmacsha.HmacSha(), - noauth.NoAuth.serviceID: noauth.NoAuth()} + hmacsha2.HmacSha2.sha224ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha224ServiceID), + hmacsha2.HmacSha2.sha256ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha256ServiceID), + hmacsha2.HmacSha2.sha384ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha384ServiceID), + hmacsha2.HmacSha2.sha512ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha512ServiceID), + noauth.NoAuth.serviceID: noauth.NoAuth(), + } privServices = {des.Des.serviceID: des.Des(), des3.Des3.serviceID: des3.Des3(), aes.Aes.serviceID: aes.Aes(), @@ -432,7 +438,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # extra-wild hack to facilitate BER substrate in-place re-write securityParameters.setComponentByPosition( - 4, '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + 4, '\x00' * authHandler.getTagLen() ) debug.logger & debug.flagSM and debug.logger( diff --git a/pysnmp/proto/secmod/rfc3826/priv/aes.py b/pysnmp/proto/secmod/rfc3826/priv/aes.py index 06c8eb3f..734e9643 100644 --- a/pysnmp/proto/secmod/rfc3826/priv/aes.py +++ b/pysnmp/proto/secmod/rfc3826/priv/aes.py @@ -8,6 +8,7 @@ import random from pyasn1.type import univ from pysnmp.proto.secmod.rfc3414.priv import base from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha +from pysnmp.proto.secmod.rfc7860.auth import hmacsha2 from pysnmp.proto.secmod.rfc3414 import localkey from pysnmp.proto import errind, error @@ -15,6 +16,14 @@ try: from Crypto.Cipher import AES except ImportError: AES = None +try: + from hashlib import md5, sha1 +except ImportError: + import md5 + import sha + + md5 = md5.new + sha1 = sha.new random.seed() @@ -66,23 +75,29 @@ class Aes(base.AbstractEncryptionService): def hashPassphrase(self, authProtocol, privKey): if authProtocol == hmacmd5.HmacMd5.serviceID: - return localkey.hashPassphraseMD5(privKey) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - return localkey.hashPassphraseSHA(privKey) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + return localkey.hashPassphrase(privKey, hashAlgo) def localizeKey(self, authProtocol, privKey, snmpEngineID): if authProtocol == hmacmd5.HmacMd5.serviceID: - localPrivKey = localkey.localizeKeyMD5(privKey, snmpEngineID) + hashAlgo = md5 elif authProtocol == hmacsha.HmacSha.serviceID: - localPrivKey = localkey.localizeKeySHA(privKey, snmpEngineID) + hashAlgo = sha1 + elif authProtocol in hmacsha2.HmacSha2.hashAlgo: + hashAlgo = hmacsha2.HmacSha2.hashAlgo[authProtocol] else: raise error.ProtocolError( 'Unknown auth protocol %s' % (authProtocol,) ) + localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo) return localPrivKey[:self.keySize] # 3.2.4.1 diff --git a/pysnmp/proto/secmod/rfc7860/__init__.py b/pysnmp/proto/secmod/rfc7860/__init__.py new file mode 100644 index 00000000..8c3066b2 --- /dev/null +++ b/pysnmp/proto/secmod/rfc7860/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/pysnmp/proto/secmod/rfc7860/auth/__init__.py b/pysnmp/proto/secmod/rfc7860/auth/__init__.py new file mode 100644 index 00000000..8c3066b2 --- /dev/null +++ b/pysnmp/proto/secmod/rfc7860/auth/__init__.py @@ -0,0 +1 @@ +# This file is necessary to make this directory a package. diff --git a/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py b/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py new file mode 100644 index 00000000..60453c53 --- /dev/null +++ b/pysnmp/proto/secmod/rfc7860/auth/hmacsha2.py @@ -0,0 +1,110 @@ +# +# This file is part of pysnmp software. +# +# Copyright (c) 2005-2017, Olivier Verriest <verri@x25.pm> +# License: http://pysnmp.sf.net/license.html +# +try: + from hashlib import sha224, sha256, sha384, sha512 + import hmac +except ImportError: + import logging + logging.debug('SHA-2 HMAC authentication unavailable', exc_info=True) + +from pyasn1.type import univ +from pysnmp.proto.secmod.rfc3414.auth import base +from pysnmp.proto.secmod.rfc3414 import localkey +from pysnmp.proto import errind, error + +# 7.2.4 + +class HmacSha2(base.AbstractAuthenticationService): + sha224ServiceID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 4) # usmHMAC128SHA224AuthProtocol + sha256ServiceID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 5) # usmHMAC192SHA256AuthProtocol + sha384ServiceID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 6) # usmHMAC256SHA384AuthProtocol + sha512ServiceID = (1, 3, 6, 1, 6, 3, 10, 1, 1, 7) # usmHMAC384SHA512AuthProtocol + keyLength = { + sha224ServiceID : 28, + sha256ServiceID : 32, + sha384ServiceID : 48, + sha512ServiceID : 64 + } + tagLength = { + sha224ServiceID : 16, + sha256ServiceID : 24, + sha384ServiceID : 32, + sha512ServiceID : 48 + } + hashAlgo = { + sha224ServiceID : sha224, + sha256ServiceID : sha256, + sha384ServiceID : sha384, + sha512ServiceID : sha512 + } + + __ipad = [0x36] * 64 + __opad = [0x5C] * 64 + + def __init__(self, oid): + if not oid in HmacSha2.hashAlgo: + raise error.ProtocolError('no such SHA-2 authentication algorithm', oid) + self.__hashAlgo = HmacSha2.hashAlgo[oid] + self.__tagLength = HmacSha2.tagLength[oid] + self.__placeHolder = univ.OctetString((0,) * self.__tagLength).asOctets() + + def hashPassphrase(self, authKey): + return localkey.hashPassphrase(authKey, self.__hashAlgo) + + def localizeKey(self, authKey, snmpEngineID): + return localkey.localizeKey(authKey, snmpEngineID, self.__hashAlgo) + + def getTagLen(self): + return self.__tagLength + + # 7.3.1 + def authenticateOutgoingMsg(self, authKey, wholeMsg): + # 7.3.1.1 + l = wholeMsg.find(self.__placeHolder) + if l == -1: + raise error.ProtocolError('Can\'t locate digest placeholder') + wholeHead = wholeMsg[:l] + wholeTail = wholeMsg[l + self.__tagLength:] + + # 7.3.1.2, 7.3.1.3 + mac = hmac.new(authKey.asOctets(), wholeMsg, self.__hashAlgo) + + # 7.3.1.4 + mac = mac.digest()[:self.__tagLength] + + # 7.3.1.5 & 6 + return wholeHead + mac + wholeTail + + # 7.3.2 + def authenticateIncomingMsg(self, authKey, authParameters, wholeMsg): + # 7.3.2.1 & 2 + if len(authParameters) != self.__tagLength: + raise error.StatusInformation( + errorIndication=errind.authenticationError + ) + + # 7.3.2.3 + l = wholeMsg.find(authParameters.asOctets()) + if l == -1: + raise error.ProtocolError('Can\'t locate digest in wholeMsg') + wholeHead = wholeMsg[:l] + wholeTail = wholeMsg[l + self.__tagLength:] + authenticatedWholeMsg = wholeHead + self.__placeHolder + wholeTail + + # 7.3.2.4 + mac = hmac.new(authKey.asOctets(), authenticatedWholeMsg, self.__hashAlgo) + + # 7.3.2.5 + mac = mac.digest()[:self.__tagLength] + + # 7.3.2.6 + if mac != authParameters: + raise error.StatusInformation( + errorIndication=errind.authenticationFailure + ) + + return authenticatedWholeMsg |