| 
									
										
										
										
											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 | 
					
						
							|  |  |  | from Crypto.Hash import SHA3_224 as SHA3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Constant-time comparison | 
					
						
							|  |  |  |         if SHA3.new(self._mac_tag).digest() != SHA3.new(received_mac_tag).digest(): | 
					
						
							|  |  |  |             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) |