Skip to content

Commit

Permalink
Dumped pysnmpcrypto.
Browse files Browse the repository at this point in the history
  • Loading branch information
lextm committed Sep 18, 2024
1 parent a9c4968 commit 787547e
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 75 deletions.
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
Revision 7.1.4, released on Sep 17, 2024
----------------------------------------

- Dumped pysnmpcrypto dependency and bind to cryptography if presented.

Revision 7.1.3, released on Sep 15, 2024
----------------------------------------

Expand Down
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,12 @@ $ pip install pysnmp

To download and install PySNMP along with its dependencies:

<!-- Need to find an alternate location for the links to pysnmp.com -->
* [PyASN1](https://pyasn1.readthedocs.io)
* [PySMI](https://www.pysnmp.com/pysmi/) (required for MIB services only)
* Optional [pysnmpcrypto](https://github.com/etingof/pysnmpcrypto) package
whenever strong SNMPv3 encryption is desired
* If cryptography package presents strong SNMPv3 encryption is enabled

Besides the library, command-line [SNMP utilities](https://github.com/lextudio/snmpclitools)
written in pure-Python could be installed via:

```bash
$ pip install snmpclitools
```

and used in the very similar manner as conventional Net-SNMP tools:

```bash
$ snmpget.py -v3 -l authPriv -u usr-md5-des -A authkey1 -X privkey1 demo.pysnmp.com sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: Linux zeus 4.8.6.5-smp #2 SMP Sun Nov 13 14:58:11 CDT 2016 i686
```
Make sure you check out other sibling projects of PySNMP on
[the home page](https://www.pysnmp.com/).

Examples
--------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/docs/pysnmp-architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
a relatively simple way to structure and retrieve data (SNMPv1/v2c)
all the way to extensible and modularized framework that supports
strong SNMPv3 crypto (with optional pysnmpcrypto package).
strong SNMPv3 crypto (if cryptography package presents).

In the order from most ancient SNMP services to the most current ones,
what follows are different layers of PySNMP APIs:
Expand Down
49 changes: 19 additions & 30 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ include = ["docs", "tests", "examples"]
[tool.poetry.dependencies]
python = "^3.8"
pyasn1 = ">=0.4.8, !=0.5.0"
pysnmpcrypto = "^0.0.4"
pysmi = "^1.3.0"

[tool.poetry.group.dev.dependencies]
Expand All @@ -50,6 +49,7 @@ flake8-import-order = "^0.18.2"
flake8-docstrings = "^1.7.0"
flake8-rst-docstrings = "^0.3.0"
sphinx-polyversion = "^1.0.0"
cryptography = "^43.0.1"

[tool.poetry_bumpversion.file."pysnmp/__init__.py"]

Expand Down
37 changes: 28 additions & 9 deletions pysnmp/proto/secmod/eso/priv/des3.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
from pysnmp.proto.secmod.rfc3414.priv import base
from pysnmp.proto.secmod.rfc7860.auth import hmacsha2

PysnmpCryptoError = False
try:
from pysnmpcrypto import PysnmpCryptoError, des3
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.decrepit.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers import Cipher, modes
except ImportError:
PysnmpCryptoError = AttributeError
des3 = None
PysnmpCryptoError = True

random.seed()

Expand Down Expand Up @@ -112,7 +114,7 @@ def __getDecryptionKey(privKey, salt):

# 5.1.1.2
def encryptData(self, encryptKey, privParameters, dataToEncrypt):
if des3 is None:
if PysnmpCryptoError:
raise error.StatusInformation(errorIndication=errind.encryptionError)

snmpEngineBoots, snmpEngineTime, salt = privParameters
Expand All @@ -127,9 +129,10 @@ def encryptData(self, encryptKey, privParameters, dataToEncrypt):
)

try:
ciphertext = des3.encrypt(plaintext, des3Key, iv)
des3 = _cryptography_cipher(des3Key, iv).encryptor()
ciphertext = des3.update(plaintext) + des3.finalize()

except PysnmpCryptoError:
except AttributeError:
raise error.StatusInformation(
errorIndication=errind.unsupportedPrivProtocol
)
Expand All @@ -138,7 +141,7 @@ def encryptData(self, encryptKey, privParameters, dataToEncrypt):

# 5.1.1.3
def decryptData(self, decryptKey, privParameters, encryptedData):
if des3 is None:
if PysnmpCryptoError:
raise error.StatusInformation(errorIndication=errind.decryptionError)
snmpEngineBoots, snmpEngineTime, salt = privParameters

Expand All @@ -153,11 +156,27 @@ def decryptData(self, decryptKey, privParameters, encryptedData):
ciphertext = encryptedData.asOctets()

try:
plaintext = des3.decrypt(ciphertext, des3Key, iv)
des3 = _cryptography_cipher(des3Key, iv).decryptor()
plaintext = des3.update(ciphertext) + des3.finalize()

except PysnmpCryptoError:
except AttributeError:
raise error.StatusInformation(
errorIndication=errind.unsupportedPrivProtocol
)

return plaintext


def _cryptography_cipher(key, iv):
"""Build a cryptography TripleDES Cipher object.
:param bytes key: Encryption key
:param bytesiv 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(),
)
47 changes: 38 additions & 9 deletions pysnmp/proto/secmod/rfc3414/priv/des.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
from pysnmp.proto.secmod.rfc3414.priv import base
from pysnmp.proto.secmod.rfc7860.auth import hmacsha2

PysnmpCryptoError = False
try:
from pysnmpcrypto import PysnmpCryptoError, des
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.decrepit.ciphers import algorithms
from cryptography.hazmat.primitives.ciphers import Cipher, modes
except ImportError:
PysnmpCryptoError = AttributeError
des = None
PysnmpCryptoError = True

random.seed()

Expand Down Expand Up @@ -97,7 +99,7 @@ def __getDecryptionKey(privKey, salt):

# 8.2.4.1
def encryptData(self, encryptKey, privParameters, dataToEncrypt):
if des is None:
if PysnmpCryptoError:
raise error.StatusInformation(errorIndication=errind.encryptionError)

snmpEngineBoots, snmpEngineTime, salt = privParameters
Expand All @@ -115,9 +117,10 @@ def encryptData(self, encryptKey, privParameters, dataToEncrypt):
)

try:
ciphertext = des.encrypt(plaintext, desKey, iv)
des = _cryptography_cipher(desKey, iv).encryptor()
ciphertext = des.update(plaintext) + des.finalize()

except PysnmpCryptoError:
except AttributeError:
raise error.StatusInformation(
errorIndication=errind.unsupportedPrivProtocol
)
Expand All @@ -127,7 +130,7 @@ def encryptData(self, encryptKey, privParameters, dataToEncrypt):

# 8.2.4.2
def decryptData(self, decryptKey, privParameters, encryptedData):
if des is None:
if PysnmpCryptoError:
raise error.StatusInformation(errorIndication=errind.decryptionError)

snmpEngineBoots, snmpEngineTime, salt = privParameters
Expand All @@ -147,9 +150,35 @@ def decryptData(self, decryptKey, privParameters, encryptedData):

try:
# 8.3.2.6
return des.decrypt(encryptedData.asOctets(), desKey, iv)
des = _cryptography_cipher(desKey, iv).decryptor()
return des.update(encryptedData.asOctets()) + des.finalize()

except PysnmpCryptoError:
except AttributeError:
raise error.StatusInformation(
errorIndication=errind.unsupportedPrivProtocol
)


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(),
)
Loading

0 comments on commit 787547e

Please sign in to comment.