2014-12-08 12:06:28 +01:00
|
|
|
# ===================================================================
|
|
|
|
#
|
|
|
|
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions
|
|
|
|
# are met:
|
|
|
|
#
|
|
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer.
|
|
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer in
|
|
|
|
# the documentation and/or other materials provided with the
|
|
|
|
# distribution.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
# ===================================================================
|
|
|
|
|
|
|
|
"""
|
|
|
|
Counter with CBC-MAC (CCM) mode.
|
|
|
|
"""
|
|
|
|
|
2015-03-09 21:43:24 +01:00
|
|
|
__all__ = ['CcmMode']
|
|
|
|
|
2014-12-08 12:06:28 +01:00
|
|
|
from Crypto.Util.py3compat import *
|
|
|
|
|
|
|
|
from binascii import unhexlify, hexlify
|
|
|
|
|
|
|
|
from Crypto.Util import Counter
|
|
|
|
from Crypto.Util.strxor import strxor
|
|
|
|
from Crypto.Util.number import long_to_bytes, bytes_to_long
|
|
|
|
|
|
|
|
from Crypto.Hash.CMAC import _SmoothMAC
|
2015-04-12 16:02:50 -04:00
|
|
|
from Crypto.Hash import BLAKE2s
|
|
|
|
from Crypto.Random import get_random_bytes
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
class _CBCMAC(_SmoothMAC):
|
|
|
|
"""MAC class based on CBC-MAC that does not need
|
|
|
|
to operate on data chunks multiple of the block size"""
|
|
|
|
|
2014-12-10 21:40:49 +01:00
|
|
|
def __init__(self, key, cipher_factory, cipher_params):
|
2014-12-08 12:06:28 +01:00
|
|
|
_SmoothMAC.__init__(self, cipher_factory.block_size, None, 0)
|
|
|
|
self._key = key
|
|
|
|
self._factory = cipher_factory
|
2014-12-10 21:40:49 +01:00
|
|
|
self._cipher_params = dict(cipher_params)
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
def ignite(self, data):
|
|
|
|
"""Start the MAC. Data provided here is consumed *before*
|
|
|
|
whatever is already stored in the internal buffer."""
|
|
|
|
|
|
|
|
if self._mac:
|
|
|
|
raise TypeError("ignite() cannot be called twice")
|
|
|
|
|
|
|
|
self._buffer.insert(0, data)
|
|
|
|
self._buffer_len += len(data)
|
2014-12-10 21:40:49 +01:00
|
|
|
self._mac = self._factory.new(self._key,
|
|
|
|
self._factory.MODE_CBC,
|
|
|
|
bchr(0) * 16,
|
|
|
|
**self._cipher_params)
|
2014-12-08 12:06:28 +01:00
|
|
|
self.update(b(""))
|
|
|
|
|
|
|
|
def _update(self, block_data):
|
|
|
|
self._t = self._mac.encrypt(block_data)[-16:]
|
|
|
|
|
|
|
|
def _digest(self, left_data):
|
|
|
|
return self._t
|
|
|
|
|
|
|
|
|
2015-03-09 21:43:24 +01:00
|
|
|
class CcmMode(object):
|
2014-12-08 12:06:28 +01:00
|
|
|
"""Counter with CBC-MAC (CCM).
|
|
|
|
|
|
|
|
This is an Authenticated Encryption with Associated Data (`AEAD`_) mode.
|
|
|
|
It provides both confidentiality and authenticity.
|
|
|
|
|
|
|
|
The header of the message may be left in the clear, if needed, and it will
|
|
|
|
still be subject to authentication. The decryption step tells the receiver
|
|
|
|
if the message comes from a source that really knowns the secret key.
|
|
|
|
Additionally, decryption detects if any part of the message - including the
|
|
|
|
header - has been modified or corrupted.
|
|
|
|
|
|
|
|
This mode requires a nonce. The nonce shall never repeat for two
|
|
|
|
different messages encrypted with the same key, but it does not need
|
|
|
|
to be random.
|
|
|
|
Note that there is a trade-off between the size of the nonce and the
|
|
|
|
maximum size of a single message you can encrypt.
|
|
|
|
|
|
|
|
It is important to use a large nonce if the key is reused across several
|
|
|
|
messages and the nonce is chosen randomly.
|
|
|
|
|
|
|
|
It is acceptable to us a short nonce if the key is only used a few times or
|
|
|
|
if the nonce is taken from a counter.
|
|
|
|
|
|
|
|
The following table shows the trade-off when the nonce is chosen at
|
|
|
|
random. The column on the left shows how many messages it takes
|
|
|
|
for the keystream to repeat **on average**. In practice, you will want to
|
|
|
|
stop using the key way before that.
|
|
|
|
|
|
|
|
+--------------------+---------------+-------------------+
|
|
|
|
| Avg. # of messages | nonce | Max. message |
|
|
|
|
| before keystream | size | size |
|
|
|
|
| repeats | (bytes) | (bytes) |
|
|
|
|
+====================+===============+===================+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^52 | 13 | 64K |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^48 | 12 | 16M |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^44 | 11 | 4G |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^40 | 10 | 1T |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^36 | 9 | 64P |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
2015-03-09 21:43:24 +01:00
|
|
|
| 2^32 | 8 | 16E |
|
2014-12-08 12:06:28 +01:00
|
|
|
+--------------------+---------------+-------------------+
|
|
|
|
|
|
|
|
This mode is only available for ciphers that operate on 128 bits blocks
|
|
|
|
(e.g. AES but not TDES).
|
|
|
|
|
2015-03-09 21:43:24 +01:00
|
|
|
See `NIST SP800-38C`_ or RFC3610_.
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
.. _`NIST SP800-38C`: http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C.pdf
|
|
|
|
.. _RFC3610: https://tools.ietf.org/html/rfc3610
|
|
|
|
.. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, factory, **kwargs):
|
|
|
|
"""Create a new block cipher, configured in CCM mode.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
factory : module
|
2015-03-09 21:43:24 +01:00
|
|
|
A symmetric cipher module from `Crypto.Cipher`
|
|
|
|
(like `Crypto.Cipher.AES`).
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
:Keywords:
|
|
|
|
key : byte string
|
|
|
|
The secret key to use in the symmetric cipher.
|
|
|
|
|
|
|
|
nonce : byte string
|
|
|
|
A mandatory value that must never be reused for any other encryption.
|
|
|
|
|
|
|
|
Its length must be in the range ``[7..13]``.
|
|
|
|
11 or 12 bytes are reasonable values in general. Bear in
|
|
|
|
mind that with CCM there is a trade-off between nonce length and
|
|
|
|
maximum message size.
|
|
|
|
|
|
|
|
mac_len : integer
|
|
|
|
Length of the MAC, in bytes. It must be even and in
|
|
|
|
the range ``[4..16]``. The default is 16.
|
|
|
|
|
|
|
|
msg_len : integer
|
|
|
|
Length of the message to (de)cipher.
|
|
|
|
If not specified, ``encrypt`` or ``decrypt`` may only be called once.
|
|
|
|
|
|
|
|
assoc_len : integer
|
|
|
|
Length of the associated data.
|
|
|
|
If not specified, all data is internally buffered.
|
|
|
|
"""
|
|
|
|
|
|
|
|
#: The block size of the underlying cipher, in bytes.
|
|
|
|
self.block_size = factory.block_size
|
|
|
|
|
|
|
|
self._factory = factory
|
2014-12-10 21:40:49 +01:00
|
|
|
try:
|
|
|
|
self._key = key = kwargs.pop("key")
|
|
|
|
self._nonce = kwargs.pop("nonce") # N
|
|
|
|
except KeyError, e:
|
|
|
|
raise TypeError("Missing parameter: " + str(e))
|
2014-12-08 12:06:28 +01:00
|
|
|
self._mac_len = kwargs.pop("mac_len", self.block_size)
|
|
|
|
self._msg_len = kwargs.pop("msg_len", None) # p
|
|
|
|
self._assoc_len = kwargs.pop("assoc_len", None) # a
|
2014-12-10 21:40:49 +01:00
|
|
|
self._cipher_params = dict(kwargs)
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
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 self._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")
|
|
|
|
|
|
|
|
# Nonce value
|
|
|
|
if not (self._nonce and 7 <= len(self._nonce) <= 13):
|
|
|
|
raise ValueError("Length of parameter 'nonce' must be"
|
|
|
|
" in the range 7..13 bytes")
|
|
|
|
|
2014-12-10 21:40:49 +01:00
|
|
|
self._signer = _CBCMAC(key, factory, self._cipher_params)
|
2014-12-08 12:06:28 +01:00
|
|
|
self._no_more_assoc_data = False # True when all associated data
|
|
|
|
# has been processed
|
|
|
|
|
|
|
|
# Allowed transitions after initialization
|
|
|
|
self._next = [self.update, self.encrypt, self.decrypt,
|
|
|
|
self.digest, self.verify]
|
|
|
|
|
|
|
|
# Try to start CCM
|
|
|
|
self._start_ccm()
|
|
|
|
|
|
|
|
def _start_ccm(self, assoc_len=None, msg_len=None):
|
|
|
|
# CCM mode. This method creates the 2 ciphers used for the MAC
|
|
|
|
# (self._signer) and for the encryption/decryption (self._cipher).
|
|
|
|
#
|
|
|
|
# Member _assoc_buffer may already contain user data that needs to be
|
|
|
|
# authenticated.
|
|
|
|
|
|
|
|
if self._signer.can_reduce():
|
|
|
|
# Already started
|
|
|
|
return
|
|
|
|
if assoc_len is not None:
|
|
|
|
self._assoc_len = assoc_len
|
|
|
|
if msg_len is not None:
|
|
|
|
self._msg_len = msg_len
|
|
|
|
if None in (self._assoc_len, self._msg_len):
|
|
|
|
return
|
|
|
|
|
|
|
|
## 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 * divmod(self._mac_len - 2, 2)[0] +
|
|
|
|
(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)
|
|
|
|
self._signer.ignite(b_0 + assoc_len_encoded) # CBC-MAC will consume
|
|
|
|
# B_0, 'a' and then 'A'
|
|
|
|
|
|
|
|
# Start CTR cipher, by formatting the counter (A.3)
|
|
|
|
prefix = bchr(q - 1) + self._nonce
|
|
|
|
ctr = Counter.new(128 - len(prefix) * 8, prefix, initial_value=0)
|
|
|
|
self._cipher = self._factory.new(self._key,
|
|
|
|
self._factory.MODE_CTR,
|
2014-12-10 21:40:49 +01:00
|
|
|
counter=ctr,
|
|
|
|
**self._cipher_params)
|
2014-12-08 12:06:28 +01:00
|
|
|
|
|
|
|
# S_0, step 6 in 6.1 for j=0
|
|
|
|
self._s_0 = self._cipher.encrypt(bchr(0) * 16)
|
|
|
|
|
|
|
|
def update(self, assoc_data):
|
|
|
|
"""Protect associated data
|
|
|
|
|
|
|
|
If there is any associated data, the caller has to invoke
|
|
|
|
this function 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 is still able to detect any modification to it.
|
|
|
|
In CCM, the *associated data* is also called
|
|
|
|
*additional authenticated data* (AAD).
|
|
|
|
|
|
|
|
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
|
|
|
|
A piece of associated data. There are no restrictions on its size.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.update not in self._next:
|
|
|
|
raise TypeError("update() can only be called"
|
|
|
|
" immediately after initialization")
|
|
|
|
|
|
|
|
self._next = [self.update, self.encrypt, self.decrypt,
|
|
|
|
self.digest, self.verify]
|
|
|
|
|
|
|
|
return self._signer.update(assoc_data)
|
|
|
|
|
|
|
|
def encrypt(self, plaintext):
|
|
|
|
"""Encrypt data with the key set at initialization.
|
|
|
|
|
|
|
|
A cipher object is stateful: once you have encrypted a message
|
|
|
|
you cannot encrypt (or decrypt) another message using the same
|
|
|
|
object.
|
|
|
|
|
|
|
|
This method can be called only **once** if ``msg_len`` was
|
|
|
|
not passed at initialization.
|
|
|
|
|
|
|
|
If ``msg_len`` was given, the data to encrypt can be broken
|
|
|
|
up in two or more pieces and `encrypt` can be called
|
|
|
|
multiple times.
|
|
|
|
|
|
|
|
That is, the statement:
|
|
|
|
|
|
|
|
>>> c.encrypt(a) + c.encrypt(b)
|
|
|
|
|
|
|
|
is equivalent to:
|
|
|
|
|
|
|
|
>>> c.encrypt(a+b)
|
|
|
|
|
|
|
|
This function does not add any padding to the plaintext.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
plaintext : byte string
|
|
|
|
The piece of data to encrypt.
|
|
|
|
It can be of any length.
|
|
|
|
:Return:
|
|
|
|
the encrypted data, as a byte string.
|
|
|
|
It is as long as *plaintext*.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.encrypt not in self._next:
|
|
|
|
raise TypeError("encrypt() can only be called after"
|
|
|
|
" initialization or an update()")
|
|
|
|
self._next = [self.encrypt, self.digest]
|
|
|
|
|
|
|
|
if self._assoc_len is None:
|
|
|
|
self._start_ccm(assoc_len=self._signer.data_signed_so_far())
|
|
|
|
if self._msg_len is None:
|
|
|
|
self._start_ccm(msg_len=len(plaintext))
|
|
|
|
self._next = [self.digest]
|
|
|
|
|
|
|
|
if not self._no_more_assoc_data:
|
|
|
|
# Associated data is concatenated with the least number
|
|
|
|
# of zero bytes (possibly none) to reach alignment to
|
|
|
|
# the 16 byte boundary (A.2.3)
|
|
|
|
self._signer.zero_pad()
|
|
|
|
self._no_more_assoc_data = True
|
|
|
|
|
|
|
|
self._signer.update(plaintext)
|
|
|
|
return self._cipher.encrypt(plaintext)
|
|
|
|
|
|
|
|
def decrypt(self, ciphertext):
|
|
|
|
"""Decrypt data with the key set at initialization.
|
|
|
|
|
|
|
|
A cipher object is stateful: once you have decrypted a message
|
|
|
|
you cannot decrypt (or encrypt) another message with the same
|
|
|
|
object.
|
|
|
|
|
|
|
|
This method can be called only **once** if ``msg_len`` was
|
|
|
|
not passed at initialization.
|
|
|
|
|
|
|
|
If ``msg_len`` was given, the data to decrypt can be
|
|
|
|
broken up in two or more pieces and `decrypt` can be
|
|
|
|
called multiple times.
|
|
|
|
|
|
|
|
That is, the statement:
|
|
|
|
|
|
|
|
>>> c.decrypt(a) + c.decrypt(b)
|
|
|
|
|
|
|
|
is equivalent to:
|
|
|
|
|
|
|
|
>>> c.decrypt(a+b)
|
|
|
|
|
|
|
|
This function does not remove any padding from the plaintext.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
ciphertext : byte string
|
|
|
|
The piece of data to decrypt.
|
|
|
|
It can be of any length.
|
|
|
|
|
|
|
|
:Return: the decrypted data (byte string).
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.decrypt not in self._next:
|
|
|
|
raise TypeError("decrypt() can only be called"
|
|
|
|
" after initialization or an update()")
|
|
|
|
self._next = [self.decrypt, self.verify]
|
|
|
|
|
|
|
|
if self._assoc_len is None:
|
|
|
|
self._start_ccm(assoc_len=self._signer.data_signed_so_far())
|
|
|
|
if self._msg_len is None:
|
|
|
|
self._start_ccm(msg_len=len(ciphertext))
|
|
|
|
self._next = [self.verify]
|
|
|
|
|
|
|
|
if not self._no_more_assoc_data:
|
|
|
|
# Associated data is concatenated with the least number
|
|
|
|
# of zero bytes (possibly none) to reach alignment to
|
|
|
|
# the 16 byte boundary (A.2.3)
|
|
|
|
self._signer.zero_pad()
|
|
|
|
self._no_more_assoc_data = True
|
|
|
|
|
|
|
|
plaintext = self._cipher.decrypt(ciphertext)
|
|
|
|
self._signer.update(plaintext)
|
|
|
|
return plaintext
|
|
|
|
|
|
|
|
def digest(self):
|
|
|
|
"""Compute the *binary* MAC tag.
|
|
|
|
|
|
|
|
The caller invokes this function at the very end.
|
|
|
|
|
|
|
|
This method returns the MAC that shall be sent to the receiver,
|
|
|
|
together with the ciphertext.
|
|
|
|
|
|
|
|
:Return: the MAC, as a byte string.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.digest not in self._next:
|
|
|
|
raise TypeError("digest() cannot be called when decrypting"
|
|
|
|
" or validating a message")
|
|
|
|
self._next = [self.digest]
|
|
|
|
|
|
|
|
if self._mac_tag:
|
|
|
|
return self._mac_tag
|
|
|
|
|
|
|
|
if self._assoc_len is None:
|
|
|
|
self._start_ccm(assoc_len=self._signer.data_signed_so_far())
|
|
|
|
if self._msg_len is None:
|
|
|
|
self._start_ccm(msg_len=0)
|
|
|
|
|
|
|
|
# Both associated data and payload are concatenated with the least
|
|
|
|
# number of zero bytes (possibly none) that align it to the
|
|
|
|
# 16 byte boundary (A.2.2 and A.2.3)
|
|
|
|
self._signer.zero_pad()
|
|
|
|
|
|
|
|
# Step 8 in 6.1 (T xor MSB_Tlen(S_0))
|
|
|
|
self._mac_tag = strxor(self._signer.digest(),
|
|
|
|
self._s_0)[:self._mac_len]
|
|
|
|
|
|
|
|
return self._mac_tag
|
|
|
|
|
|
|
|
def hexdigest(self):
|
|
|
|
"""Compute the *printable* MAC tag.
|
|
|
|
|
|
|
|
This method is like `digest`.
|
|
|
|
|
|
|
|
:Return: the MAC, as a hexadecimal string.
|
|
|
|
"""
|
|
|
|
return "".join(["%02x" % bord(x) for x in self.digest()])
|
|
|
|
|
|
|
|
def verify(self, received_mac_tag):
|
|
|
|
"""Validate the *binary* MAC tag.
|
|
|
|
|
|
|
|
The caller invokes this function at the very end.
|
|
|
|
|
|
|
|
This method checks if the decrypted message is indeed valid
|
|
|
|
(that is, if the key is correct) and it has not been
|
|
|
|
tampered with while in transit.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
received_mac_tag : byte string
|
|
|
|
This is the *binary* MAC, as received from the sender.
|
|
|
|
:Raises ValueError:
|
|
|
|
if the MAC does not match. The message has been tampered with
|
|
|
|
or the key is incorrect.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if self.verify not in self._next:
|
|
|
|
raise TypeError("verify() cannot be called"
|
|
|
|
" when encrypting a message")
|
|
|
|
self._next = [self.verify]
|
|
|
|
|
|
|
|
if not self._mac_tag:
|
|
|
|
|
|
|
|
if self._assoc_len is None:
|
|
|
|
self._start_ccm(assoc_len=self._signer.data_signed_so_far())
|
|
|
|
if self._msg_len is None:
|
|
|
|
self._start_ccm(msg_len=0)
|
|
|
|
|
|
|
|
# Both associated data and payload are concatenated with the least
|
|
|
|
# number of zero bytes (possibly none) that align it to the
|
|
|
|
# 16 byte boundary (A.2.2 and A.2.3)
|
|
|
|
self._signer.zero_pad()
|
|
|
|
|
|
|
|
# Step 8 in 6.1 (T xor MSB_Tlen(S_0))
|
|
|
|
self._mac_tag = strxor(self._signer.digest(),
|
|
|
|
self._s_0)[:self._mac_len]
|
|
|
|
|
2015-04-12 16:02:50 -04:00
|
|
|
secret = get_random_bytes(16)
|
|
|
|
|
|
|
|
mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag)
|
|
|
|
mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag)
|
|
|
|
|
|
|
|
if mac1.digest() != mac2.digest():
|
2014-12-08 12:06:28 +01:00
|
|
|
raise ValueError("MAC check failed")
|
|
|
|
|
|
|
|
def hexverify(self, hex_mac_tag):
|
|
|
|
"""Validate the *printable* MAC tag.
|
|
|
|
|
|
|
|
This method is like `verify`.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
hex_mac_tag : string
|
|
|
|
This is the *printable* MAC, as received from the sender.
|
|
|
|
:Raises ValueError:
|
|
|
|
if the MAC does not match. The message has been tampered with
|
|
|
|
or the key is incorrect.
|
|
|
|
"""
|
|
|
|
|
|
|
|
self.verify(unhexlify(hex_mac_tag))
|
|
|
|
|
|
|
|
def encrypt_and_digest(self, plaintext):
|
|
|
|
"""Perform encrypt() and digest() in one step.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
plaintext : byte string
|
|
|
|
The piece of data to encrypt.
|
|
|
|
:Return:
|
|
|
|
a tuple with two byte strings:
|
|
|
|
|
|
|
|
- the encrypted data
|
|
|
|
- the MAC
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self.encrypt(plaintext), self.digest()
|
|
|
|
|
|
|
|
def decrypt_and_verify(self, ciphertext, received_mac_tag):
|
|
|
|
"""Perform decrypt() and verify() in one step.
|
|
|
|
|
|
|
|
:Parameters:
|
|
|
|
ciphertext : byte string
|
|
|
|
The piece of data to decrypt.
|
|
|
|
received_mac_tag : byte string
|
|
|
|
This is the *binary* MAC, as received from the sender.
|
|
|
|
|
|
|
|
:Return: the decrypted data (byte string).
|
|
|
|
:Raises ValueError:
|
|
|
|
if the MAC does not match. The message has been tampered with
|
|
|
|
or the key is incorrect.
|
|
|
|
"""
|
|
|
|
|
|
|
|
plaintext = self.decrypt(ciphertext)
|
|
|
|
self.verify(received_mac_tag)
|
|
|
|
return plaintext
|
2014-12-16 07:50:48 +01:00
|
|
|
|
|
|
|
|
|
|
|
def _create_ccm_cipher(factory, **kwargs):
|
2015-03-09 21:43:24 +01:00
|
|
|
return CcmMode(factory, **kwargs)
|