Beispiel #1
0
    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(bstr(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 += 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 __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 = bstr(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)
Beispiel #3
0
    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) + bstr(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)
Beispiel #4
0
    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) + bstr(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)
Beispiel #5
0
    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 : byte string/array
            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 = bstr(initial_counter_block[:prefix_len])
            """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]
Beispiel #6
0
    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 : byte string/array
            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 += bstr(assoc_data[:filler])
            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 = bstr(assoc_data[update_len:])
        self._update(assoc_data, update_len)
        return self
Beispiel #7
0
def bcrypt(password, cost, salt=None):
    """Hash a password into a key, using the OpenBSD bcrypt protocol.

    Args:
      password (byte string or string):
        The secret password or pass phrase.
        It must be at most 72 bytes long.
        It must not contain the zero byte.
        Unicode strings will be encoded as UTF-8.
      cost (integer):
        The exponential factor that makes it slower to compute the hash.
        It must be in the range 4 to 31.
      salt (byte string):
        Optional. Random byte string to thwarts dictionary and rainbow table
        attacks. It must be 16 bytes long.
        If not passed, a random value is generated.

    Return (byte string):
        The bcrypt hash

    Raises:
        ValueError: if password is longer than 72 bytes or if it contains the
        zero byte

    Note:
        If you want to hash passwords with no restrictions on their length, it
        is common practice to apply a cryptographic hash and then BASE64-encode
        the result. For instance::

            from base64 import b64encode
            from Crypto.Hash import SHA256
            from Crypto.Protocol.KDF import bcrypt

            password = b"test"
            b64pwd = b64encode(SHA256.new(password).digest())
            bcrypt_hash = bcrypt(b64pwd, 10)
    """

    password = tobytes(password, "utf-8")

    if password.find(bchr(0)[0]) != -1:
        raise ValueError("The password contains the zero byte")

    if len(password) < 72:
        password += b"\x00"

    if salt is None:
        salt = get_random_bytes(16)
    if len(salt) != 16:
        raise ValueError("bcrypt salt must be 16 bytes long")

    ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt", True)

    cost_enc = b"$" + bstr(str(cost).zfill(2))
    salt_enc = b"$" + _bcrypt_encode(salt)
    hash_enc = _bcrypt_encode(ctext[:-1])     # only use 23 bytes, not 24
    return b"$2a" + cost_enc + salt_enc + hash_enc
    def _create_ctr_cipher(self, mac_tag):
        """Create a new CTR cipher from the MAC in SIV mode"""

        tag_int = bytes_to_long(bstr(mac_tag))
        return self._factory.new(self._subkey_cipher,
                                 self._factory.MODE_CTR,
                                 initial_value=tag_int ^
                                 (tag_int & 0x8000000080000000),
                                 nonce=b(""),
                                 **self._cipher_params)
Beispiel #9
0
    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 += bstr(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(c_uint8_ptr(in_data), trans_len,
                                          trans_func, trans_desc)
        if prefix:
            result = prefix + result

        # Left-over
        self._cache_P = bstr(in_data[trans_len:])

        return result
Beispiel #10
0
    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 : byte string/array
            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 = bstr(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 ]
Beispiel #11
0
def bcrypt(password, cost, salt=None):
    """Hash a password into a key, using the OpenBSD bcrypt protocol.

    Args:
      password (byte string or string):
        The secret password or pass phrase.
        It must be at most 72 bytes long.
        It must not contain the zero byte.
        Unicode strings will be encoded as UTF-8.
      cost (integer):
        The exponential factor that makes it slower to compute the hash.
        It must be in the range 4 to 31.
        A value of at least 12 is recommended.
      salt (byte string):
        Optional. Random byte string to thwarts dictionary and rainbow table
        attacks. It must be 16 bytes long.
        If not passed, a random value is generated.

    Return (byte string):
        The bcrypt hash

    Raises:
        ValueError: if password is longer than 72 bytes or if it contains the zero byte

   """

    password = tobytes(password, "utf-8")

    if password.find(bchr(0)[0]) != -1:
        raise ValueError("The password contains the zero byte")

    if len(password) < 72:
        password += b"\x00"

    if salt is None:
        salt = get_random_bytes(16)
    if len(salt) != 16:
        raise ValueError("bcrypt salt must be 16 bytes long")

    ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt",
                         True)

    cost_enc = b"$" + bstr(str(cost).zfill(2))
    salt_enc = b"$" + _bcrypt_encode(salt)
    hash_enc = _bcrypt_encode(ctext[:-1])  # only use 23 bytes, not 24
    return b"$2a" + cost_enc + salt_enc + hash_enc
Beispiel #12
0
    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 = bstr(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 isinstance(nonce, unicode):
            raise TypeError("nonce must be a byte string")

        self._omac = [
            CMAC.new(key,
                     bchr(0) * (self.block_size - 1) + bchr(i),
                     ciphermod=factory,
                     cipher_params=cipher_params) for i in xrange(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)
Beispiel #13
0
    def __init__(self, key, nonce):
        """Initialize a ChaCha20 cipher object

        See also `new()` at the module level."""

        self.nonce = bstr(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)
Beispiel #14
0
def _create_base_cipher(dict_parameters):
    """This method instantiates and returns a handle to a low-level base cipher.
    It will absorb named parameters in the process."""

    try:
        key_in = dict_parameters.pop("key")
    except KeyError:
        raise TypeError("Missing 'key' parameter")

    key = adjust_key_parity(bstr(key_in))

    start_operation = _raw_des3_lib.DES3_start_operation
    stop_operation = _raw_des3_lib.DES3_stop_operation

    cipher = VoidPointer()
    result = start_operation(key, c_size_t(len(key)), cipher.address_of())
    if result:
        raise ValueError("Error %X while instantiating the TDES cipher" %
                         result)
    return SmartPointer(cipher.get(), stop_operation)
    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._nonce = nonce
        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 isinstance(nonce, str):
                raise TypeError(
                    "When provided, the nonce must be a byte string")

            if len(nonce) == 0:
                raise ValueError("When provided, the nonce must be non-empty")

            self.nonce = bstr(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 _create_base_cipher(dict_parameters):
    """This method instantiates and returns a handle to a low-level base cipher.
    It will absorb named parameters in the process."""

    try:
        key_in = dict_parameters.pop("key")
    except KeyError:
        raise TypeError("Missing 'key' parameter")

    key = adjust_key_parity(bstr(key_in))

    start_operation = _raw_des3_lib.DES3_start_operation
    stop_operation = _raw_des3_lib.DES3_stop_operation

    cipher = VoidPointer()
    result = start_operation(key,
                             c_size_t(len(key)),
                             cipher.address_of())
    if result:
        raise ValueError("Error %X while instantiating the TDES cipher"
                         % result)
    return SmartPointer(cipher.get(), stop_operation)
Beispiel #17
0
def _bcrypt_encode(data):
    s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

    bits = []
    for c in data:
        bits_c = bin(bord(c))[2:].zfill(8)
        bits.append(bstr(bits_c))
    bits = b"".join(bits)

    bits6 = [bits[idx:idx + 6] for idx in range(0, len(bits), 6)]

    result = []
    for g in bits6[:-1]:
        idx = int(g, 2)
        result.append(s[idx])

    g = bits6[-1]
    idx = int(g, 2) << (6 - len(g))
    result.append(s[idx])
    result = "".join(result)

    return tobytes(result)
    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=bchr(0) * self.block_size,
                                segment_size=self.block_size * 8,
                                **cipher_params)

        # 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 = bstr(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)
Beispiel #19
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 = bstr(nonce)
        """Nonce used for this session."""
        if len(nonce) not in list(range(1, 16)):
            raise ValueError("Nonce must be at most 15 bytes long")
        if isinstance(nonce, str):
            raise TypeError("Nonce must be a byte string")

        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()
Beispiel #20
0
    def __init__(self, factory, key, nonce, mac_len, cipher_params):

        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 isinstance(nonce, unicode):
            raise TypeError("Nonce must be a byte string")

        self.nonce = bstr(nonce)
        """Nonce"""

        self._factory = factory
        self._key = bstr(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(bchr(0) * 16)

        # Step 2 - Compute J0 (integer, not byte string!)
        if len(self.nonce) == 12:
            self._j0 = bytes_to_long(self.nonce + b("\x00\x00\x00\x01"))
        else:
            fill = (16 - (len(nonce) % 16)) % 16 + 8
            ghash_in = (self.nonce + bchr(0) * fill +
                        long_to_bytes(8 * len(self.nonce), 8))
            self._j0 = bytes_to_long(
                _GHASH(hash_subkey).update(ghash_in).digest())

        # Step 3 - Prepare GCTR cipher for encryption/decryption
        self._cipher = factory.new(key,
                                   self._factory.MODE_CTR,
                                   initial_value=self._j0 + 1,
                                   nonce=b(""),
                                   **cipher_params)

        # Step 5 - Bootstrat GHASH
        self._signer = _GHASH(hash_subkey)

        # Step 6 - Prepare GCTR cipher for GMAC
        self._tag_cipher = factory.new(key,
                                       self._factory.MODE_CTR,
                                       initial_value=self._j0,
                                       nonce=b(""),
                                       **cipher_params)

        # Cache for data to authenticate
        self._cache = b("")

        self._status = MacStatus.PROCESSING_AUTH_DATA
Beispiel #21
0
    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 = bstr(nonce)
        """The nonce used for this cipher instance"""

        self._factory = factory
        self._key = bstr(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=bchr(0) * 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, 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=bchr(q - 1) + nonce,
                                         **cipher_params)

        # S_0, step 6 in 6.1 for j=0
        self._s_0 = self._cipher.encrypt(bchr(0) * 16)

        # Try to start the MAC
        if None not in (assoc_len, msg_len):
            self._start_mac()