def runTest(self): ARC2.new(b'\x00' * 16, ARC2.MODE_ECB, effective_keylen=40) self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB) self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB) self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, effective_keylen=39) self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, effective_keylen=1025)
def runTest(self): # Encrypt/Decrypt data and test output parameter cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB) pt = b'5' * 16 ct = cipher.encrypt(pt) output = bytearray(16) res = cipher.encrypt(pt, output=output) self.assertEqual(ct, output) self.assertEqual(res, None) res = cipher.decrypt(ct, output=output) self.assertEqual(pt, output) self.assertEqual(res, None) output = memoryview(bytearray(16)) cipher.encrypt(pt, output=output) self.assertEqual(ct, output) cipher.decrypt(ct, output=output) self.assertEqual(pt, output) self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) shorter_output = bytearray(7) self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
def runTest(self): # Encrypt/Decrypt data and test output parameter cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB) pt = b'5' * 16 ct = cipher.encrypt(pt) output = bytearray(16) res = cipher.encrypt(pt, output=output) self.assertEqual(ct, output) self.assertEqual(res, None) res = cipher.decrypt(ct, output=output) self.assertEqual(pt, output) self.assertEqual(res, None) import sys if sys.version[:3] != '2.6': output = memoryview(bytearray(16)) cipher.encrypt(pt, output=output) self.assertEqual(ct, output) cipher.decrypt(ct, output=output) self.assertEqual(pt, output) self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) shorter_output = bytearray(7) self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output)
def decrypt(self, file_path, password): private_key = self.get_private_key(password) if private_key is None: return {'status': False, 'msg': "Cannot get private key"} with open(file_path, 'rb') as fi: try: msg = json.loads(fi.read()) except ValueError: return {'status': False, 'msg': "File structure is damaged"} for key, value in msg.iteritems(): msg[key] = b64decode(value) secret_key = PKCS1_OAEP.new(private_key).decrypt(msg['secret_key']) try: # init cipher if msg['alg'] == ALG_OPTIONS[0]: cipher = AES.new(secret_key, AES.MODE_EAX, msg['nonce']) elif msg['alg'] == ALG_OPTIONS[1]: cipher = AES.new(secret_key, AES.MODE_OCB, msg['nonce']) elif msg['alg'] == ALG_OPTIONS[2]: cipher = AES.new(secret_key, AES.MODE_CFB, msg['iv']) elif msg['alg'] == ALG_OPTIONS[3]: cipher = AES.new(secret_key, AES.MODE_CTR, msg['nonce']) elif msg['alg'] == ALG_OPTIONS[4]: cipher = DES.new(secret_key, DES.MODE_OFB, iv=msg['iv']) elif msg['alg'] == ALG_OPTIONS[5]: cipher = ARC2.new(secret_key, ARC2.MODE_CFB) elif msg['alg'] == ALG_OPTIONS[6]: cipher = ARC4.new(secret_key) elif msg['alg'] == ALG_OPTIONS[7]: cipher = ChaCha20.new(key=secret_key, nonce=msg['nonce']) elif msg['alg'] == ALG_OPTIONS[8]: cipher = Salsa20.new(key=secret_key, nonce=msg['nonce']) else: return {'status': False, 'msg': "Cannot define the algorithm used to encrypt this file"} # decrypt and verify if msg['alg'] in ALG_OPTIONS[1:3]: decrypted_msg = cipher.decrypt_and_verify(msg['cipher_text'], msg['tag']) elif msg['alg'] in ALG_OPTIONS[3:]: decrypted_msg = cipher.decrypt(msg['cipher_text']) SHA256.new(decrypted_msg).hexdigest(), msg['tag'] if SHA256.new(decrypted_msg).hexdigest() != msg['tag']: raise ValueError else: return {'status': False, 'msg': "Cannot define the algorithm used to encrypt this file"} except ValueError, KeyError: return {'status': False, 'msg': "Decrypt failed, you are not the owner of this file"} dir_path, file_name = os.path.split(file_path) with open(dir_path + '/' + msg['file_name'], 'wb') as fo: fo.write(decrypted_msg) return {'status': True, 'msg': "Successfully decrypted file %s" % file_path}
def pycryptodomexExamples(): from Cryptodome.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES from Cryptodome.Random import get_random_bytes key = b'-8B key-' DES.new(key, DES.MODE_OFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^ key = DES3.adjust_key_parity(get_random_bytes(24)) cipher = DES3.new( key, DES3.MODE_CFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'Sixteen byte key' cipher = ARC2.new( key, ARC2.MODE_CFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'Very long and confidential key' cipher = ARC4.new(key) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'An arbitrarily long key' cipher = Blowfish.new( key, Blowfish.MODE_CBC) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^^^^^ key = b'Sixteen byte key' cipher = AES.new(key, AES.MODE_CCM) # Compliant cipher = UnknownFlyingValue.new( key, UnknownMode.CBC) # Compliant, doesn't matter # Force the engine to generate an ambiguous symbol, for code coverage only. ambiguous = "" if 42 * 42 < 1700 else (lambda x: x * x) cipher = ambiguous.new(key, Unknown.Mode)
def pycroptodomeExamples(): from Crypto.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES from Crypto.Random import get_random_bytes key = b'-8B key-' DES.new(key, DES.MODE_OFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^ key = DES3.adjust_key_parity(get_random_bytes(24)) cipher = DES3.new( key, DES3.MODE_CFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'Sixteen byte key' cipher = ARC2.new( key, ARC2.MODE_CFB) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'Very long and confidential key' cipher = ARC4.new(key) # Noncompliant {{Use a strong cipher algorithm.}} # ^^^^^^^^ key = b'An arbitrarily long key' cipher = Blowfish.new( key, Blowfish.MODE_CBC) # Noncompliant {{Use a strong cipher algorithm.}}
def encrypt(self, file_path, alg): if alg not in ALG_OPTIONS: return False with open(file_path, 'rb') as fi, open(file_path + ENCRYPT_EXTEND, 'wb') as fo: public_key = self.get_public_key() cipher_rsa = PKCS1_OAEP.new(public_key) plain_text = fi.read() msg = {'alg': alg} if alg == ALG_OPTIONS[0]: secret_key = Random.get_random_bytes(16) cipher = AES.new(secret_key, AES.MODE_EAX) msg.update({'nonce': cipher.nonce}) elif alg == ALG_OPTIONS[1]: secret_key = Random.get_random_bytes(16) cipher = AES.new(secret_key, AES.MODE_OCB) msg.update({'nonce': cipher.nonce}) elif alg == ALG_OPTIONS[2]: secret_key = Random.get_random_bytes(16) iv = Random.new().read(AES.block_size) cipher = AES.new(secret_key, AES.MODE_CFB, iv) msg.update({'iv': iv}) elif alg == ALG_OPTIONS[3]: secret_key = Random.get_random_bytes(16) cipher = AES.new(secret_key, AES.MODE_CTR) msg.update({'nonce': cipher.nonce}) elif alg == ALG_OPTIONS[4]: secret_key = Random.get_random_bytes(8) cipher = DES.new(secret_key, DES.MODE_OFB) msg.update({'iv': cipher.iv}) elif alg == ALG_OPTIONS[5]: secret_key = Random.get_random_bytes(16) cipher = ARC2.new(secret_key, ARC2.MODE_CFB) msg.update({'iv': cipher.iv}) elif alg == ALG_OPTIONS[6]: secret_key = Random.get_random_bytes(40) cipher = ARC4.new(secret_key) elif alg == ALG_OPTIONS[7]: secret_key = Random.get_random_bytes(32) cipher = ChaCha20.new(key=secret_key) msg.update({'nonce': cipher.nonce}) elif alg == ALG_OPTIONS[8]: secret_key = Random.get_random_bytes(32) cipher = Salsa20.new(key=secret_key) msg.update({'nonce': cipher.nonce}) else: return False if alg in ALG_OPTIONS[1:3]: cipher_text, tag = cipher.encrypt_and_digest(plain_text) elif alg in ALG_OPTIONS[3:]: cipher_text = cipher.encrypt(plain_text) tag = SHA256.new(plain_text).hexdigest() else: return False dir_path, file_name = os.path.split(file_path) msg.update({'secret_key': cipher_rsa.encrypt(secret_key), 'cipher_text': cipher_text, 'tag': tag, 'file_name': file_name}) for key, value in msg.iteritems(): msg[key] = b64encode(value).encode('utf-8') fo.write(json.dumps(msg)) return True
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 from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers import algorithms from cryptography.hazmat.primitives.ciphers import modes from cryptography.hazmat.backends import default_backend from struct import pack key = b'Sixteen byte key' 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 = 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') iv = Random.new().read(bs) key = b'An arbitrarily long key' plaintext = b'docendo discimus ' plen = bs - divmod(len(plaintext),bs)[1] padding = [plen]*plen
class Crypter(object): """Implements modern authenticated encryption for strings The current version (1) uses HMAC-SHA256 and AES256-CBC using Encrypt-then-MAC. Should be secure >>>2030 according to NIST standards. http://www.keylength.com/ for a summary of algorithms and expected security. The message is padded with null characters. This means that strings with null characters should not use this method unless a different padding scheme is added AES in GCM mode is faster, but the pycrypto implementation is immature. This may be a better choice for future versions. There is currently legacy support for decryption under the old key using ARC2 TODO(devinlundberg): remove legacy ARC2 decryption support """ __metaclass__ = SingletonType # Remove legacy crypter in future. _legacy_crypter = ARC2.new(PinballConfig.SECRET_KEY, ARC2.MODE_ECB) _aes_block_size = 16 _padding_char = '\x00' def _serialize(self, ciphertext, mac, **params): """Creates a serialized crypto object with current version and key""" encoded_params = {k: v.encode('base64') for k, v in params.items()} return json.dumps({ 'version': PinballConfig.CRYPTO_VERSION, 'ciphertext': ciphertext.encode('base64'), 'auth': mac.encode('base64'), 'params': encoded_params }).encode('base64') def _deserialize(self, encoded_ciphertext): """Gets version, ciphertext, auth, and params from serialized object""" try: ciphertext_json = encoded_ciphertext.decode('base64') except binascii.Error: raise CryptoException('Invalid Base64') try: ciphertext_obj = json.loads(ciphertext_json) except ValueError: raise CryptoException('Invalid JSON format') if any(key not in ciphertext_obj for key in ('version', 'ciphertext', 'auth', 'params')): raise CryptoException('Invalid JSON parameters') version = ciphertext_obj['version'] try: ciphertext = ciphertext_obj['ciphertext'].decode('base64') auth = ciphertext_obj['auth'].decode('base64') params = {k: v.decode('base64') for k, v in ciphertext_obj['params'].items()} except binascii.Error: raise CryptoException('Invalid Base64') except AttributeError: raise CryptoException('Unsupported types') return version, ciphertext, auth, params def _cbc_hmac_sha256_decrypt(self, ciphertext, auth, iv): """Authenticated decrypt using AES-CBC and HMAC SHA256 Encrypt-then-MAC""" hmac = HMAC.new(PinballConfig.HMAC_KEY, digestmod=SHA256) hmac.update(ciphertext) hmac.update(iv) if not compare_digest(hmac.hexdigest(), auth): raise CryptoException('Decryption Failed') aes = AES.new(PinballConfig.AES_CBC_KEY, AES.MODE_CBC, iv) return aes.decrypt(ciphertext).rstrip(self._padding_char) def encrypt(self, message): """Encrypts string of any length using the current crypto version Args: message: The string that needs to be encrypted. Returns: A serialized authenticated encrypted object """ iv = ''.join(chr(random.randint(0, 255)) for _ in range(self._aes_block_size)) aes = AES.new(PinballConfig.AES_CBC_KEY, AES.MODE_CBC, iv) hmac = HMAC.new(PinballConfig.HMAC_KEY, digestmod=SHA256) padded_length = (len(message) + self._aes_block_size - len(message) % (self._aes_block_size)) padded_message = message.ljust(padded_length, self._padding_char) ciphertext = aes.encrypt(padded_message) hmac.update(ciphertext) hmac.update(iv) return self._serialize(ciphertext, hmac.hexdigest(), iv=iv) def decrypt(self, encoded_ciphertext): """Deserializes and decrypts a string with the current or legacy algorithms Args: encoded_ciphertext: The string that needs to be decrypted. Returns: The decrypted message. Throws: CryptoException: on failed decryption. """ try: version, ciphertext, auth, params = self._deserialize(encoded_ciphertext) except CryptoException: # This should raise an exception when support for ARC2 ends. return self._legacy_crypter.decrypt(encoded_ciphertext).rstrip('0') if version == 1: if 'iv' not in params: raise CryptoException('Missing IV') return self._cbc_hmac_sha256_decrypt(ciphertext, auth, params['iv']) else: raise CryptoException('Unsupported Crypto Version')
from Cryptodome.Cipher import DES, DES3, ARC2, ARC4, Blowfish, AES from Cryptodome.Random import get_random_bytes key = b'-8B key-' DES.new( key, DES.MODE_OFB ) # Noncompliant: DES works with 56-bit keys allow attacks via exhaustive search key = DES3.adjust_key_parity(get_random_bytes(24)) cipher = DES3.new( key, DES3.MODE_CFB ) # Noncompliant: Triple DES is vulnerable to meet-in-the-middle attack key = b'Sixteen byte key' cipher = ARC2.new( key, ARC2.MODE_CFB) # Noncompliant: RC2 is vulnerable to a related-key attack key = b'Very long and confidential key' cipher = ARC4.new( key ) # Noncompliant: vulnerable to several attacks (see https://en.wikipedia.org/wiki/RC4#Security) key = b'An arbitrarily long key' cipher = Blowfish.new( key, Blowfish.MODE_CBC ) # Noncompliant: Blowfish use a 64-bit block size makes it vulnerable to birthday attacks