def test_bytearray(self): data = b("1") * 16 iv = b("\x00") * 6 + b("\xFF\xFF") # Encrypt cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64, initial_value=iv) ref1 = cipher1.encrypt(data) cipher2 = AES.new(self.key_128, AES.MODE_CTR, nonce=bytearray(self.nonce_64), initial_value=bytearray(iv)) ref2 = cipher2.encrypt(bytearray(data)) self.assertEqual(ref1, ref2) self.assertEqual(cipher1.nonce, cipher2.nonce) # Decrypt cipher3 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64, initial_value=iv) ref3 = cipher3.decrypt(data) cipher4 = AES.new(self.key_128, AES.MODE_CTR, nonce=bytearray(self.nonce_64), initial_value=bytearray(iv)) ref4 = cipher4.decrypt(bytearray(data)) self.assertEqual(ref3, ref4)
def _start_mac(self): assert(self._mac_status == MacStatus.NOT_STARTED) assert(None not in (self._assoc_len, self._msg_len)) assert(isinstance(self._cache, list)) # Formatting control information and nonce (A.2.1) q = 15 - len(self.nonce) # length of Q, the encoded message length flags = (64 * (self._assoc_len > 0) + 8 * ((self._mac_len - 2) // 2) + (q - 1)) b_0 = bchr(flags) + self.nonce + long_to_bytes(self._msg_len, q) # Formatting associated data (A.2.2) # Encoded 'a' is concatenated with the associated data 'A' assoc_len_encoded = b('') if self._assoc_len > 0: if self._assoc_len < (2 ** 16 - 2 ** 8): enc_size = 2 elif self._assoc_len < (2 ** 32): assoc_len_encoded = b('\xFF\xFE') enc_size = 4 else: assoc_len_encoded = b('\xFF\xFF') enc_size = 8 assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size) # b_0 and assoc_len_encoded must be processed first self._cache.insert(0, b_0) self._cache.insert(1, assoc_len_encoded) # Process all the data cached so far first_data_to_mac = b("").join(self._cache) self._cache = b("") self._mac_status = MacStatus.PROCESSING_AUTH_DATA self._update(first_data_to_mac)
def _update(self, assoc_data_pt=b("")): """Update the MAC with associated data or plaintext (without FSM checks)""" if self._mac_status == MacStatus.NOT_STARTED: self._cache.append(assoc_data_pt) return assert(byte_string(self._cache)) assert(len(self._cache) < self.block_size) if len(self._cache) > 0: filler = min(self.block_size - len(self._cache), len(assoc_data_pt)) self._cache += assoc_data_pt[:filler] assoc_data_pt = assoc_data_pt[filler:] if len(self._cache) < self.block_size: return # The cache is exactly one block self._t = self._mac.encrypt(self._cache) self._cache = b("") update_len = len(assoc_data_pt) // self.block_size * self.block_size self._cache = assoc_data_pt[update_len:] if update_len > 0: self._t = self._mac.encrypt(assoc_data_pt[:update_len])[-16:]
def update(self, msg): """Authenticate the next chunk of message. Args: data (byte string): The next chunk of data """ self._data_size += len(msg) if len(self._cache) > 0: filler = min(self.digest_size - len(self._cache), len(msg)) self._cache += msg[:filler] if len(self._cache) < self.digest_size: return self msg = msg[filler:] self._update(self._cache) self._cache = b("") update_len, remain = divmod(len(msg), self.digest_size) update_len *= self.digest_size if remain > 0: self._update(msg[:update_len]) self._cache = msg[update_len:] else: self._update(msg) self._cache = b("") return self
def test_nonce_parameter(self): # Nonce parameter becomes nonce attribute cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64) self.assertEqual(cipher1.nonce, self.nonce_64) counter = Counter.new(64, prefix=self.nonce_64, initial_value=0) cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) self.assertEqual(cipher1.nonce, cipher2.nonce) pt = get_tag_random("plaintext", 65536) self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) # Nonce is implicitly created (for AES) when no parameters are passed nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce self.assertNotEqual(nonce1, nonce2) self.assertEqual(len(nonce1), 8) # Nonce can be zero-length cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b("")) self.assertEqual(b(""), cipher.nonce) # Nonce and Counter are mutually exclusive self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, counter=self.ctr_128, nonce=self.nonce_64)
def test3(self): for keylen, taglen, result in self.tv3: key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) C = b("") for i in range(128): S = bchr(0) * i N = long_to_bytes(3 * i + 1, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 2, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() N = long_to_bytes(3 * i + 3, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(S) C += cipher.encrypt() + cipher.digest() N = long_to_bytes(385, 12) cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) cipher.update(C) result2 = cipher.encrypt() + cipher.digest() self.assertEqual(unhexlify(b(result)), result2)
def test_unaligned_data_64(self): plaintexts = [ b("7777777") ] * 100 cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) self.assertEqual(b("").join(ciphertexts), cipher.encrypt(b("").join(plaintexts)))
def _start_mac(self): assert(self._mac_status == MacStatus.NOT_STARTED) assert(None not in (self._assoc_len, self._msg_len)) assert(isinstance(self._cache, list)) # Formatting control information and nonce (A.2.1) q = 15 - len(self.nonce) # length of Q, the encoded message length flags = (64 * (self._assoc_len > 0) + 8 * ((self._mac_len - 2) // 2) + (q - 1)) b_0 = bchr(flags) + self.nonce + long_to_bytes(self._msg_len, q) # Formatting associated data (A.2.2) # Encoded 'a' is concatenated with the associated data 'A' assoc_len_encoded = b('') if self._assoc_len > 0: if self._assoc_len < (2 ** 16 - 2 ** 8): enc_size = 2 elif self._assoc_len < (2L ** 32): assoc_len_encoded = b('\xFF\xFE') enc_size = 4 else: assoc_len_encoded = b('\xFF\xFF') enc_size = 8 assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size)
def import_key(encoded, passphrase=None): """Import an ECC key (public or private). :Parameters: encoded : bytes or a (multi-line) string The ECC key to import. An ECC public key can be: - An X.509 certificate, binary (DER) or ASCII (PEM) - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) An ECC private key can be: - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - In ASCII format (PEM or OpenSSH) Private keys can be in the clear or password-protected. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. :Keywords: passphrase : byte string The passphrase to use for decrypting a private key. Encryption may be applied protected at the PEM level or at the PKCS#8 level. This parameter is ignored if the key in input is not encrypted. :Return: An ECC key object (`EccKey`) :Raise ValueError: When the given key cannot be parsed (possibly because the pass phrase is wrong). .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt """ encoded = tobytes(encoded) if passphrase is not None: passphrase = tobytes(passphrase) # PEM if encoded.startswith(b('-----')): der_encoded, marker, enc_flag = PEM.decode(tostr(encoded), passphrase) if enc_flag: passphrase = None return _import_der(der_encoded, passphrase) # OpenSSH if encoded.startswith(b('ecdsa-sha2-')): return _import_openssh(encoded) # DER if bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) raise ValueError("ECC key format is not supported")
def _transcrypt(self, in_data, trans_func, trans_desc): # Last piece to encrypt/decrypt if in_data is None: out_data = self._transcrypt_aligned(self._cache_P, len(self._cache_P), trans_func, trans_desc) self._cache_P = b("") return out_data # Try to fill up the cache, if it already contains something expect_byte_string(in_data) prefix = b("") if len(self._cache_P) > 0: filler = min(16 - len(self._cache_P), len(in_data)) self._cache_P += in_data[:filler] in_data = in_data[filler:] if len(self._cache_P) < 16: # We could not manage to fill the cache, so there is certainly # no output yet. return b("") # Clear the cache, and proceeding with any other aligned data prefix = self._transcrypt_aligned(self._cache_P, len(self._cache_P), trans_func, trans_desc) self._cache_P = b("") # Process data in multiples of the block size trans_len = len(in_data) // 16 * 16 result = self._transcrypt_aligned(in_data, trans_len, trans_func, trans_desc) if prefix: result = prefix + result # Left-over self._cache_P = in_data[trans_len:] return result
def test_unaligned_data_128(self): plaintexts = [ b("7777777") ] * 100 cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) self.assertEqual(b("").join(ciphertexts), cipher.encrypt(b("").join(plaintexts)))
def test_iv_with_matching_length(self): self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, b("")) self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, self.iv_128[:15]) self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, self.iv_128 + b("0"))
def __init__(self, factory, nonce, mac_len, cipher_params): if factory.block_size != 16: raise ValueError("OCB mode is only available for ciphers" " that operate on 128 bits blocks") self.block_size = 16 """The block size of the underlying cipher, in bytes.""" self.nonce = nonce """Nonce used for this session.""" if len(nonce) not in range(1, 16): raise ValueError("Nonce must be at most 15 bytes long") self._mac_len = mac_len if not 8 <= mac_len <= 16: raise ValueError("MAC tag must be between 8 and 16 bytes long") # Cache for MAC tag self._mac_tag = None # Cache for unaligned associated data self._cache_A = b("") # Cache for unaligned ciphertext/plaintext self._cache_P = b("") # Allowed transitions after initialization self._next = [self.update, self.encrypt, self.decrypt, self.digest, self.verify] # Compute Offset_0 params_without_key = dict(cipher_params) key = params_without_key.pop("key") nonce = bchr(self._mac_len << 4 & 0xFF) + bchr(0) * (14 - len(self.nonce)) + bchr(1) + self.nonce bottom = bord(nonce[15]) & 0x3F # 6 bits, 0..63 ktop = factory.new(key, factory.MODE_ECB, **params_without_key).encrypt( nonce[:15] + bchr(bord(nonce[15]) & 0xC0) ) stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits offset_0 = long_to_bytes(bytes_to_long(stretch) >> (64 - bottom), 24)[8:] # Create low-level cipher instance raw_cipher = factory._create_base_cipher(cipher_params) if cipher_params: raise TypeError("Unknown keywords: " + str(cipher_params)) self._state = VoidPointer() result = _raw_ocb_lib.OCB_start_operation( raw_cipher.get(), offset_0, c_size_t(len(offset_0)), self._state.address_of() ) if result: raise ValueError("Error %d while instantiating the OCB mode" % result) # Ensure that object disposal of this Python object will (eventually) # free the memory allocated by the raw library for the cipher mode self._state = SmartPointer(self._state.get(), _raw_ocb_lib.OCB_stop_operation) # Memory allocated for the underlying block cipher is now owed # by the cipher mode raw_cipher.release()
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) cipher.encrypt(b("")) self.assertRaises(TypeError, cipher.decrypt, b("")) cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) cipher.decrypt(b("")) self.assertRaises(TypeError, cipher.encrypt, b(""))
def digest(self): if self._tag: return self._tag if self._buffer_len>0: self.update(b("")) left_data = b("").join(self._buffer) self._tag = self._digest(left_data) return self._tag
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) eiv = cipher.encrypt(b("")) self.assertRaises(TypeError, cipher.decrypt, b("")) cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) cipher.decrypt(b("")) self.assertRaises(TypeError, cipher.encrypt, b(""))
def __init__(self, module, params): from Crypto import Random unittest.TestCase.__init__(self) self.module = module self.iv = Random.get_random_bytes(module.block_size) self.key = b(params['key']) self.plaintext = 100 * b(params['plaintext']) self.module_name = params.get('module_name', None)
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) cipher.encrypt(b("")) self.assertRaises(TypeError, cipher.decrypt, b("")) cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) cipher.decrypt(b("")) self.assertRaises(TypeError, cipher.encrypt, b(""))
def test_unaligned_data_64(self): cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) for wrong_length in range(1,8): self.assertRaises(ValueError, cipher.encrypt, b("5") * wrong_length) cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) for wrong_length in range(1,8): self.assertRaises(ValueError, cipher.decrypt, b("5") * wrong_length)
def test_unaligned_data_128(self): cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) for wrong_length in range(1,16): self.assertRaises(ValueError, cipher.encrypt, b("5") * wrong_length) cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) for wrong_length in range(1,16): self.assertRaises(ValueError, cipher.decrypt, b("5") * wrong_length)
def test_copy(self): h = self.BLAKE2.new(digest_bits=self.max_bits, data=b("init")) h2 = h.copy() self.assertEqual(h.digest(), h2.digest()) h.update(b("second")) self.assertNotEqual(h.digest(), h2.digest()) h2.update(b("second")) self.assertEqual(h.digest(), h2.digest())
def test_either_encrypt_or_decrypt(self): cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) cipher.encrypt(b("")) self.assertRaises(TypeError, cipher.decrypt, b("")) cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) cipher.decrypt(b("")) self.assertRaises(TypeError, cipher.encrypt, b(""))
def test_new_positive(self): xof1 = self.shake.new() xof2 = self.shake.new(data=b("90")) xof3 = self.shake.new().update(b("90")) self.assertNotEqual(xof1.read(10), xof2.read(10)) xof3.read(10) self.assertEqual(xof2.read(10), xof3.read(10))
def test_init(self): # Verify that nonce can be passed in the old way (3rd parameter) # or in the new way ('nonce' parameter) ct, mac = self._create_cipher().encrypt_and_digest(b("XXX")) cipher = AES.new(self.key, AES.MODE_OCB, bchr(0)*15) ct2, mac2 = cipher.encrypt_and_digest(b("XXX")) self.assertEquals(ct, ct2) self.assertEquals(mac, mac2)
def runTest(self): for key_size, result in self.test_vectors: next_data = b("") for _ in xrange(100): h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b("A" * key_size)) h.update(next_data) next_data = h.digest() + next_data self.assertEqual(h.digest(), result)
def test_update_chaining(self): cipher = self._create_cipher() cipher.update(b("XXX")).update(b("YYY")) mac = cipher.digest() cipher = self._create_cipher() cipher.update(b("XXXYYY")) mac2 = cipher.digest() self.assertEquals(mac, mac2)
def test_invalid_multiple_encrypt(self): # Without AAD cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) cipher.encrypt(b("xxx")) self.assertRaises(TypeError, cipher.encrypt, b("xxx")) # With AAD cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) cipher.update(b("yyy")) cipher.encrypt(b("xxx")) self.assertRaises(TypeError, cipher.encrypt, b("xxx"))
def __init__(self, key, msg=b(""), digestmod=None): """Create a new HMAC object. :Parameters: key : byte string secret key for the MAC object. It must be long enough to match the expected security level of the MAC. However, there is no benefit in using keys longer than the `digest_size` of the underlying hash algorithm. msg : byte string The very first chunk of the message to authenticate. It is equivalent to an early call to `update()`. Optional. :Parameter digestmod: The hash algorithm the HMAC is based on. Default is `Crypto.Hash.MD5`. :Type digestmod: A hash module or object instantiated from `Crypto.Hash` """ if digestmod is None: digestmod = MD5 if msg is None: msg = b("") #: Size of the MAC tag self.digest_size = digestmod.digest_size self._digestmod = digestmod try: if len(key) <= digestmod.block_size: # Step 1 or 2 key_0 = key + bchr(0) * (digestmod.block_size - len(key)) else: # Step 3 hash_k = digestmod.new(key).digest() key_0 = hash_k + bchr(0) * (digestmod.block_size - len(hash_k)) except AttributeError: # Not all hash types have "block_size" raise ValueError("Hash type incompatible to HMAC") # Step 4 key_0_ipad = strxor(key_0, bchr(0x36) * len(key_0)) # Start step 5 and 6 self._inner = digestmod.new(key_0_ipad) self._inner.update(msg) # Step 7 key_0_opad = strxor(key_0, bchr(0x5c) * len(key_0)) # Start step 8 and 9 self._outer = digestmod.new(key_0_opad)
def test_unaligned_data_64(self): plaintexts = [ b("7777777") ] * 100 cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) self.assertEqual(b("").join(ciphertexts), cipher.encrypt(b("").join(plaintexts))) cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) self.assertEqual(b("").join(ciphertexts), cipher.encrypt(b("").join(plaintexts)))
def test_template(self, factory=factory, key_size=key_size): cipher = factory.new(get_tag_random("cipher", key_size), factory.MODE_EAX, nonce=b("nonce")) ct, mac = cipher.encrypt_and_digest(b("plaintext")) cipher = factory.new(get_tag_random("cipher", key_size), factory.MODE_EAX, nonce=b("nonce")) pt2 = cipher.decrypt_and_verify(ct, mac) self.assertEqual(b("plaintext"), pt2)
def test_null_encryption_decryption(self): for func in "encrypt", "decrypt": cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) result = getattr(cipher, func)(b("")) self.assertEqual(result, b(""))