pysnmp-sky/pysnmp/crypto/__init__.py

132 lines
4.4 KiB
Python

"""Backend-selecting cryptographic logic to allow migration to pyca/cryptography
without immediately dropping support for legacy minor Python versions.
On installation, the correct backend dependency is selected based on the Python
version. Versions that are supported by pyca/cryptography use that backend; all
other versions (currently 2.4, 2.5, 2.6, 3.2, and 3.3) fall back to Pycryptodome.
"""
from pysnmp.proto import errind, error
CRYPTOGRAPHY = 'cryptography'
CRYPTODOME = 'Cryptodome'
# Determine the available backend. Always prefer cryptography if it is available.
try:
import cryptography
backend = CRYPTOGRAPHY
except ImportError:
try:
import Cryptodome
backend = CRYPTODOME
except ImportError:
backend = None
def _cryptodome_encrypt(cipher_factory, plaintext, key, iv):
"""Use a Pycryptodome cipher factory to encrypt data.
:param cipher_factory: Factory callable that builds a Pycryptodome Cipher instance based
on the key and IV
:type cipher_factory: callable
:param bytes plaintext: Plaintext data to encrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Encrypted ciphertext
:rtype: bytes
"""
encryptor = cipher_factory(key, iv)
return encryptor.encrypt(plaintext)
def _cryptodome_decrypt(cipher_factory, ciphertext, key, iv):
"""Use a Pycryptodome cipher factory to decrypt data.
:param cipher_factory: Factory callable that builds a Pycryptodome Cipher instance based
on the key and IV
:type cipher_factory: callable
:param bytes ciphertext: Ciphertext data to decrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Decrypted plaintext
:rtype: bytes
"""
decryptor = cipher_factory(key, iv)
return decryptor.decrypt(ciphertext)
def _cryptography_encrypt(cipher_factory, plaintext, key, iv):
"""Use a cryptography cipher factory to encrypt data.
:param cipher_factory: Factory callable that builds a cryptography Cipher instance based
on the key and IV
:type cipher_factory: callable
:param bytes plaintext: Plaintext data to encrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Encrypted ciphertext
:rtype: bytes
"""
encryptor = cipher_factory(key, iv).encryptor()
return encryptor.update(plaintext) + encryptor.finalize()
def _cryptography_decrypt(cipher_factory, ciphertext, key, iv):
"""Use a cryptography cipher factory to decrypt data.
:param cipher_factory: Factory callable that builds a cryptography Cipher instance based
on the key and IV
:type cipher_factory: callable
:param bytes ciphertext: Ciphertext data to decrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Decrypted plaintext
:rtype: bytes
"""
decryptor = cipher_factory(key, iv).decryptor()
return decryptor.update(ciphertext) + decryptor.finalize()
_DECRYPT_MAP = {
CRYPTOGRAPHY: _cryptography_decrypt,
CRYPTODOME: _cryptodome_decrypt
}
_ENCRYPT_MAP = {
CRYPTOGRAPHY: _cryptography_encrypt,
CRYPTODOME: _cryptodome_encrypt
}
def generic_encrypt(cipher_factory_map, plaintext, key, iv):
"""Encrypt data using the available backend.
:param dict cipher_factory_map: Dictionary that maps the backend name to a cipher factory
callable for that backend
:param bytes plaintext: Plaintext data to encrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Encrypted ciphertext
:rtype: bytes
"""
if backend is None:
raise error.StatusInformation(
errorIndication=errind.encryptionError
)
return _ENCRYPT_MAP[backend](cipher_factory_map[backend], plaintext, key, iv)
def generic_decrypt(cipher_factory_map, ciphertext, key, iv):
"""Decrypt data using the available backend.
:param dict cipher_factory_map: Dictionary that maps the backend name to a cipher factory
callable for that backend
:param bytes ciphertext: Ciphertext data to decrypt
:param bytes key: Encryption key
:param bytes IV: Initialization vector
:returns: Decrypted plaintext
:rtype: bytes
"""
if backend is None:
raise error.StatusInformation(
errorIndication=errind.decryptionError
)
return _DECRYPT_MAP[backend](cipher_factory_map[backend], ciphertext, key, iv)