def _update(self, assoc_data_pt=b""): """Update the MAC with associated data or plaintext (without FSM checks)""" # If MAC has not started yet, we just park the data into a list. # If the data is mutable, we create a copy and store that instead. if self._mac_status == MacStatus.NOT_STARTED: if _is_mutable(assoc_data_pt): assoc_data_pt = _copy_bytes(None, None, assoc_data_pt) self._cache.append(assoc_data_pt) return 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 += _copy_bytes(None, filler, assoc_data_pt) assoc_data_pt = _copy_bytes(filler, None, assoc_data_pt) 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 = _copy_bytes(update_len, None, assoc_data_pt) if update_len > 0: self._t = self._mac.encrypt(assoc_data_pt[:update_len])[-16:]
def __init__(self, key, nonce): """Initialize a Salsa20 cipher object See also `new()` at the module level.""" if len(key) not in key_size: raise ValueError("Incorrect key length for Salsa20 (%d bytes)" % len(key)) if len(nonce) != 8: raise ValueError("Incorrect nonce length for Salsa20 (%d bytes)" % len(nonce)) self.nonce = _copy_bytes(None, None, nonce) self._state = VoidPointer() result = _raw_salsa20_lib.Salsa20_stream_init( c_uint8_ptr(key), c_size_t(len(key)), c_uint8_ptr(nonce), c_size_t(len(nonce)), self._state.address_of()) if result: raise ValueError("Error %d instantiating a Salsa20 cipher") self._state = SmartPointer(self._state.get(), _raw_salsa20_lib.Salsa20_stream_destroy) self.block_size = 1 self.key_size = len(key)
def update(self, msg): """Authenticate the next chunk of message. Args: data (byte string/byte array/memoryview): The next chunk of data """ # Mutable values must be copied if cached 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 = _copy_bytes(update_len, None, msg) else: self._update(msg) self._cache = b"" return self
def __init__(self, block_cipher, initial_counter_block, prefix_len, counter_len, little_endian): """Create a new block cipher, configured in CTR mode. :Parameters: block_cipher : C pointer A smart pointer to the low-level block cipher instance. initial_counter_block : bytes/bytearray/memoryview The initial plaintext to use to generate the key stream. It is as large as the cipher block, and it embeds the initial value of the counter. This value must not be reused. It shall contain a nonce or a random component. Reusing the *initial counter block* for encryptions performed with the same key compromises confidentiality. prefix_len : integer The amount of bytes at the beginning of the counter block that never change. counter_len : integer The length in bytes of the counter embedded in the counter block. little_endian : boolean True if the counter in the counter block is an integer encoded in little endian mode. If False, it is big endian. """ if len(initial_counter_block) == prefix_len + counter_len: self.nonce = _copy_bytes(None, prefix_len, initial_counter_block) """Nonce; not available if there is a fixed suffix""" self._state = VoidPointer() result = raw_ctr_lib.CTR_start_operation( block_cipher.get(), c_uint8_ptr(initial_counter_block), c_size_t(len(initial_counter_block)), c_size_t(prefix_len), counter_len, little_endian, self._state.address_of()) if result: raise ValueError("Error %X while instatiating the CTR 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_ctr_lib.CTR_stop_operation) # Memory allocated for the underlying block cipher is now owed # by the cipher mode block_cipher.release() self.block_size = len(initial_counter_block) """The block size of the underlying cipher, in bytes.""" self._next = [self.encrypt, self.decrypt]
def update(self, assoc_data): """Process the associated data. If there is any associated data, the caller has to invoke this method one or more times, before using ``decrypt`` or ``encrypt``. By *associated data* it is meant any data (e.g. packet headers) that will not be encrypted and will be transmitted in the clear. However, the receiver shall still able to detect modifications. If there is no associated data, this method must not be called. The caller may split associated data in segments of any size, and invoke this method multiple times, each time with the next segment. :Parameters: assoc_data : bytes/bytearray/memoryview A piece of associated data. """ if self.update not in self._next: raise TypeError("update() can only be called" " immediately after initialization") self._next = [ self.encrypt, self.decrypt, self.digest, self.verify, self.update ] if len(self._cache_A) > 0: filler = min(16 - len(self._cache_A), len(assoc_data)) self._cache_A += _copy_bytes(None, filler, assoc_data) assoc_data = assoc_data[filler:] if len(self._cache_A) < 16: return self # Clear the cache, and proceeding with any other aligned data self._cache_A, seg = b"", self._cache_A self.update(seg) update_len = len(assoc_data) // 16 * 16 self._cache_A = _copy_bytes(update_len, None, assoc_data) self._update(assoc_data, update_len) return self
def __init__(self, key, msg, ciphermod, cipher_params, mac_len, update_after_digest): self.digest_size = mac_len self._key = _copy_bytes(None, None, key) self._factory = ciphermod self._cipher_params = cipher_params self._block_size = bs = ciphermod.block_size self._mac_tag = None self._update_after_digest = update_after_digest # Section 5.3 of NIST SP 800 38B and Appendix B if bs == 8: const_Rb = 0x1B self._max_size = 8 * (2**21) elif bs == 16: const_Rb = 0x87 self._max_size = 16 * (2**48) else: raise TypeError("CMAC requires a cipher with a block size" " of 8 or 16 bytes, not %d" % bs) # Compute sub-keys zero_block = b'\x00' * bs self._ecb = ciphermod.new(key, ciphermod.MODE_ECB, **self._cipher_params) L = self._ecb.encrypt(zero_block) if bord(L[0]) & 0x80: self._k1 = _shift_bytes(L, const_Rb) else: self._k1 = _shift_bytes(L) if bord(self._k1[0]) & 0x80: self._k2 = _shift_bytes(self._k1, const_Rb) else: self._k2 = _shift_bytes(self._k1) # Initialize CBC cipher with zero IV self._cbc = ciphermod.new(key, ciphermod.MODE_CBC, zero_block, **self._cipher_params) # Cache for outstanding data to authenticate self._cache = bytearray(bs) self._cache_n = 0 # Last piece of ciphertext produced self._last_ct = zero_block # Last block that was encrypted with AES self._last_pt = None # Counter for total message size self._data_size = 0 if msg: self.update(msg)
def _update(self, data): assert (len(self._cache) < 16) if len(self._cache) > 0: filler = min(16 - len(self._cache), len(data)) self._cache += _copy_bytes(None, filler, data) data = data[filler:] if len(self._cache) < 16: return # The cache is exactly one block self._signer.update(self._cache) self._cache = b"" update_len = len(data) // 16 * 16 self._cache = _copy_bytes(update_len, None, data) if update_len > 0: self._signer.update(data[:update_len])
def encrypt(self, message): """Encrypt a message with PKCS#1 OAEP. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 2, minus twice the hash output size. For instance, if you use RSA 2048 and SHA-256, the longest message you can encrypt is 190 byte long. :type message: bytes/bytearray/memoryview :returns: The ciphertext, as large as the RSA modulus. :rtype: bytes :raises ValueError: if the message is too long. """ # See 7.1.1 in RFC3447 modBits = crypto.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size mLen = len(message) # Step 1b ps_len = k - mLen - 2 * hLen - 2 if ps_len < 0: raise ValueError("Plaintext is too long.") # Step 2a lHash = self._hashObj.new(self._label).digest() # Step 2b ps = b'\x00' * ps_len # Step 2c db = lHash + ps + b'\x01' + _copy_bytes(None, None, message) # Step 2d ros = self._randfunc(hLen) # Step 2e dbMask = self._mgf(ros, k - hLen - 1) # Step 2f maskedDB = strxor(db, dbMask) # Step 2g seedMask = self._mgf(maskedDB, hLen) # Step 2h maskedSeed = strxor(ros, seedMask) # Step 2i em = b'\x00' + maskedSeed + maskedDB # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
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 prefix = b"" if len(self._cache_P) > 0: filler = min(16 - len(self._cache_P), len(in_data)) self._cache_P += _copy_bytes(None, filler, in_data) 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(c_uint8_ptr(in_data), trans_len, trans_func, trans_desc) if prefix: result = prefix + result # Left-over self._cache_P = _copy_bytes(trans_len, None, in_data) return result
def __init__(self, block_cipher, iv, segment_size): """Create a new block cipher, configured in CFB mode. :Parameters: block_cipher : C pointer A smart pointer to the low-level block cipher instance. iv : bytes/bytearray/memoryview The initialization vector to use for encryption or decryption. It is as long as the cipher block. **The IV must be unpredictable**. Ideally it is picked randomly. Reusing the *IV* for encryptions performed with the same key compromises confidentiality. segment_size : integer The number of bytes the plaintext and ciphertext are segmented in. """ self._state = VoidPointer() result = raw_cfb_lib.CFB_start_operation(block_cipher.get(), c_uint8_ptr(iv), c_size_t(len(iv)), c_size_t(segment_size), self._state.address_of()) if result: raise ValueError("Error %d while instatiating the CFB 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_cfb_lib.CFB_stop_operation) # Memory allocated for the underlying block cipher is now owed # by the cipher mode block_cipher.release() self.block_size = len(iv) """The block size of the underlying cipher, in bytes.""" self.iv = _copy_bytes(None, None, iv) """The Initialization Vector originally used to create the object. The value does not change.""" self.IV = self.iv """Alias for `iv`""" self._next = [self.encrypt, self.decrypt]
def __init__(self, factory, key, nonce, mac_len, cipher_params): """EAX cipher mode""" self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self.nonce = _copy_bytes(None, None, nonce) """The nonce originally used to create the object.""" self._mac_len = mac_len self._mac_tag = None # Cache for MAC tag # Allowed transitions after initialization self._next = [ self.update, self.encrypt, self.decrypt, self.digest, self.verify ] # MAC tag length if not (4 <= self._mac_len <= self.block_size): raise ValueError("Parameter 'mac_len' must not be larger than %d" % self.block_size) # Nonce cannot be empty and must be a byte string if len(self.nonce) == 0: raise ValueError("Nonce cannot be empty in EAX mode") if not is_buffer(nonce): raise TypeError("nonce must be bytes, bytearray or memoryview") self._omac = [ CMAC.new(key, b'\x00' * (self.block_size - 1) + struct.pack('B', i), ciphermod=factory, cipher_params=cipher_params) for i in range(0, 3) ] # Compute MAC of nonce self._omac[0].update(self.nonce) self._signer = self._omac[1] # MAC of the nonce is also the initial counter for CTR encryption counter_int = bytes_to_long(self._omac[0].digest()) self._cipher = factory.new(key, factory.MODE_CTR, initial_value=counter_int, nonce=b"", **cipher_params)
def encrypt(self, message): """Produce the PKCS#1 v1.5 encryption of a message. This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in `section 7.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-28>`_. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 11. :type message: bytes/bytearray/memoryview :Returns: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raises ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # See 7.2.1 in RFC8017 modBits = Crypto.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes mLen = len(message) # Step 1 if mLen > k - 11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - mLen - 3: new_byte = self._randfunc(1) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b"".join(ps) assert (len(ps) == k - mLen - 3) # Step 2b em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def _update(self, data_block): """Update a block aligned to the block boundary""" if len(data_block) == 0: return assert len(data_block) % self.digest_size == 0 ct = self._cbc.encrypt(data_block) if len(data_block) == self.digest_size: self._before_last_ct = self._last_ct else: self._before_last_ct = ct[-self.digest_size * 2:-self.digest_size] self._last_ct = ct[-self.digest_size:] # data_block can mutable self._last_pt = _copy_bytes(-self.digest_size, None, data_block)
def __init__(self, key, nonce): """Initialize a ChaCha20 cipher object See also `new()` at the module level.""" self.nonce = _copy_bytes(None, None, nonce) self._next = (self.encrypt, self.decrypt) self._state = VoidPointer() result = _raw_chacha20_lib.chacha20_init(self._state.address_of(), c_uint8_ptr(key), c_size_t(len(key)), self.nonce, c_size_t(len(nonce))) if result: raise ValueError("Error %d instantiating a ChaCha20 cipher") self._state = SmartPointer(self._state.get(), _raw_chacha20_lib.chacha20_destroy)
def __init__(self, factory, key, nonce, kwargs): self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self._factory = factory self._cipher_params = kwargs if len(key) not in (32, 48, 64): raise ValueError("Incorrect key length (%d bytes)" % len(key)) if nonce is not None: if not is_buffer(nonce): raise TypeError( "When provided, the nonce must be bytes, bytearray or memoryview" ) if len(nonce) == 0: raise ValueError("When provided, the nonce must be non-empty") self.nonce = _copy_bytes(None, None, nonce) """Public attribute is only available in case of non-deterministic encryption.""" subkey_size = len(key) // 2 self._mac_tag = None # Cache for MAC tag self._kdf = _S2V(key[:subkey_size], ciphermod=factory, cipher_params=self._cipher_params) self._subkey_cipher = key[subkey_size:] # Purely for the purpose of verifying that cipher_params are OK factory.new(key[:subkey_size], factory.MODE_ECB, **kwargs) # Allowed transitions after initialization self._next = [ self.update, self.encrypt, self.decrypt, self.digest, self.verify ]
def update(self, item): """Pass the next component of the vector. The maximum number of components you can pass is equal to the block length of the cipher (in bits) minus 1. :Parameters: item : byte string The next component of the vector. :Raise TypeError: when the limit on the number of components has been reached. """ if self._n_updates == 0: raise TypeError("Too many components passed to S2V") self._n_updates -= 1 mac = CMAC.new(self._key, msg=self._last_string, ciphermod=self._ciphermod, cipher_params=self._cipher_params) self._cache = strxor(self._double(self._cache), mac.digest()) self._last_string = _copy_bytes(None, None, item)
def __init__(self, factory, key, iv, cipher_params): #: The block size of the underlying cipher, in bytes. self.block_size = factory.block_size self._done_first_block = False # True after the first encryption # Instantiate a temporary cipher to process the IV IV_cipher = factory.new(key, factory.MODE_CFB, IV=b'\x00' * self.block_size, segment_size=self.block_size * 8, **cipher_params) iv = _copy_bytes(None, None, iv) # The cipher will be used for... if len(iv) == self.block_size: # ... encryption self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) elif len(iv) == self.block_size + 2: # ... decryption self._encrypted_IV = iv # Last two bytes are for a deprecated "quick check" feature that # should not be used. (https://eprint.iacr.org/2005/033) iv = IV_cipher.decrypt(iv)[:-2] else: raise ValueError("Length of IV must be %d or %d bytes" " for MODE_OPENPGP" % (self.block_size, self.block_size + 2)) self.iv = self.IV = iv # Instantiate the cipher for the real PGP data self._cipher = factory.new(key, factory.MODE_CFB, IV=self._encrypted_IV[-self.block_size:], segment_size=self.block_size * 8, **cipher_params)
def __init__(self, key, hashAlgo, mgfunc, label, randfunc): """Initialize this PKCS#1 OAEP cipher object. :Parameters: key : an RSA key object If a private half is given, both encryption and decryption are possible. If a public half is given, only encryption is possible. hashAlgo : hash object The hash function to use. This can be a module under `crypto.Hash` or an existing hash object created from any of such modules. If not specified, `crypto.Hash.SHA1` is used. mgfunc : callable A mask generation function that accepts two parameters: a string to use as seed, and the lenth of the mask to generate, in bytes. If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). label : bytes/bytearray/memoryview A label to apply to this particular encryption. If not specified, an empty string is used. Specifying a label does not improve security. randfunc : callable A function that returns random bytes. :attention: Modify the mask generation function only if you know what you are doing. Sender and receiver must use the same one. """ self._key = key if hashAlgo: self._hashObj = hashAlgo else: self._hashObj = crypto.Hash.SHA1 if mgfunc: self._mgf = mgfunc else: self._mgf = lambda x, y: MGF1(x, y, self._hashObj) self._label = _copy_bytes(None, None, label) self._randfunc = randfunc
def __init__(self, key, ciphermod, cipher_params=None): """Initialize the S2V PRF. :Parameters: key : byte string A secret that can be used as key for CMACs based on ciphers from ``ciphermod``. ciphermod : module A block cipher module from `Crypto.Cipher`. cipher_params : dictionary A set of extra parameters to use to create a cipher instance. """ self._key = _copy_bytes(None, None, key) self._ciphermod = ciphermod self._last_string = self._cache = b'\x00' * ciphermod.block_size # Max number of update() call we can process self._n_updates = ciphermod.block_size * 8 - 1 if cipher_params is None: self._cipher_params = {} else: self._cipher_params = dict(cipher_params)
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 = _copy_bytes(None, None, nonce) """Nonce used for this session.""" if len(nonce) not in range(1, 16): raise ValueError("Nonce must be at most 15 bytes long") if not is_buffer(nonce): raise TypeError("Nonce must be bytes, bytearray or memoryview") 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 = (struct.pack('B', self._mac_len << 4 & 0xFF) + b'\x00' * (14 - len(nonce)) + b'\x01' + self.nonce) bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 top_bits = bord(nonce[15]) & 0xC0 # 2 bits ktop_cipher = factory.new(key, factory.MODE_ECB, **params_without_key) ktop = ktop_cipher.encrypt(struct.pack('15sB', nonce[:15], top_bits)) stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits offset_0 = long_to_bytes( bytes_to_long(stretch) >> (64 - bottom_bits), 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 __init__(self, factory, key, nonce, mac_len, cipher_params, ghash_c): self.block_size = factory.block_size if self.block_size != 16: raise ValueError("GCM mode is only available for ciphers" " that operate on 128 bits blocks") if len(nonce) == 0: raise ValueError("Nonce cannot be empty") if not is_buffer(nonce): raise TypeError("Nonce must be bytes, bytearray or memoryview") # See NIST SP 800 38D, 5.2.1.1 if len(nonce) > 2**64 - 1: raise ValueError("Nonce exceeds maximum length") self.nonce = _copy_bytes(None, None, nonce) """Nonce""" self._factory = factory self._key = _copy_bytes(None, None, key) self._tag = None # Cache for MAC tag self._mac_len = mac_len if not (4 <= mac_len <= 16): raise ValueError("Parameter 'mac_len' must be in the range 4..16") # Allowed transitions after initialization self._next = [ self.update, self.encrypt, self.decrypt, self.digest, self.verify ] self._no_more_assoc_data = False # Length of associated data self._auth_len = 0 # Length of the ciphertext or plaintext self._msg_len = 0 # Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H # See also Algorithm 5 (decryption) hash_subkey = factory.new(key, self._factory.MODE_ECB, **cipher_params).encrypt(b'\x00' * 16) # Step 2 - Compute J0 if len(self.nonce) == 12: j0 = self.nonce + b"\x00\x00\x00\x01" else: fill = (16 - (len(nonce) % 16)) % 16 + 8 ghash_in = (self.nonce + b'\x00' * fill + long_to_bytes(8 * len(nonce), 8)) j0 = _GHASH(hash_subkey, ghash_c).update(ghash_in).digest() # Step 3 - Prepare GCTR cipher for encryption/decryption nonce_ctr = j0[:12] iv_ctr = (bytes_to_long(j0) + 1) & 0xFFFFFFFF self._cipher = factory.new(key, self._factory.MODE_CTR, initial_value=iv_ctr, nonce=nonce_ctr, **cipher_params) # Step 5 - Bootstrat GHASH self._signer = _GHASH(hash_subkey, ghash_c) # Step 6 - Prepare GCTR cipher for GMAC self._tag_cipher = factory.new(key, self._factory.MODE_CTR, initial_value=j0, nonce=b"", **cipher_params) # Cache for data to authenticate self._cache = b"" self._status = MacStatus.PROCESSING_AUTH_DATA
def __init__(self, factory, key, nonce, mac_len, msg_len, assoc_len, cipher_params): self.block_size = factory.block_size """The block size of the underlying cipher, in bytes.""" self.nonce = _copy_bytes(None, None, nonce) """The nonce used for this cipher instance""" self._factory = factory self._key = _copy_bytes(None, None, key) self._mac_len = mac_len self._msg_len = msg_len self._assoc_len = assoc_len self._cipher_params = cipher_params self._mac_tag = None # Cache for MAC tag if self.block_size != 16: raise ValueError("CCM mode is only available for ciphers" " that operate on 128 bits blocks") # MAC tag length (Tlen) if mac_len not in (4, 6, 8, 10, 12, 14, 16): raise ValueError("Parameter 'mac_len' must be even" " and in the range 4..16 (not %d)" % mac_len) # Nonce value if not (nonce and 7 <= len(nonce) <= 13): raise ValueError("Length of parameter 'nonce' must be" " in the range 7..13 bytes") # Create MAC object (the tag will be the last block # bytes worth of ciphertext) self._mac = self._factory.new(key, factory.MODE_CBC, iv=b'\x00' * 16, **cipher_params) self._mac_status = MacStatus.NOT_STARTED self._t = None # Allowed transitions after initialization self._next = [ self.update, self.encrypt, self.decrypt, self.digest, self.verify ] # Cumulative lengths self._cumul_assoc_len = 0 self._cumul_msg_len = 0 # Cache for unaligned associated data/plaintext. # This is a list with byte strings, but when the MAC starts, # it will become a binary string no longer than the block size. self._cache = [] # Start CTR cipher, by formatting the counter (A.3) q = 15 - len(nonce) # length of Q, the encoded message length self._cipher = self._factory.new(key, self._factory.MODE_CTR, nonce=struct.pack("B", q - 1) + self.nonce, **cipher_params) # S_0, step 6 in 6.1 for j=0 self._s_0 = self._cipher.encrypt(b'\x00' * 16) # Try to start the MAC if None not in (assoc_len, msg_len): self._start_mac()
def __init__(self, key, msg, ciphermod, cipher_params, mac_len): if ciphermod is None: raise TypeError("ciphermod must be specified (try AES)") self._key = _copy_bytes(None, None, key) self._factory = ciphermod if cipher_params is None: self._cipher_params = {} else: self._cipher_params = dict(cipher_params) self._mac_len = mac_len or ciphermod.block_size if self._mac_len < 4: raise ValueError("MAC tag length must be at least 4 bytes long") if self._mac_len > ciphermod.block_size: raise ValueError( "MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size) # Section 5.3 of NIST SP 800 38B and Appendix B if ciphermod.block_size == 8: const_Rb = 0x1B self._max_size = 8 * (2**21) elif ciphermod.block_size == 16: const_Rb = 0x87 self._max_size = 16 * (2**48) else: raise TypeError("CMAC requires a cipher with a block size" "of 8 or 16 bytes, not %d" % (ciphermod.block_size, )) # Size of the final MAC tag, in bytes self.digest_size = ciphermod.block_size self._mac_tag = None # Compute sub-keys zero_block = b'\x00' * ciphermod.block_size cipher = ciphermod.new(key, ciphermod.MODE_ECB, **self._cipher_params) l = cipher.encrypt(zero_block) if bord(l[0]) & 0x80: self._k1 = _shift_bytes(l, const_Rb) else: self._k1 = _shift_bytes(l) if bord(self._k1[0]) & 0x80: self._k2 = _shift_bytes(self._k1, const_Rb) else: self._k2 = _shift_bytes(self._k1) # Initialize CBC cipher with zero IV self._cbc = ciphermod.new(key, ciphermod.MODE_CBC, zero_block, **self._cipher_params) # Cache for outstanding data to authenticate self._cache = b"" # Last two pieces of ciphertext produced self._last_ct = self._last_pt = zero_block self._before_last_ct = None # Counter for total message size self._data_size = 0 if msg: self.update(msg)