Mini Shell
#
# This file is part of pysnmp software.
#
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysnmp/license.html
#
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
try:
from Cryptodome.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()
# RFC3826
#
class Aes(base.AbstractEncryptionService):
serviceID = (1, 3, 6, 1, 6, 3, 10, 1, 2, 4) # usmAesCfb128Protocol
keySize = 16
_localInt = random.randrange(0, 0xffffffffffffffff)
# 3.1.2.1
def __getEncryptionKey(self, privKey, snmpEngineBoots, snmpEngineTime):
salt = [self._localInt >> 56 & 0xff,
self._localInt >> 48 & 0xff,
self._localInt >> 40 & 0xff,
self._localInt >> 32 & 0xff,
self._localInt >> 24 & 0xff,
self._localInt >> 16 & 0xff,
self._localInt >> 8 & 0xff,
self._localInt & 0xff]
if self._localInt == 0xffffffffffffffff:
self._localInt = 0
else:
self._localInt += 1
return self.__getDecryptionKey(privKey, snmpEngineBoots, snmpEngineTime, salt) + (
univ.OctetString(salt).asOctets(),)
def __getDecryptionKey(self, privKey, snmpEngineBoots,
snmpEngineTime, salt):
snmpEngineBoots, snmpEngineTime, salt = (
int(snmpEngineBoots), int(snmpEngineTime), salt
)
iv = [snmpEngineBoots >> 24 & 0xff,
snmpEngineBoots >> 16 & 0xff,
snmpEngineBoots >> 8 & 0xff,
snmpEngineBoots & 0xff,
snmpEngineTime >> 24 & 0xff,
snmpEngineTime >> 16 & 0xff,
snmpEngineTime >> 8 & 0xff,
snmpEngineTime & 0xff] + salt
return privKey[:self.keySize].asOctets(), univ.OctetString(iv).asOctets()
def hashPassphrase(self, authProtocol, privKey):
if authProtocol == hmacmd5.HmacMd5.serviceID:
hashAlgo = md5
elif authProtocol == hmacsha.HmacSha.serviceID:
hashAlgo = sha1
elif authProtocol in hmacsha2.HmacSha2.hashAlgorithms:
hashAlgo = hmacsha2.HmacSha2.hashAlgorithms[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:
hashAlgo = md5
elif authProtocol == hmacsha.HmacSha.serviceID:
hashAlgo = sha1
elif authProtocol in hmacsha2.HmacSha2.hashAlgorithms:
hashAlgo = hmacsha2.HmacSha2.hashAlgorithms[authProtocol]
else:
raise error.ProtocolError(
'Unknown auth protocol %s' % (authProtocol,)
)
localPrivKey = localkey.localizeKey(privKey, snmpEngineID, hashAlgo)
return localPrivKey[:self.keySize]
# 3.2.4.1
def encryptData(self, encryptKey, privParameters, dataToEncrypt):
if AES is None:
raise error.StatusInformation(
errorIndication=errind.encryptionError
)
snmpEngineBoots, snmpEngineTime, salt = privParameters
# 3.3.1.1
aesKey, iv, salt = self.__getEncryptionKey(
encryptKey, snmpEngineBoots, snmpEngineTime
)
# 3.3.1.3
aesObj = AES.new(aesKey, AES.MODE_CFB, iv, segment_size=128)
# PyCrypto seems to require padding
dataToEncrypt = dataToEncrypt + univ.OctetString((0,) * (16 - len(dataToEncrypt) % 16)).asOctets()
ciphertext = aesObj.encrypt(dataToEncrypt)
# 3.3.1.4
return univ.OctetString(ciphertext), univ.OctetString(salt)
# 3.2.4.2
def decryptData(self, decryptKey, privParameters, encryptedData):
if AES is None:
raise error.StatusInformation(
errorIndication=errind.decryptionError
)
snmpEngineBoots, snmpEngineTime, salt = privParameters
# 3.3.2.1
if len(salt) != 8:
raise error.StatusInformation(
errorIndication=errind.decryptionError
)
# 3.3.2.3
aesKey, iv = self.__getDecryptionKey(
decryptKey, snmpEngineBoots, snmpEngineTime, salt
)
aesObj = AES.new(aesKey, AES.MODE_CFB, iv, segment_size=128)
# PyCrypto seems to require padding
encryptedData = encryptedData + univ.OctetString((0,) * (16 - len(encryptedData) % 16)).asOctets()
# 3.3.2.4-6
return aesObj.decrypt(encryptedData.asOctets())
Zerion Mini Shell 1.0