Add Cryptodome to blacklist and weak ciphers/hash
As stated in the bug, the PyCryptodomex package reintroduces PyCrypto, but with a different namespace. Therefore Bandit should also include Cryptodome in its checks. Change-Id: I6a02f97747420cedfb4523917ea0083ed5792d7a Closes-Bug: #1655975
This commit is contained in:
parent
17c737a391
commit
d4e213445a
@ -64,6 +64,9 @@ Use of insecure MD2, MD4, or MD5 hash function.
|
||||
| | | - Crypto.Hash.MD2.new | |
|
||||
| | | - Crypto.Hash.MD4.new | |
|
||||
| | | - Crypto.Hash.MD5.new | |
|
||||
| | | - Cryptodome.Hash.MD2.new | |
|
||||
| | | - Cryptodome.Hash.MD4.new | |
|
||||
| | | - Cryptodome.Hash.MD5.new | |
|
||||
| | | - cryptography.hazmat.primitives | |
|
||||
| | | .hashes.MD5 | |
|
||||
+------+---------------------+------------------------------------+-----------+
|
||||
@ -82,6 +85,11 @@ as AES.
|
||||
| | | - Crypto.Cipher.Blowfish.new | |
|
||||
| | | - Crypto.Cipher.DES.new | |
|
||||
| | | - Crypto.Cipher.XOR.new | |
|
||||
| | | - Cryptodome.Cipher.ARC2.new | |
|
||||
| | | - Cryptodome.Cipher.ARC4.new | |
|
||||
| | | - Cryptodome.Cipher.Blowfish.new | |
|
||||
| | | - Cryptodome.Cipher.DES.new | |
|
||||
| | | - Cryptodome.Cipher.XOR.new | |
|
||||
| | | - cryptography.hazmat.primitives | |
|
||||
| | | .ciphers.algorithms.ARC4 | |
|
||||
| | | - cryptography.hazmat.primitives | |
|
||||
@ -313,6 +321,9 @@ def gen_blacklist():
|
||||
'Crypto.Hash.MD2.new',
|
||||
'Crypto.Hash.MD4.new',
|
||||
'Crypto.Hash.MD5.new',
|
||||
'Cryptodome.Hash.MD2.new',
|
||||
'Cryptodome.Hash.MD4.new',
|
||||
'Cryptodome.Hash.MD5.new',
|
||||
'cryptography.hazmat.primitives.hashes.MD5'],
|
||||
'Use of insecure MD2, MD4, or MD5 hash function.'
|
||||
))
|
||||
@ -324,6 +335,11 @@ def gen_blacklist():
|
||||
'Crypto.Cipher.Blowfish.new',
|
||||
'Crypto.Cipher.DES.new',
|
||||
'Crypto.Cipher.XOR.new',
|
||||
'Cryptodome.Cipher.ARC2.new',
|
||||
'Cryptodome.Cipher.ARC4.new',
|
||||
'Cryptodome.Cipher.Blowfish.new',
|
||||
'Cryptodome.Cipher.DES.new',
|
||||
'Cryptodome.Cipher.XOR.new',
|
||||
'cryptography.hazmat.primitives.ciphers.algorithms.ARC4',
|
||||
'cryptography.hazmat.primitives.ciphers.algorithms.Blowfish',
|
||||
'cryptography.hazmat.primitives.ciphers.algorithms.IDEA'],
|
||||
|
@ -106,6 +106,8 @@ def _weak_crypto_key_size_pycrypto(context):
|
||||
func_key_type = {
|
||||
'Crypto.PublicKey.DSA.generate': 'DSA',
|
||||
'Crypto.PublicKey.RSA.generate': 'RSA',
|
||||
'Cryptodome.PublicKey.DSA.generate': 'DSA',
|
||||
'Cryptodome.PublicKey.RSA.generate': 'RSA',
|
||||
}
|
||||
key_type = func_key_type.get(context.call_function_name_qual)
|
||||
if key_type:
|
||||
|
@ -1,8 +1,13 @@
|
||||
from Crypto.Cipher import ARC2
|
||||
from Crypto.Cipher import ARC4
|
||||
from Crypto.Cipher import Blowfish
|
||||
from Crypto.Cipher import DES
|
||||
from Crypto.Cipher import XOR
|
||||
from Crypto.Cipher import ARC2 as pycrypto_arc2
|
||||
from Crypto.Cipher import ARC4 as pycrypto_arc4
|
||||
from Crypto.Cipher import Blowfish as pycrypto_blowfish
|
||||
from Crypto.Cipher import DES as pycrypto_des
|
||||
from Crypto.Cipher import XOR as pycrypto_xor
|
||||
from Cryptodome.Cipher import ARC2 as pycryptodomex_arc2
|
||||
from Cryptodome.Cipher import ARC4 as pycryptodomex_arc4
|
||||
from Cryptodome.Cipher import Blowfish as pycryptodomex_blowfish
|
||||
from Cryptodome.Cipher import DES as pycryptodomex_des
|
||||
from Cryptodome.Cipher import XOR as pycryptodomex_xor
|
||||
from Crypto.Hash import SHA
|
||||
from Crypto import Random
|
||||
from Crypto.Util import Counter
|
||||
@ -13,36 +18,49 @@ from cryptography.hazmat.backends import default_backend
|
||||
from struct import pack
|
||||
|
||||
key = b'Sixteen byte key'
|
||||
iv = Random.new().read(ARC2.block_size)
|
||||
cipher = ARC2.new(key, ARC2.MODE_CFB, iv)
|
||||
iv = Random.new().read(pycrypto_arc2.block_size)
|
||||
cipher = pycrypto_arc2.new(key, pycrypto_arc2.MODE_CFB, iv)
|
||||
msg = iv + cipher.encrypt(b'Attack at dawn')
|
||||
cipher = pycryptodomex_arc2.new(key, pycryptodomex_arc2.MODE_CFB, iv)
|
||||
msg = iv + cipher.encrypt(b'Attack at dawn')
|
||||
|
||||
key = b'Very long and confidential key'
|
||||
nonce = Random.new().read(16)
|
||||
tempkey = SHA.new(key+nonce).digest()
|
||||
cipher = ARC4.new(tempkey)
|
||||
cipher = pycrypto_arc4.new(tempkey)
|
||||
msg = nonce + cipher.encrypt(b'Open the pod bay doors, HAL')
|
||||
cipher = pycryptodomex_arc4.new(tempkey)
|
||||
msg = nonce + cipher.encrypt(b'Open the pod bay doors, HAL')
|
||||
|
||||
bs = Blowfish.block_size
|
||||
key = b'An arbitrarily long key'
|
||||
iv = Random.new().read(bs)
|
||||
cipher = Blowfish.new(key, Blowfish.MODE_CBC, iv)
|
||||
key = b'An arbitrarily long key'
|
||||
plaintext = b'docendo discimus '
|
||||
plen = bs - divmod(len(plaintext),bs)[1]
|
||||
padding = [plen]*plen
|
||||
padding = pack('b'*plen, *padding)
|
||||
bs = pycrypto_blowfish.block_size
|
||||
cipher = pycrypto_blowfish.new(key, pycrypto_blowfish.MODE_CBC, iv)
|
||||
msg = iv + cipher.encrypt(plaintext + padding)
|
||||
bs = pycryptodomex_blowfish.block_size
|
||||
cipher = pycryptodomex_blowfish.new(key, pycryptodomex_blowfish.MODE_CBC, iv)
|
||||
msg = iv + cipher.encrypt(plaintext + padding)
|
||||
|
||||
key = b'-8B key-'
|
||||
nonce = Random.new().read(DES.block_size/2)
|
||||
ctr = Counter.new(DES.block_size*8/2, prefix=nonce)
|
||||
cipher = DES.new(key, DES.MODE_CTR, counter=ctr)
|
||||
plaintext = b'We are no longer the knights who say ni!'
|
||||
nonce = Random.new().read(pycrypto_des.block_size/2)
|
||||
ctr = Counter.new(pycrypto_des.block_size*8/2, prefix=nonce)
|
||||
cipher = pycrypto_des.new(key, pycrypto_des.MODE_CTR, counter=ctr)
|
||||
msg = nonce + cipher.encrypt(plaintext)
|
||||
nonce = Random.new().read(pycryptodomex_des.block_size/2)
|
||||
ctr = Counter.new(pycryptodomex_des.block_size*8/2, prefix=nonce)
|
||||
cipher = pycryptodomex_des.new(key, pycryptodomex_des.MODE_CTR, counter=ctr)
|
||||
msg = nonce + cipher.encrypt(plaintext)
|
||||
|
||||
key = b'Super secret key'
|
||||
cipher = XOR.new(key)
|
||||
plaintext = b'Encrypt me'
|
||||
cipher = pycrypto_xor.new(key)
|
||||
msg = cipher.encrypt(plaintext)
|
||||
cipher = pycryptodomex_xor.new(key)
|
||||
msg = cipher.encrypt(plaintext)
|
||||
|
||||
cipher = Cipher(algorithms.ARC4(key), mode=None, backend=default_backend())
|
||||
|
@ -2,6 +2,9 @@ from cryptography.hazmat.primitives import hashes
|
||||
from Crypto.Hash import MD2 as pycrypto_md2
|
||||
from Crypto.Hash import MD4 as pycrypto_md4
|
||||
from Crypto.Hash import MD5 as pycrypto_md5
|
||||
from Cryptodome.Hash import MD2 as pycryptodomex_md2
|
||||
from Cryptodome.Hash import MD4 as pycryptodomex_md4
|
||||
from Cryptodome.Hash import MD5 as pycryptodomex_md5
|
||||
import hashlib
|
||||
|
||||
hashlib.md5(1)
|
||||
@ -15,4 +18,8 @@ pycrypto_md2.new()
|
||||
pycrypto_md4.new()
|
||||
pycrypto_md5.new()
|
||||
|
||||
pycryptodomex_md2.new()
|
||||
pycryptodomex_md4.new()
|
||||
pycryptodomex_md5.new()
|
||||
|
||||
hashes.MD5()
|
||||
|
@ -2,8 +2,10 @@ from cryptography.hazmat import backends
|
||||
from cryptography.hazmat.primitives.asymmetric import dsa
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from Crypto.PublicKey import DSA
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.PublicKey import DSA as pycrypto_dsa
|
||||
from Crypto.PublicKey import RSA as pycrypto_rsa
|
||||
from Cryptodome.PublicKey import DSA as pycryptodomex_dsa
|
||||
from Cryptodome.PublicKey import RSA as pycryptodomex_rsa
|
||||
|
||||
|
||||
# Correct
|
||||
@ -14,8 +16,10 @@ ec.generate_private_key(curve=ec.SECP384R1,
|
||||
rsa.generate_private_key(public_exponent=65537,
|
||||
key_size=2048,
|
||||
backend=backends.default_backend())
|
||||
DSA.generate(bits=2048)
|
||||
RSA.generate(bits=2048)
|
||||
pycrypto_dsa.generate(bits=2048)
|
||||
pycrypto_rsa.generate(bits=2048)
|
||||
pycryptodomex_dsa.generate(bits=2048)
|
||||
pycryptodomex_rsa.generate(bits=2048)
|
||||
|
||||
# Also correct: without keyword args
|
||||
dsa.generate_private_key(4096,
|
||||
@ -25,8 +29,10 @@ ec.generate_private_key(ec.SECP256K1,
|
||||
rsa.generate_private_key(3,
|
||||
4096,
|
||||
backends.default_backend())
|
||||
DSA.generate(4096)
|
||||
RSA.generate(4096)
|
||||
pycrypto_dsa.generate(4096)
|
||||
pycrypto_rsa.generate(4096)
|
||||
pycryptodomex_dsa.generate(4096)
|
||||
pycryptodomex_rsa.generate(4096)
|
||||
|
||||
# Incorrect: weak key sizes
|
||||
dsa.generate_private_key(key_size=1024,
|
||||
@ -36,8 +42,10 @@ ec.generate_private_key(curve=ec.SECT163R2,
|
||||
rsa.generate_private_key(public_exponent=65537,
|
||||
key_size=1024,
|
||||
backend=backends.default_backend())
|
||||
DSA.generate(bits=1024)
|
||||
RSA.generate(bits=1024)
|
||||
pycrypto_dsa.generate(bits=1024)
|
||||
pycrypto_rsa.generate(bits=1024)
|
||||
pycryptodomex_dsa.generate(bits=1024)
|
||||
pycryptodomex_rsa.generate(bits=1024)
|
||||
|
||||
# Also incorrect: without keyword args
|
||||
dsa.generate_private_key(512,
|
||||
@ -47,8 +55,10 @@ ec.generate_private_key(ec.SECT163R2,
|
||||
rsa.generate_private_key(3,
|
||||
512,
|
||||
backends.default_backend())
|
||||
DSA.generate(512)
|
||||
RSA.generate(512)
|
||||
pycrypto_dsa.generate(512)
|
||||
pycrypto_rsa.generate(512)
|
||||
pycryptodomex_dsa.generate(512)
|
||||
pycryptodomex_rsa.generate(512)
|
||||
|
||||
# Don't crash when the size is variable
|
||||
rsa.generate_private_key(public_exponent=65537,
|
||||
|
@ -113,14 +113,14 @@ class FunctionalTests(testtools.TestCase):
|
||||
|
||||
def test_crypto_md5(self):
|
||||
'''Test the `hashlib.md5` example.'''
|
||||
expect = {'SEVERITY': {'MEDIUM': 8},
|
||||
'CONFIDENCE': {'HIGH': 8}}
|
||||
expect = {'SEVERITY': {'MEDIUM': 11},
|
||||
'CONFIDENCE': {'HIGH': 11}}
|
||||
self.check_example('crypto-md5.py', expect)
|
||||
|
||||
def test_ciphers(self):
|
||||
'''Test the `Crypto.Cipher` example.'''
|
||||
expect = {'SEVERITY': {'HIGH': 8},
|
||||
'CONFIDENCE': {'HIGH': 8}}
|
||||
expect = {'SEVERITY': {'HIGH': 13},
|
||||
'CONFIDENCE': {'HIGH': 13}}
|
||||
self.check_example('ciphers.py', expect)
|
||||
|
||||
def test_cipher_modes(self):
|
||||
@ -465,8 +465,8 @@ class FunctionalTests(testtools.TestCase):
|
||||
def test_weak_cryptographic_key(self):
|
||||
'''Test for weak key sizes.'''
|
||||
expect = {
|
||||
'SEVERITY': {'MEDIUM': 6, 'HIGH': 4},
|
||||
'CONFIDENCE': {'HIGH': 10}
|
||||
'SEVERITY': {'MEDIUM': 8, 'HIGH': 6},
|
||||
'CONFIDENCE': {'HIGH': 14}
|
||||
}
|
||||
self.check_example('weak_cryptographic_key_sizes.py', expect)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user