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:
Eric Brown 2017-01-12 23:53:24 -08:00
parent 17c737a391
commit d4e213445a
6 changed files with 84 additions and 31 deletions

View File

@ -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'],

View File

@ -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:

View File

@ -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())

View File

@ -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()

View File

@ -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,

View File

@ -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)