_mode_openpgp.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2014, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. """
  31. OpenPGP mode.
  32. """
  33. __all__ = ['OpenPgpMode']
  34. from tls.Crypto.Util.py3compat import _copy_bytes
  35. from tls.Crypto.Random import get_random_bytes
  36. class OpenPgpMode(object):
  37. """OpenPGP mode.
  38. This mode is a variant of CFB, and it is only used in PGP and
  39. OpenPGP_ applications. If in doubt, use another mode.
  40. An Initialization Vector (*IV*) is required.
  41. Unlike CFB, the *encrypted* IV (not the IV itself) is
  42. transmitted to the receiver.
  43. The IV is a random data block. For legacy reasons, two of its bytes are
  44. duplicated to act as a checksum for the correctness of the key, which is now
  45. known to be insecure and is ignored. The encrypted IV is therefore 2 bytes
  46. longer than the clean IV.
  47. .. _OpenPGP: http://tools.ietf.org/html/rfc4880
  48. :undocumented: __init__
  49. """
  50. def __init__(self, factory, key, iv, cipher_params):
  51. #: The block size of the underlying cipher, in bytes.
  52. self.block_size = factory.block_size
  53. self._done_first_block = False # True after the first encryption
  54. # Instantiate a temporary cipher to process the IV
  55. IV_cipher = factory.new(
  56. key,
  57. factory.MODE_CFB,
  58. IV=b'\x00' * self.block_size,
  59. segment_size=self.block_size * 8,
  60. **cipher_params)
  61. iv = _copy_bytes(None, None, iv)
  62. # The cipher will be used for...
  63. if len(iv) == self.block_size:
  64. # ... encryption
  65. self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:])
  66. elif len(iv) == self.block_size + 2:
  67. # ... decryption
  68. self._encrypted_IV = iv
  69. # Last two bytes are for a deprecated "quick check" feature that
  70. # should not be used. (https://eprint.iacr.org/2005/033)
  71. iv = IV_cipher.decrypt(iv)[:-2]
  72. else:
  73. raise ValueError("Length of IV must be %d or %d bytes"
  74. " for MODE_OPENPGP"
  75. % (self.block_size, self.block_size + 2))
  76. self.iv = self.IV = iv
  77. # Instantiate the cipher for the real PGP data
  78. self._cipher = factory.new(
  79. key,
  80. factory.MODE_CFB,
  81. IV=self._encrypted_IV[-self.block_size:],
  82. segment_size=self.block_size * 8,
  83. **cipher_params)
  84. def encrypt(self, plaintext):
  85. """Encrypt data with the key and the parameters set at initialization.
  86. A cipher object is stateful: once you have encrypted a message
  87. you cannot encrypt (or decrypt) another message using the same
  88. object.
  89. The data to encrypt can be broken up in two or
  90. more pieces and `encrypt` can be called multiple times.
  91. That is, the statement:
  92. >>> c.encrypt(a) + c.encrypt(b)
  93. is equivalent to:
  94. >>> c.encrypt(a+b)
  95. This function does not add any padding to the plaintext.
  96. :Parameters:
  97. plaintext : bytes/bytearray/memoryview
  98. The piece of data to encrypt.
  99. :Return:
  100. the encrypted data, as a byte string.
  101. It is as long as *plaintext* with one exception:
  102. when encrypting the first message chunk,
  103. the encypted IV is prepended to the returned ciphertext.
  104. """
  105. res = self._cipher.encrypt(plaintext)
  106. if not self._done_first_block:
  107. res = self._encrypted_IV + res
  108. self._done_first_block = True
  109. return res
  110. def decrypt(self, ciphertext):
  111. """Decrypt data with the key and the parameters set at initialization.
  112. A cipher object is stateful: once you have decrypted a message
  113. you cannot decrypt (or encrypt) another message with the same
  114. object.
  115. The data to decrypt can be broken up in two or
  116. more pieces and `decrypt` can be called multiple times.
  117. That is, the statement:
  118. >>> c.decrypt(a) + c.decrypt(b)
  119. is equivalent to:
  120. >>> c.decrypt(a+b)
  121. This function does not remove any padding from the plaintext.
  122. :Parameters:
  123. ciphertext : bytes/bytearray/memoryview
  124. The piece of data to decrypt.
  125. :Return: the decrypted data (byte string).
  126. """
  127. return self._cipher.decrypt(ciphertext)
  128. def _create_openpgp_cipher(factory, **kwargs):
  129. """Create a new block cipher, configured in OpenPGP mode.
  130. :Parameters:
  131. factory : module
  132. The module.
  133. :Keywords:
  134. key : bytes/bytearray/memoryview
  135. The secret key to use in the symmetric cipher.
  136. IV : bytes/bytearray/memoryview
  137. The initialization vector to use for encryption or decryption.
  138. For encryption, the IV must be as long as the cipher block size.
  139. For decryption, it must be 2 bytes longer (it is actually the
  140. *encrypted* IV which was prefixed to the ciphertext).
  141. """
  142. iv = kwargs.pop("IV", None)
  143. IV = kwargs.pop("iv", None)
  144. if (None, None) == (iv, IV):
  145. iv = get_random_bytes(factory.block_size)
  146. if iv is not None:
  147. if IV is not None:
  148. raise TypeError("You must either use 'iv' or 'IV', not both")
  149. else:
  150. iv = IV
  151. try:
  152. key = kwargs.pop("key")
  153. except KeyError as e:
  154. raise TypeError("Missing component: " + str(e))
  155. return OpenPgpMode(factory, key, iv, kwargs)