strong crypto moved to pysnmpcrypto
parent
bc2654205b
commit
24a7988766
10
CHANGES.txt
10
CHANGES.txt
|
@ -1,9 +1,13 @@
|
||||||
|
|
||||||
Revision 4.?.?, released 2018-??-??
|
Revision 5.0.0, released 2018-03-??
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Crypto abstraction layer added to allow use of pyca/cryptography instead of Pycryptodome
|
- SNMPv3 crypto operations that require external dependencies
|
||||||
- Dependencies modified to use pyca/cryptography for supported Python versions
|
made dependent on the optional external
|
||||||
|
package -- pysnmpcrypto.
|
||||||
|
- By switching to pysnmpcrypto, pysnmp effectively migrates from
|
||||||
|
PyCryptodomex to pyca/cryptography whenever available on the
|
||||||
|
platform.
|
||||||
|
|
||||||
Revision 4.4.4, released 2018-01-03
|
Revision 4.4.4, released 2018-01-03
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
|
@ -57,9 +57,8 @@ to download and install PySNMP along with its dependencies:
|
||||||
|
|
||||||
* [PyASN1](http://snmplabs.com/pyasn1/)
|
* [PyASN1](http://snmplabs.com/pyasn1/)
|
||||||
* [PySMI](http://snmplabs.com/pysmi/) (required for MIB services only)
|
* [PySMI](http://snmplabs.com/pysmi/) (required for MIB services only)
|
||||||
* A supported cryptography backend (required only if SNMPv3 encryption is in use)
|
* Optional [pysnmpcrypto](https://github.com/etingof/pysnmpcrypto) package
|
||||||
* [pyca/cryptography](http://cryptography.io/) for Python 2.7 and 3.4+
|
whenever strong SNMPv3 encryption is desired
|
||||||
* [PyCryptodomex](https://pycryptodome.readthedocs.io) for Python 2.4-2.6 and 3.2-3.3
|
|
||||||
|
|
||||||
Besides the library, command-line [SNMP utilities](https://github.com/etingof/snmpclitools)
|
Besides the library, command-line [SNMP utilities](https://github.com/etingof/snmpclitools)
|
||||||
written in pure-Python could be installed via:
|
written in pure-Python could be installed via:
|
||||||
|
|
|
@ -30,5 +30,6 @@ Laurelin of Middle Earth
|
||||||
Robert Reese
|
Robert Reese
|
||||||
Olivier Verriest
|
Olivier Verriest
|
||||||
Eugene M. Kim
|
Eugene M. Kim
|
||||||
|
Matt Bullock
|
||||||
Thanks to Python Software Foundation for granting financial support
|
Thanks to Python Software Foundation for granting financial support
|
||||||
for the project.
|
for the project.
|
||||||
|
|
|
@ -9,7 +9,7 @@ We can look at PySNMP's internal structure from the view point of
|
||||||
SNMP protocol evolution. SNMP was evolving for many years from
|
SNMP protocol evolution. SNMP was evolving for many years from
|
||||||
a relatively simple way to structure and retrieve data (SNMPv1/v2c)
|
a relatively simple way to structure and retrieve data (SNMPv1/v2c)
|
||||||
all the way to extensible and modularized framework that supports
|
all the way to extensible and modularized framework that supports
|
||||||
strong crypto out-of-the-box (SNMPv3).
|
strong SNMPv3 crypto (with optional pysnmpcrypto package).
|
||||||
|
|
||||||
In the order from most ancient SNMP services to the most current ones,
|
In the order from most ancient SNMP services to the most current ones,
|
||||||
what follows are different layers of PySNMP APIs:
|
what follows are different layers of PySNMP APIs:
|
||||||
|
|
|
@ -42,19 +42,16 @@ In case you are installing PySNMP on an off-line system, the following
|
||||||
packages need to be downloaded and installed for PySNMP to become
|
packages need to be downloaded and installed for PySNMP to become
|
||||||
operational:
|
operational:
|
||||||
|
|
||||||
* `PyASN1 <https://pypi.python.org/pypi/pyasn1>`_,
|
* `pysnmp <https://pypi.python.org/pypi/pysnmp/>`_,
|
||||||
used for handling ASN.1 objects
|
|
||||||
* `PySNMP <https://pypi.python.org/pypi/pysnmp/>`_,
|
|
||||||
SNMP engine implementation
|
SNMP engine implementation
|
||||||
|
* `pyasn1 <https://pypi.python.org/pypi/pyasn1>`_,
|
||||||
Optional, but recommended:
|
used for handling ASN.1 objects
|
||||||
|
* `pysmi <https://pypi.python.org/pypi/pysmi/>`_ for automatic
|
||||||
* `PyCryptodomex <https://pypi.python.org/pypi/pycryptodomex/>`_,
|
|
||||||
used by SNMPv3 crypto features
|
|
||||||
* `PySMI <https://pypi.python.org/pypi/pysmi/>`_ for automatic
|
|
||||||
MIB download and compilation. That helps visualizing more SNMP objects
|
MIB download and compilation. That helps visualizing more SNMP objects
|
||||||
* `Ply <https://pypi.python.org/pypi/ply/>`_, parser generator
|
|
||||||
required by PySMI
|
Optional:
|
||||||
|
* `pysnmpcrypto <https://pypi.python.org/pypi/pysnmpcrypto/>`_,
|
||||||
|
for strong SNMPv3 crypto support
|
||||||
|
|
||||||
The installation procedure for all the above packages is as follows
|
The installation procedure for all the above packages is as follows
|
||||||
(on UNIX-based systems):
|
(on UNIX-based systems):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# http://www.python.org/dev/peps/pep-0396/
|
# http://www.python.org/dev/peps/pep-0396/
|
||||||
__version__ = '4.4.4'
|
__version__ = '5.0.0'
|
||||||
# backward compatibility
|
# backward compatibility
|
||||||
version = tuple([int(x) for x in __version__.split('.')])
|
version = tuple([int(x) for x in __version__.split('.')])
|
||||||
majorVersionId = version[0]
|
majorVersionId = version[0]
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
"""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)
|
|
|
@ -1,67 +0,0 @@
|
||||||
"""
|
|
||||||
Crypto logic for RFC3826.
|
|
||||||
|
|
||||||
https://tools.ietf.org/html/rfc3826
|
|
||||||
"""
|
|
||||||
from pysnmp.crypto import backend, CRYPTODOME, CRYPTOGRAPHY, generic_decrypt, generic_encrypt
|
|
||||||
|
|
||||||
if backend == CRYPTOGRAPHY:
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
|
|
||||||
elif backend == CRYPTODOME:
|
|
||||||
from Cryptodome.Cipher import AES
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptodome_cipher(key, iv):
|
|
||||||
"""Build a Pycryptodome AES Cipher object.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: AES Cipher instance
|
|
||||||
"""
|
|
||||||
return AES.new(key, AES.MODE_CFB, iv, segment_size=128)
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptography_cipher(key, iv):
|
|
||||||
"""Build a cryptography AES Cipher object.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: AES Cipher instance
|
|
||||||
:rtype: cryptography.hazmat.primitives.ciphers.Cipher
|
|
||||||
"""
|
|
||||||
return Cipher(
|
|
||||||
algorithm=algorithms.AES(key),
|
|
||||||
mode=modes.CFB(iv),
|
|
||||||
backend=default_backend()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_CIPHER_FACTORY_MAP = {
|
|
||||||
CRYPTOGRAPHY: _cryptography_cipher,
|
|
||||||
CRYPTODOME: _cryptodome_cipher
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(plaintext, key, iv):
|
|
||||||
"""Encrypt data using AES on the available backend.
|
|
||||||
|
|
||||||
:param bytes plaintext: Plaintext data to encrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Encrypted ciphertext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_encrypt(_CIPHER_FACTORY_MAP, plaintext, key, iv)
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(ciphertext, key, iv):
|
|
||||||
"""Decrypt data using AES on the available backend.
|
|
||||||
|
|
||||||
:param bytes ciphertext: Ciphertext data to decrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Decrypted plaintext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_decrypt(_CIPHER_FACTORY_MAP, ciphertext, key, iv)
|
|
|
@ -1,74 +0,0 @@
|
||||||
"""
|
|
||||||
Crypto logic for RFC3414.
|
|
||||||
|
|
||||||
https://tools.ietf.org/html/rfc3414
|
|
||||||
"""
|
|
||||||
from pysnmp.crypto import backend, CRYPTODOME, CRYPTOGRAPHY, generic_decrypt, generic_encrypt
|
|
||||||
|
|
||||||
if backend == CRYPTOGRAPHY:
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
|
|
||||||
elif backend == CRYPTODOME:
|
|
||||||
from Cryptodome.Cipher import DES
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptodome_cipher(key, iv):
|
|
||||||
"""Build a Pycryptodome DES Cipher object.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: DES Cipher instance
|
|
||||||
"""
|
|
||||||
return DES.new(key, DES.MODE_CBC, iv)
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptography_cipher(key, iv):
|
|
||||||
"""Build a cryptography DES(-like) Cipher object.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
pyca/cryptography does not support DES directly because it is a seriously old, insecure,
|
|
||||||
and deprecated algorithm. However, triple DES is just three rounds of DES (encrypt,
|
|
||||||
decrypt, encrypt) done by taking a key three times the size of a DES key and breaking
|
|
||||||
it into three pieces. So triple DES with des_key * 3 is equivalent to DES.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: TripleDES Cipher instance providing DES behavior by using provided DES key
|
|
||||||
:rtype: cryptography.hazmat.primitives.ciphers.Cipher
|
|
||||||
"""
|
|
||||||
return Cipher(
|
|
||||||
algorithm=algorithms.TripleDES(key * 3),
|
|
||||||
mode=modes.CBC(iv),
|
|
||||||
backend=default_backend()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_CIPHER_FACTORY_MAP = {
|
|
||||||
CRYPTOGRAPHY: _cryptography_cipher,
|
|
||||||
CRYPTODOME: _cryptodome_cipher
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(plaintext, key, iv):
|
|
||||||
"""Encrypt data using DES on the available backend.
|
|
||||||
|
|
||||||
:param bytes plaintext: Plaintext data to encrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Encrypted ciphertext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_encrypt(_CIPHER_FACTORY_MAP, plaintext, key, iv)
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(ciphertext, key, iv):
|
|
||||||
"""Decrypt data using DES on the available backend.
|
|
||||||
|
|
||||||
:param bytes ciphertext: Ciphertext data to decrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Decrypted plaintext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_decrypt(_CIPHER_FACTORY_MAP, ciphertext, key, iv)
|
|
|
@ -1,67 +0,0 @@
|
||||||
"""
|
|
||||||
Crypto logic for Reeder 3DES-EDE for USM (Internet draft).
|
|
||||||
|
|
||||||
https://tools.ietf.org/html/draft-reeder-snmpv3-usm-3desede-00
|
|
||||||
"""
|
|
||||||
from pysnmp.crypto import backend, CRYPTODOME, CRYPTOGRAPHY, generic_decrypt, generic_encrypt
|
|
||||||
|
|
||||||
if backend == CRYPTOGRAPHY:
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
from cryptography.hazmat.primitives.ciphers import algorithms, Cipher, modes
|
|
||||||
elif backend == CRYPTODOME:
|
|
||||||
from Cryptodome.Cipher import DES3
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptodome_cipher(key, iv):
|
|
||||||
"""Build a Pycryptodome DES3 Cipher object.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: DES3 Cipher instance
|
|
||||||
"""
|
|
||||||
return DES3.new(key, DES3.MODE_CBC, iv)
|
|
||||||
|
|
||||||
|
|
||||||
def _cryptography_cipher(key, iv):
|
|
||||||
"""Build a cryptography TripleDES Cipher object.
|
|
||||||
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: TripleDES Cipher instance
|
|
||||||
:rtype: cryptography.hazmat.primitives.ciphers.Cipher
|
|
||||||
"""
|
|
||||||
return Cipher(
|
|
||||||
algorithm=algorithms.TripleDES(key),
|
|
||||||
mode=modes.CBC(iv),
|
|
||||||
backend=default_backend()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
_CIPHER_FACTORY_MAP = {
|
|
||||||
CRYPTOGRAPHY: _cryptography_cipher,
|
|
||||||
CRYPTODOME: _cryptodome_cipher
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(plaintext, key, iv):
|
|
||||||
"""Encrypt data using triple DES on the available backend.
|
|
||||||
|
|
||||||
:param bytes plaintext: Plaintext data to encrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Encrypted ciphertext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_encrypt(_CIPHER_FACTORY_MAP, plaintext, key, iv)
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(ciphertext, key, iv):
|
|
||||||
"""Decrypt data using triple DES on the available backend.
|
|
||||||
|
|
||||||
:param bytes ciphertext: Ciphertext data to decrypt
|
|
||||||
:param bytes key: Encryption key
|
|
||||||
:param bytes IV: Initialization vector
|
|
||||||
:returns: Decrypted plaintext
|
|
||||||
:rtype: bytes
|
|
||||||
"""
|
|
||||||
return generic_decrypt(_CIPHER_FACTORY_MAP, ciphertext, key, iv)
|
|
|
@ -175,13 +175,13 @@ authenticationFailure = AuthenticationFailure('Authenticator mismatched')
|
||||||
class UnsupportedAuthProtocol(ErrorIndication):
|
class UnsupportedAuthProtocol(ErrorIndication):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
unsupportedAuthProtocol = UnsupportedAuthProtocol('Authentication protocol is not supprted')
|
unsupportedAuthProtocol = UnsupportedAuthProtocol('Authentication protocol is not supported')
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedPrivProtocol(ErrorIndication):
|
class UnsupportedPrivProtocol(ErrorIndication):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
unsupportedPrivProtocol = UnsupportedPrivProtocol('Privacy protocol is not supprted')
|
unsupportedPrivProtocol = UnsupportedPrivProtocol('Privacy protocol is not supported')
|
||||||
|
|
||||||
|
|
||||||
class UnknownSecurityName(ErrorIndication):
|
class UnknownSecurityName(ErrorIndication):
|
||||||
|
|
|
@ -5,15 +5,6 @@
|
||||||
# License: http://snmplabs.com/pysnmp/license.html
|
# License: http://snmplabs.com/pysnmp/license.html
|
||||||
#
|
#
|
||||||
import random
|
import random
|
||||||
from pysnmp.crypto import des3
|
|
||||||
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
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from hashlib import md5, sha1
|
from hashlib import md5, sha1
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -23,6 +14,21 @@ except ImportError:
|
||||||
md5 = md5.new
|
md5 = md5.new
|
||||||
sha1 = sha.new
|
sha1 = sha.new
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pysnmpcrypto import des3, PysnmpCryptoError
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
PysnmpCryptoError = AttributeError
|
||||||
|
des3 = None
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,7 +123,14 @@ class Des3(base.AbstractEncryptionService):
|
||||||
privParameters = univ.OctetString(salt)
|
privParameters = univ.OctetString(salt)
|
||||||
|
|
||||||
plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets()
|
plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets()
|
||||||
ciphertext = des3.encrypt(plaintext, des3Key, iv)
|
|
||||||
|
try:
|
||||||
|
ciphertext = des3.encrypt(plaintext, des3Key, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
||||||
return univ.OctetString(ciphertext), privParameters
|
return univ.OctetString(ciphertext), privParameters
|
||||||
|
|
||||||
|
@ -138,6 +151,13 @@ class Des3(base.AbstractEncryptionService):
|
||||||
)
|
)
|
||||||
|
|
||||||
ciphertext = encryptedData.asOctets()
|
ciphertext = encryptedData.asOctets()
|
||||||
plaintext = des3.decrypt(ciphertext, des3Key, iv)
|
|
||||||
|
try:
|
||||||
|
plaintext = des3.decrypt(ciphertext, des3Key, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
||||||
return plaintext
|
return plaintext
|
||||||
|
|
|
@ -5,15 +5,6 @@
|
||||||
# License: http://snmplabs.com/pysnmp/license.html
|
# License: http://snmplabs.com/pysnmp/license.html
|
||||||
#
|
#
|
||||||
import random
|
import random
|
||||||
from pysnmp.crypto import des
|
|
||||||
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
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from hashlib import md5, sha1
|
from hashlib import md5, sha1
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -23,6 +14,22 @@ except ImportError:
|
||||||
md5 = md5.new
|
md5 = md5.new
|
||||||
sha1 = sha.new
|
sha1 = sha.new
|
||||||
|
|
||||||
|
from sys import version_info
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pysnmpcrypto import des, PysnmpCryptoError
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
PysnmpCryptoError = AttributeError
|
||||||
|
des = None
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,7 +114,14 @@ class Des(base.AbstractEncryptionService):
|
||||||
|
|
||||||
# 8.1.1.2
|
# 8.1.1.2
|
||||||
plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets()
|
plaintext = dataToEncrypt + univ.OctetString((0,) * (8 - len(dataToEncrypt) % 8)).asOctets()
|
||||||
ciphertext = des.encrypt(plaintext, desKey, iv)
|
|
||||||
|
try:
|
||||||
|
ciphertext = des.encrypt(plaintext, desKey, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
||||||
# 8.3.1.3 & 4
|
# 8.3.1.3 & 4
|
||||||
return univ.OctetString(ciphertext), privParameters
|
return univ.OctetString(ciphertext), privParameters
|
||||||
|
@ -133,5 +147,11 @@ class Des(base.AbstractEncryptionService):
|
||||||
errorIndication=errind.decryptionError
|
errorIndication=errind.decryptionError
|
||||||
)
|
)
|
||||||
|
|
||||||
# 8.3.2.6
|
try:
|
||||||
return des.decrypt(encryptedData.asOctets(), desKey, iv)
|
# 8.3.2.6
|
||||||
|
return des.decrypt(encryptedData.asOctets(), desKey, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
|
@ -5,14 +5,6 @@
|
||||||
# License: http://snmplabs.com/pysnmp/license.html
|
# License: http://snmplabs.com/pysnmp/license.html
|
||||||
#
|
#
|
||||||
import random
|
import random
|
||||||
from pyasn1.type import univ
|
|
||||||
from pysnmp.crypto import aes
|
|
||||||
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:
|
try:
|
||||||
from hashlib import md5, sha1
|
from hashlib import md5, sha1
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -22,6 +14,20 @@ except ImportError:
|
||||||
md5 = md5.new
|
md5 = md5.new
|
||||||
sha1 = sha.new
|
sha1 = sha.new
|
||||||
|
|
||||||
|
try:
|
||||||
|
from pysnmpcrypto import aes, PysnmpCryptoError
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
PysnmpCryptoError = AttributeError
|
||||||
|
aes = None
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,7 +116,13 @@ class Aes(base.AbstractEncryptionService):
|
||||||
# PyCrypto seems to require padding
|
# PyCrypto seems to require padding
|
||||||
dataToEncrypt = dataToEncrypt + univ.OctetString((0,) * (16 - len(dataToEncrypt) % 16)).asOctets()
|
dataToEncrypt = dataToEncrypt + univ.OctetString((0,) * (16 - len(dataToEncrypt) % 16)).asOctets()
|
||||||
|
|
||||||
ciphertext = aes.encrypt(dataToEncrypt, aesKey, iv)
|
try:
|
||||||
|
ciphertext = aes.encrypt(dataToEncrypt, aesKey, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
||||||
# 3.3.1.4
|
# 3.3.1.4
|
||||||
return univ.OctetString(ciphertext), univ.OctetString(salt)
|
return univ.OctetString(ciphertext), univ.OctetString(salt)
|
||||||
|
@ -133,5 +145,11 @@ class Aes(base.AbstractEncryptionService):
|
||||||
# PyCrypto seems to require padding
|
# PyCrypto seems to require padding
|
||||||
encryptedData = encryptedData + univ.OctetString((0,) * (16 - len(encryptedData) % 16)).asOctets()
|
encryptedData = encryptedData + univ.OctetString((0,) * (16 - len(encryptedData) % 16)).asOctets()
|
||||||
|
|
||||||
# 3.3.2.4-6
|
try:
|
||||||
return aes.decrypt(encryptedData.asOctets(), aesKey, iv)
|
# 3.3.2.4-6
|
||||||
|
return aes.decrypt(encryptedData.asOctets(), aesKey, iv)
|
||||||
|
|
||||||
|
except PysnmpCryptoError:
|
||||||
|
raise error.StatusInformation(
|
||||||
|
errorIndication=errind.unsupportedPrivProtocol
|
||||||
|
)
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
pysmi
|
pysmi
|
||||||
pycryptodomex; python_version < '2.7'
|
|
||||||
cryptography; python_version == '2.7'
|
|
||||||
pycryptodomex; python_version == '3.2'
|
|
||||||
pycryptodomex; python_version == '3.3'
|
|
||||||
cryptography; python_version >= '3.4'
|
|
||||||
pyasn1>=0.2.3
|
pyasn1>=0.2.3
|
||||||
ordereddict; python_version < '2.7'
|
ordereddict; python_version < '2.7'
|
||||||
|
|
8
setup.py
8
setup.py
|
@ -55,12 +55,7 @@ if py_version < (2, 4):
|
||||||
print("ERROR: this package requires Python 2.4 or later!")
|
print("ERROR: this package requires Python 2.4 or later!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if py_version < (2, 7) or (py_version >= (3, 0) and py_version < (3, 4)):
|
requires = ['pyasn1>=0.2.3', 'pysmi']
|
||||||
crypto_lib = 'pycryptodomex'
|
|
||||||
else:
|
|
||||||
crypto_lib = 'cryptography'
|
|
||||||
|
|
||||||
requires = ['pyasn1>=0.2.3', 'pysmi', crypto_lib]
|
|
||||||
|
|
||||||
if py_version < (2, 7):
|
if py_version < (2, 7):
|
||||||
requires.append('ordereddict')
|
requires.append('ordereddict')
|
||||||
|
@ -112,7 +107,6 @@ params.update({
|
||||||
'pysnmp.carrier.twisted.dgram',
|
'pysnmp.carrier.twisted.dgram',
|
||||||
'pysnmp.carrier.asyncio',
|
'pysnmp.carrier.asyncio',
|
||||||
'pysnmp.carrier.asyncio.dgram',
|
'pysnmp.carrier.asyncio.dgram',
|
||||||
'pysnmp.crypto',
|
|
||||||
'pysnmp.entity',
|
'pysnmp.entity',
|
||||||
'pysnmp.entity.rfc3413',
|
'pysnmp.entity.rfc3413',
|
||||||
'pysnmp.entity.rfc3413.oneliner',
|
'pysnmp.entity.rfc3413.oneliner',
|
||||||
|
|
Loading…
Reference in New Issue