updated pycrypto
This commit is contained in:
@@ -31,67 +31,23 @@ encryption.
|
|||||||
As an example, encryption can be done as follows:
|
As an example, encryption can be done as follows:
|
||||||
|
|
||||||
>>> from Crypto.Cipher import AES
|
>>> from Crypto.Cipher import AES
|
||||||
>>> from Crypto.Random import get_random_bytes
|
>>> from Crypto import Random
|
||||||
>>>
|
>>>
|
||||||
>>> key = b'Sixteen byte key'
|
>>> key = b'Sixteen byte key'
|
||||||
>>> iv = get_random_bytes(16)
|
>>> iv = Random.new().read(AES.block_size)
|
||||||
>>> cipher = AES.new(key, AES.MODE_CFB, iv)
|
>>> cipher = AES.new(key, AES.MODE_CFB, iv)
|
||||||
>>> msg = iv + cipher.encrypt(b'Attack at dawn')
|
>>> msg = iv + cipher.encrypt(b'Attack at dawn')
|
||||||
|
|
||||||
A more complicated example is based on CCM, (see `MODE_CCM`) an `AEAD`_ mode
|
|
||||||
that provides both confidentiality and authentication for a message.
|
|
||||||
It also allows message for the header to remain in the clear, whilst still
|
|
||||||
being authenticated. The encryption is done as follows:
|
|
||||||
|
|
||||||
>>> from Crypto.Cipher import AES
|
|
||||||
>>> from Crypto.Random import get_random_bytes
|
|
||||||
>>>
|
|
||||||
>>>
|
|
||||||
>>> hdr = b'To your eyes only'
|
|
||||||
>>> plaintext = b'Attack at dawn'
|
|
||||||
>>> key = b'Sixteen byte key'
|
|
||||||
>>> nonce = get_random_bytes(11)
|
|
||||||
>>> cipher = AES.new(key, AES.MODE_CCM, nonce)
|
|
||||||
>>> cipher.update(hdr)
|
|
||||||
>>> msg = nonce, hdr, cipher.encrypt(plaintext), cipher.digest()
|
|
||||||
|
|
||||||
We assume that the tuple ``msg`` is transmitted to the receiver:
|
|
||||||
|
|
||||||
>>> nonce, hdr, ciphertext, mac = msg
|
|
||||||
>>> key = b'Sixteen byte key'
|
|
||||||
>>> cipher = AES.new(key, AES.MODE_CCM, nonce)
|
|
||||||
>>> cipher.update(hdr)
|
|
||||||
>>> plaintext = cipher.decrypt(ciphertext)
|
|
||||||
>>> try:
|
|
||||||
>>> cipher.verify(mac)
|
|
||||||
>>> print "The message is authentic: hdr=%s, pt=%s" % (hdr, plaintext)
|
|
||||||
>>> except ValueError:
|
|
||||||
>>> print "Key incorrect or message corrupted"
|
|
||||||
|
|
||||||
.. __: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
|
.. __: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
|
||||||
.. _NIST: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
.. _NIST: http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
|
||||||
.. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
|
|
||||||
|
|
||||||
:undocumented: __revision__, __package__
|
:undocumented: __revision__, __package__
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
from Crypto.Cipher import blockalgo
|
from Crypto.Cipher import blockalgo
|
||||||
from Crypto.Cipher import _AES
|
from Crypto.Cipher import _AES
|
||||||
from Crypto.Util import cpuid
|
|
||||||
# Import _AESNI. If AES-NI is not available or _AESNI has not been built, set
|
|
||||||
# _AESNI to None.
|
|
||||||
try:
|
|
||||||
if cpuid.have_aes_ni():
|
|
||||||
from Crypto.Cipher import _AESNI
|
|
||||||
else:
|
|
||||||
_AESNI = None
|
|
||||||
except ImportError:
|
|
||||||
_AESNI = None
|
|
||||||
|
|
||||||
class AESCipher (blockalgo.BlockAlgo):
|
class AESCipher (blockalgo.BlockAlgo):
|
||||||
"""AES cipher object"""
|
"""AES cipher object"""
|
||||||
@@ -100,17 +56,6 @@ class AESCipher (blockalgo.BlockAlgo):
|
|||||||
"""Initialize an AES cipher object
|
"""Initialize an AES cipher object
|
||||||
|
|
||||||
See also `new()` at the module level."""
|
See also `new()` at the module level."""
|
||||||
|
|
||||||
# Check if the use_aesni was specified.
|
|
||||||
use_aesni = True
|
|
||||||
if kwargs.has_key('use_aesni'):
|
|
||||||
use_aesni = kwargs['use_aesni']
|
|
||||||
del kwargs['use_aesni']
|
|
||||||
|
|
||||||
# Use _AESNI if the user requested AES-NI and it's available
|
|
||||||
if _AESNI is not None and use_aesni:
|
|
||||||
blockalgo.BlockAlgo.__init__(self, _AESNI, key, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
|
blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
|
||||||
|
|
||||||
def new(key, *args, **kwargs):
|
def new(key, *args, **kwargs):
|
||||||
@@ -120,15 +65,11 @@ def new(key, *args, **kwargs):
|
|||||||
key : byte string
|
key : byte string
|
||||||
The secret key to use in the symmetric cipher.
|
The secret key to use in the symmetric cipher.
|
||||||
It must be 16 (*AES-128*), 24 (*AES-192*), or 32 (*AES-256*) bytes long.
|
It must be 16 (*AES-128*), 24 (*AES-192*), or 32 (*AES-256*) bytes long.
|
||||||
|
|
||||||
Only in `MODE_SIV`, it needs to be 32, 48, or 64 bytes long.
|
|
||||||
:Keywords:
|
:Keywords:
|
||||||
mode : a *MODE_** constant
|
mode : a *MODE_** constant
|
||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -138,19 +79,8 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 16 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_CCM`, `MODE_EAX`, `MODE_GCM`, `MODE_SIV`).
|
|
||||||
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
|
|
||||||
For `MODE_CCM`, 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.
|
|
||||||
|
|
||||||
For the other modes, there are no restrictions on its length,
|
|
||||||
but it is recommended to use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of `block_size` bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
@@ -159,20 +89,6 @@ def new(key, *args, **kwargs):
|
|||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
|
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_CCM`). Length of the MAC, in bytes. It must be even and in
|
|
||||||
the range ``[4..16]``. The default is 16.
|
|
||||||
|
|
||||||
(*Only* `MODE_EAX` and `MODE_GCM`). Length of the MAC, in bytes. It must be no
|
|
||||||
larger than 16 bytes (which is the default).
|
|
||||||
msg_len : integer
|
|
||||||
(*Only* `MODE_CCM`). Length of the message to (de)cipher.
|
|
||||||
If not specified, ``encrypt`` or ``decrypt`` may only be called once.
|
|
||||||
assoc_len : integer
|
|
||||||
(*Only* `MODE_CCM`). Length of the associated data.
|
|
||||||
If not specified, all data is internally buffered.
|
|
||||||
use_aesni : boolean
|
|
||||||
Use AES-NI if available.
|
|
||||||
|
|
||||||
:Return: an `AESCipher` object
|
:Return: an `AESCipher` object
|
||||||
"""
|
"""
|
||||||
@@ -192,14 +108,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: Counter with CBC-MAC (CCM) Mode. See `blockalgo.MODE_CCM`.
|
|
||||||
MODE_CCM = 8
|
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Syntethic Initialization Vector (SIV). See `blockalgo.MODE_SIV`.
|
|
||||||
MODE_SIV = 10
|
|
||||||
#: Galois Counter Mode (GCM). See `blockalgo.MODE_GCM`.
|
|
||||||
MODE_GCM = 11
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 16
|
block_size = 16
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -82,8 +82,6 @@ def new(key, *args, **kwargs):
|
|||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -93,19 +91,12 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 8 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_EAX`).
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
There are no restrictions on its length, but it is recommended to
|
|
||||||
use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of `block_size` bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
For better performance, use `Crypto.Util.Counter`.
|
For better performance, use `Crypto.Util.Counter`.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_EAX`). Length of the MAC, in bytes.
|
|
||||||
It must be no larger than 8 (which is the default).
|
|
||||||
segment_size : integer
|
segment_size : integer
|
||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
@@ -132,8 +123,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 8
|
block_size = 8
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ As an example, encryption can be done as follows:
|
|||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
|
||||||
from Crypto.Cipher import _ARC4
|
from Crypto.Cipher import _ARC4
|
||||||
|
|
||||||
class ARC4Cipher:
|
class ARC4Cipher:
|
||||||
@@ -75,18 +74,7 @@ class ARC4Cipher:
|
|||||||
|
|
||||||
See also `new()` at the module level."""
|
See also `new()` at the module level."""
|
||||||
|
|
||||||
if len(args)>0:
|
|
||||||
ndrop = args[0]
|
|
||||||
args = args[1:]
|
|
||||||
else:
|
|
||||||
ndrop = kwargs.get('drop', 0)
|
|
||||||
if ndrop: del kwargs['drop']
|
|
||||||
self._cipher = _ARC4.new(key, *args, **kwargs)
|
self._cipher = _ARC4.new(key, *args, **kwargs)
|
||||||
if ndrop:
|
|
||||||
# This is OK even if the cipher is used for decryption, since encrypt
|
|
||||||
# and decrypt are actually the same thing with ARC4.
|
|
||||||
self._cipher.encrypt(b('\x00')*ndrop)
|
|
||||||
|
|
||||||
self.block_size = self._cipher.block_size
|
self.block_size = self._cipher.block_size
|
||||||
self.key_size = self._cipher.key_size
|
self.key_size = self._cipher.key_size
|
||||||
|
|
||||||
@@ -120,17 +108,8 @@ def new(key, *args, **kwargs):
|
|||||||
The secret key to use in the symmetric cipher.
|
The secret key to use in the symmetric cipher.
|
||||||
It can have any length, with a minimum of 40 bytes.
|
It can have any length, with a minimum of 40 bytes.
|
||||||
Its cryptograpic strength is always capped to 2048 bits (256 bytes).
|
Its cryptograpic strength is always capped to 2048 bits (256 bytes).
|
||||||
:Keywords:
|
|
||||||
drop : integer
|
|
||||||
The amount of bytes to discard from the initial part of the keystream.
|
|
||||||
In fact, such part has been found to be distinguishable from random
|
|
||||||
data (while it shouldn't) and also correlated to key.
|
|
||||||
|
|
||||||
The recommended value is 3072_ bytes. The default value is 0.
|
|
||||||
|
|
||||||
:Return: an `ARC4Cipher` object
|
:Return: an `ARC4Cipher` object
|
||||||
|
|
||||||
.. _3072: http://eprint.iacr.org/2002/067.pdf
|
|
||||||
"""
|
"""
|
||||||
return ARC4Cipher(key, *args, **kwargs)
|
return ARC4Cipher(key, *args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ def new(key, *args, **kwargs):
|
|||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -87,19 +85,12 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 8 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_EAX`).
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
There are no restrictions on its length, but it is recommended to
|
|
||||||
use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of `block_size` bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
For better performance, use `Crypto.Util.Counter`.
|
For better performance, use `Crypto.Util.Counter`.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_EAX`). Length of the MAC, in bytes.
|
|
||||||
It must be no larger than 8 (which is the default).
|
|
||||||
segment_size : integer
|
segment_size : integer
|
||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
@@ -123,8 +114,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 8
|
block_size = 8
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -79,8 +79,6 @@ def new(key, *args, **kwargs):
|
|||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -90,19 +88,12 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 8 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_EAX`).
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
There are no restrictions on its length, but it is recommended to
|
|
||||||
use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of `block_size` bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
For better performance, use `Crypto.Util.Counter`.
|
For better performance, use `Crypto.Util.Counter`.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_EAX`). Length of the MAC, in bytes.
|
|
||||||
It must be no larger than 8 (which is the default).
|
|
||||||
segment_size : integer
|
segment_size : integer
|
||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
@@ -126,8 +117,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 8
|
block_size = 8
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -33,12 +33,12 @@ DES should not be used for new designs. Use `AES`.
|
|||||||
|
|
||||||
As an example, encryption can be done as follows:
|
As an example, encryption can be done as follows:
|
||||||
|
|
||||||
>>> from Crypto.Cipher import DES
|
>>> from Crypto.Cipher import DES3
|
||||||
>>> from Crypto import Random
|
>>> from Crypto import Random
|
||||||
>>>
|
>>>
|
||||||
>>> key = b'-8B key-'
|
>>> key = b'Sixteen byte key'
|
||||||
>>> iv = Random.new().read(DES.block_size)
|
>>> iv = Random.new().read(DES3.block_size)
|
||||||
>>> cipher = DES.new(key, DES.MODE_OFB, iv)
|
>>> cipher = DES3.new(key, DES3.MODE_OFB, iv)
|
||||||
>>> plaintext = b'sona si latine loqueris '
|
>>> plaintext = b'sona si latine loqueris '
|
||||||
>>> msg = iv + cipher.encrypt(plaintext)
|
>>> msg = iv + cipher.encrypt(plaintext)
|
||||||
|
|
||||||
@@ -74,8 +74,6 @@ def new(key, *args, **kwargs):
|
|||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -85,19 +83,12 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 8 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_EAX`).
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
There are no restrictions on its length, but it is recommended to
|
|
||||||
use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of `block_size` bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
For better performance, use `Crypto.Util.Counter`.
|
For better performance, use `Crypto.Util.Counter`.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_EAX`). Length of the MAC, in bytes.
|
|
||||||
It must be no larger than 8 (which is the default).
|
|
||||||
segment_size : integer
|
segment_size : integer
|
||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
@@ -121,8 +112,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 8
|
block_size = 8
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -44,14 +44,14 @@ as `AES`.
|
|||||||
|
|
||||||
As an example, encryption can be done as follows:
|
As an example, encryption can be done as follows:
|
||||||
|
|
||||||
>>> from Crypto.Cipher import DES3
|
>>> from Crypto.Cipher import DES
|
||||||
>>> from Crypto import Random
|
>>> from Crypto import Random
|
||||||
>>> from Crypto.Util import Counter
|
>>> from Crypto.Util import Counter
|
||||||
>>>
|
>>>
|
||||||
>>> key = b'Sixteen byte key'
|
>>> key = b'-8B key-'
|
||||||
>>> nonce = Random.new().read(DES3.block_size/2)
|
>>> nonce = Random.new().read(DES.block_size/2)
|
||||||
>>> ctr = Counter.new(DES3.block_size*8/2, prefix=nonce)
|
>>> ctr = Counter.new(DES.block_size*8/2, prefix=nonce)
|
||||||
>>> cipher = DES3.new(key, DES3.MODE_CTR, counter=ctr)
|
>>> cipher = DES.new(key, DES.MODE_CTR, counter=ctr)
|
||||||
>>> plaintext = b'We are no longer the knights who say ni!'
|
>>> plaintext = b'We are no longer the knights who say ni!'
|
||||||
>>> msg = nonce + cipher.encrypt(plaintext)
|
>>> msg = nonce + cipher.encrypt(plaintext)
|
||||||
|
|
||||||
@@ -87,8 +87,6 @@ def new(key, *args, **kwargs):
|
|||||||
The chaining mode to use for encryption or decryption.
|
The chaining mode to use for encryption or decryption.
|
||||||
Default is `MODE_ECB`.
|
Default is `MODE_ECB`.
|
||||||
IV : byte string
|
IV : byte string
|
||||||
(*Only* `MODE_CBC`, `MODE_CFB`, `MODE_OFB`, `MODE_OPENPGP`).
|
|
||||||
|
|
||||||
The initialization vector to use for encryption or decryption.
|
The initialization vector to use for encryption or decryption.
|
||||||
|
|
||||||
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
It is ignored for `MODE_ECB` and `MODE_CTR`.
|
||||||
@@ -98,19 +96,12 @@ def new(key, *args, **kwargs):
|
|||||||
actually the *encrypted* IV which was prefixed to the ciphertext).
|
actually the *encrypted* IV which was prefixed to the ciphertext).
|
||||||
It is mandatory.
|
It is mandatory.
|
||||||
|
|
||||||
For all other modes, it must be 8 bytes long.
|
For all other modes, it must be `block_size` bytes longs. It is optional and
|
||||||
nonce : byte string
|
when not present it will be given a default value of all zeroes.
|
||||||
(*Only* `MODE_EAX`).
|
|
||||||
A mandatory value that must never be reused for any other encryption.
|
|
||||||
There are no restrictions on its length, but it is recommended to
|
|
||||||
use at least 16 bytes.
|
|
||||||
counter : callable
|
counter : callable
|
||||||
(*Only* `MODE_CTR`). A stateful function that returns the next
|
(*Only* `MODE_CTR`). A stateful function that returns the next
|
||||||
*counter block*, which is a byte string of 8 bytes.
|
*counter block*, which is a byte string of `block_size` bytes.
|
||||||
For better performance, use `Crypto.Util.Counter`.
|
For better performance, use `Crypto.Util.Counter`.
|
||||||
mac_len : integer
|
|
||||||
(*Only* `MODE_EAX`). Length of the MAC, in bytes.
|
|
||||||
It must be no larger than 8 (which is the default).
|
|
||||||
segment_size : integer
|
segment_size : integer
|
||||||
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
|
||||||
are segmented in.
|
are segmented in.
|
||||||
@@ -136,8 +127,6 @@ MODE_OFB = 5
|
|||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
#: OpenPGP Mode. See `blockalgo.MODE_OPENPGP`.
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
#: EAX Mode. See `blockalgo.MODE_EAX`.
|
|
||||||
MODE_EAX = 9
|
|
||||||
#: Size of a data block (in bytes)
|
#: Size of a data block (in bytes)
|
||||||
block_size = 8
|
block_size = 8
|
||||||
#: Size of a key (in bytes)
|
#: Size of a key (in bytes)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ As an example, a sender may encrypt a message in this way:
|
|||||||
>>> from Crypto.Cipher import PKCS1_OAEP
|
>>> from Crypto.Cipher import PKCS1_OAEP
|
||||||
>>> from Crypto.PublicKey import RSA
|
>>> from Crypto.PublicKey import RSA
|
||||||
>>>
|
>>>
|
||||||
>>> message = b'To be encrypted'
|
>>> message = 'To be encrypted'
|
||||||
>>> key = RSA.importKey(open('pubkey.der').read())
|
>>> key = RSA.importKey(open('pubkey.der').read())
|
||||||
>>> cipher = PKCS1_OAEP.new(key)
|
>>> cipher = PKCS1_OAEP.new(key)
|
||||||
>>> ciphertext = cipher.encrypt(message)
|
>>> ciphertext = cipher.encrypt(message)
|
||||||
@@ -55,7 +55,7 @@ __revision__ = "$Id$"
|
|||||||
__all__ = [ 'new', 'PKCS1OAEP_Cipher' ]
|
__all__ = [ 'new', 'PKCS1OAEP_Cipher' ]
|
||||||
|
|
||||||
import Crypto.Signature.PKCS1_PSS
|
import Crypto.Signature.PKCS1_PSS
|
||||||
import Crypto.Hash.SHA1
|
import Crypto.Hash.SHA
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
import Crypto.Util.number
|
import Crypto.Util.number
|
||||||
@@ -75,12 +75,12 @@ class PKCS1OAEP_Cipher:
|
|||||||
hashAlgo : hash object
|
hashAlgo : hash object
|
||||||
The hash function to use. This can be a module under `Crypto.Hash`
|
The hash function to use. This can be a module under `Crypto.Hash`
|
||||||
or an existing hash object created from any of such modules. If not specified,
|
or an existing hash object created from any of such modules. If not specified,
|
||||||
`Crypto.Hash.SHA1` is used.
|
`Crypto.Hash.SHA` (that is, SHA-1) is used.
|
||||||
mgfunc : callable
|
mgfunc : callable
|
||||||
A mask generation function that accepts two parameters: a string to
|
A mask generation function that accepts two parameters: a string to
|
||||||
use as seed, and the lenth of the mask to generate, in bytes.
|
use as seed, and the lenth of the mask to generate, in bytes.
|
||||||
If not specified, the standard MGF1 is used (a safe choice).
|
If not specified, the standard MGF1 is used (a safe choice).
|
||||||
label : byte string
|
label : string
|
||||||
A label to apply to this particular encryption. If not specified,
|
A label to apply to this particular encryption. If not specified,
|
||||||
an empty string is used. Specifying a label does not improve
|
an empty string is used. Specifying a label does not improve
|
||||||
security.
|
security.
|
||||||
@@ -93,7 +93,7 @@ class PKCS1OAEP_Cipher:
|
|||||||
if hashAlgo:
|
if hashAlgo:
|
||||||
self._hashObj = hashAlgo
|
self._hashObj = hashAlgo
|
||||||
else:
|
else:
|
||||||
self._hashObj = Crypto.Hash.SHA1
|
self._hashObj = Crypto.Hash.SHA
|
||||||
|
|
||||||
if mgfunc:
|
if mgfunc:
|
||||||
self._mgf = mgfunc
|
self._mgf = mgfunc
|
||||||
@@ -117,12 +117,12 @@ class PKCS1OAEP_Cipher:
|
|||||||
section 7.1.1 of RFC3447.
|
section 7.1.1 of RFC3447.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
message : byte string
|
message : string
|
||||||
The message to encrypt, also known as plaintext. It can be of
|
The message to encrypt, also known as plaintext. It can be of
|
||||||
variable length, but not longer than the RSA modulus (in bytes)
|
variable length, but not longer than the RSA modulus (in bytes)
|
||||||
minus 2, minus twice the hash output size.
|
minus 2, minus twice the hash output size.
|
||||||
|
|
||||||
:Return: A byte string, the ciphertext in which the message is encrypted.
|
:Return: A string, the ciphertext in which the message is encrypted.
|
||||||
It is as long as the RSA modulus (in bytes).
|
It is as long as the RSA modulus (in bytes).
|
||||||
:Raise ValueError:
|
:Raise ValueError:
|
||||||
If the RSA key length is not sufficiently long to deal with the given
|
If the RSA key length is not sufficiently long to deal with the given
|
||||||
@@ -173,10 +173,10 @@ class PKCS1OAEP_Cipher:
|
|||||||
section 7.1.2 of RFC3447.
|
section 7.1.2 of RFC3447.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
ct : byte string
|
ct : string
|
||||||
The ciphertext that contains the message to recover.
|
The ciphertext that contains the message to recover.
|
||||||
|
|
||||||
:Return: A byte string, the original message.
|
:Return: A string, the original message.
|
||||||
:Raise ValueError:
|
:Raise ValueError:
|
||||||
If the ciphertext length is incorrect, or if the decryption does not
|
If the ciphertext length is incorrect, or if the decryption does not
|
||||||
succeed.
|
succeed.
|
||||||
@@ -238,12 +238,12 @@ def new(key, hashAlgo=None, mgfunc=None, label=b('')):
|
|||||||
hashAlgo : hash object
|
hashAlgo : hash object
|
||||||
The hash function to use. This can be a module under `Crypto.Hash`
|
The hash function to use. This can be a module under `Crypto.Hash`
|
||||||
or an existing hash object created from any of such modules. If not specified,
|
or an existing hash object created from any of such modules. If not specified,
|
||||||
`Crypto.Hash.SHA1` is used.
|
`Crypto.Hash.SHA` (that is, SHA-1) is used.
|
||||||
mgfunc : callable
|
mgfunc : callable
|
||||||
A mask generation function that accepts two parameters: a string to
|
A mask generation function that accepts two parameters: a string to
|
||||||
use as seed, and the lenth of the mask to generate, in bytes.
|
use as seed, and the lenth of the mask to generate, in bytes.
|
||||||
If not specified, the standard MGF1 is used (a safe choice).
|
If not specified, the standard MGF1 is used (a safe choice).
|
||||||
label : byte string
|
label : string
|
||||||
A label to apply to this particular encryption. If not specified,
|
A label to apply to this particular encryption. If not specified,
|
||||||
an empty string is used. Specifying a label does not improve
|
an empty string is used. Specifying a label does not improve
|
||||||
security.
|
security.
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ As an example, a sender may encrypt a message in this way:
|
|||||||
>>> from Crypto.PublicKey import RSA
|
>>> from Crypto.PublicKey import RSA
|
||||||
>>> from Crypto.Hash import SHA
|
>>> from Crypto.Hash import SHA
|
||||||
>>>
|
>>>
|
||||||
>>> message = b'To be encrypted'
|
>>> message = 'To be encrypted'
|
||||||
>>> h = SHA.new(message)
|
>>> h = SHA.new(message)
|
||||||
>>>
|
>>>
|
||||||
>>> key = RSA.importKey(open('pubkey.der').read())
|
>>> key = RSA.importKey(open('pubkey.der').read())
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -24,21 +24,8 @@
|
|||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
from binascii import unhexlify
|
|
||||||
|
|
||||||
from Crypto.Util import Counter
|
|
||||||
from Crypto.Util.strxor import strxor
|
|
||||||
from Crypto.Util.number import long_to_bytes, bytes_to_long
|
|
||||||
import Crypto.Util.Counter
|
|
||||||
from Crypto.Hash import CMAC
|
|
||||||
from Crypto.Hash.CMAC import _SmoothMAC
|
|
||||||
from Crypto.Protocol.KDF import _S2V
|
|
||||||
|
|
||||||
from Crypto.Util import galois
|
|
||||||
|
|
||||||
#: *Electronic Code Book (ECB)*.
|
#: *Electronic Code Book (ECB)*.
|
||||||
#: This is the simplest encryption mode. Each of the plaintext blocks
|
#: This is the simplest encryption mode. Each of the plaintext blocks
|
||||||
#: is directly encrypted into a ciphertext block, independently of
|
#: is directly encrypted into a ciphertext block, independently of
|
||||||
@@ -55,8 +42,8 @@ MODE_ECB = 1
|
|||||||
#: (*IV*) is required.
|
#: (*IV*) is required.
|
||||||
#:
|
#:
|
||||||
#: The *IV* is a data block to be transmitted to the receiver.
|
#: The *IV* is a data block to be transmitted to the receiver.
|
||||||
#: The *IV* can be made public, but it must be authenticated by the receiver
|
#: The *IV* can be made public, but it must be authenticated by the receiver and
|
||||||
#: and it should be picked randomly.
|
#: it should be picked randomly.
|
||||||
#:
|
#:
|
||||||
#: See `NIST SP800-38A`_ , Section 6.2 .
|
#: See `NIST SP800-38A`_ , Section 6.2 .
|
||||||
#:
|
#:
|
||||||
@@ -86,8 +73,7 @@ MODE_PGP = 4
|
|||||||
|
|
||||||
#: *Output FeedBack (OFB)*. This mode is very similar to CBC, but it
|
#: *Output FeedBack (OFB)*. This mode is very similar to CBC, but it
|
||||||
#: transforms the underlying block cipher into a stream cipher.
|
#: transforms the underlying block cipher into a stream cipher.
|
||||||
#: The keystream is the iterated block encryption of an
|
#: The keystream is the iterated block encryption of an Initialization Vector (*IV*).
|
||||||
#: Initialization Vector (*IV*).
|
|
||||||
#:
|
#:
|
||||||
#: The *IV* is a data block to be transmitted to the receiver.
|
#: The *IV* is a data block to be transmitted to the receiver.
|
||||||
#: The *IV* can be made public, but it should be picked randomly.
|
#: The *IV* can be made public, but it should be picked randomly.
|
||||||
@@ -124,399 +110,37 @@ MODE_OFB = 5
|
|||||||
#: .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
#: .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||||
MODE_CTR = 6
|
MODE_CTR = 6
|
||||||
|
|
||||||
#: *OpenPGP CFB*. This mode is a variant of CFB, and it is only used in PGP and
|
#: OpenPGP. This mode is a variant of CFB, and it is only used in PGP and OpenPGP_ applications.
|
||||||
#: OpenPGP_ applications. An Initialization Vector (*IV*) is required.
|
#: An Initialization Vector (*IV*) is required.
|
||||||
#:
|
#:
|
||||||
#: Unlike CFB, the IV is not transmitted to the receiver.
|
#: Unlike CFB, the IV is not transmitted to the receiver. Instead, the *encrypted* IV is.
|
||||||
#: Instead, the *encrypted* IV is.
|
#: The IV is a random data block. Two of its bytes are duplicated to act as a checksum
|
||||||
#: The IV is a random data block. Two of its bytes are duplicated to act
|
#: for the correctness of the key. The encrypted IV is therefore 2 bytes longer than
|
||||||
#: as a checksum for the correctness of the key. The encrypted IV is
|
#: the clean IV.
|
||||||
#: therefore 2 bytes longer than the clean IV.
|
|
||||||
#:
|
#:
|
||||||
#: .. _OpenPGP: http://tools.ietf.org/html/rfc4880
|
#: .. _OpenPGP: http://tools.ietf.org/html/rfc4880
|
||||||
MODE_OPENPGP = 7
|
MODE_OPENPGP = 7
|
||||||
|
|
||||||
#: *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) |
|
|
||||||
#: +====================+===============+===================+
|
|
||||||
#: | 2**52 | 13 | 64K |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | 2**48 | 12 | 16M |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | 2**44 | 11 | 4G |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | 2**40 | 10 | 1T |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | 2**36 | 9 | 64P |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | 2**32 | 8 | 16E |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#:
|
|
||||||
#: This mode is only available for ciphers that operate on 128 bits blocks
|
|
||||||
#: (e.g. AES but not TDES).
|
|
||||||
#:
|
|
||||||
#: See `NIST SP800-38C`_ or RFC3610_ .
|
|
||||||
#:
|
|
||||||
#: .. _`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
|
|
||||||
MODE_CCM = 8
|
|
||||||
|
|
||||||
#: *EAX*. 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.
|
|
||||||
#
|
|
||||||
#: This mode is only available for ciphers that operate on 64 or
|
|
||||||
#: 128 bits blocks.
|
|
||||||
#:
|
|
||||||
#: There are no official standards defining EAX. The implementation is based on
|
|
||||||
#: `a proposal`__ that was presented to NIST.
|
|
||||||
#:
|
|
||||||
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
|
|
||||||
#: .. __: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
|
|
||||||
MODE_EAX = 9
|
|
||||||
|
|
||||||
#: *Synthetic Initialization Vector*. 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.
|
|
||||||
#:
|
|
||||||
#: If the data being encrypted is completely unpredictable to an adversary
|
|
||||||
#: (e.g. a secret key, for key wrapping purposes) a nonce is not strictly
|
|
||||||
#: required.
|
|
||||||
#:
|
|
||||||
#: Otherwise, a nonce has to be provided; the nonce shall never repeat
|
|
||||||
#: for two different messages encrypted with the same key, but it does not
|
|
||||||
#: need to be random.
|
|
||||||
#:
|
|
||||||
#: Unlike other AEAD modes such as CCM, EAX or GCM, accidental reuse of a
|
|
||||||
#: nonce is not catastrophic for the confidentiality of the message. The only
|
|
||||||
#: effect is that an attacker can tell when the same plaintext (and same
|
|
||||||
#: associated data) is protected with the same key.
|
|
||||||
#:
|
|
||||||
#: The length of the MAC is fixed to the block size of the underlying cipher.
|
|
||||||
#: The key size is twice the length of the key of the underlying cipher.
|
|
||||||
#:
|
|
||||||
#: This mode is only available for AES ciphers.
|
|
||||||
#:
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | Cipher | SIV MAC size | SIV key length |
|
|
||||||
#: | | (bytes) | (bytes) |
|
|
||||||
#: +====================+===============+===================+
|
|
||||||
#: | AES-128 | 16 | 32 |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | AES-192 | 16 | 48 |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#: | AES-256 | 16 | 64 |
|
|
||||||
#: +--------------------+---------------+-------------------+
|
|
||||||
#:
|
|
||||||
#: See `RFC5297`_ and the `original paper`__.
|
|
||||||
#:
|
|
||||||
#: .. _RFC5297: https://tools.ietf.org/html/rfc5297
|
|
||||||
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
|
|
||||||
#: .. __: http://www.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf
|
|
||||||
MODE_SIV = 10
|
|
||||||
|
|
||||||
#: *Galois/Counter Mode (GCM)*. 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.
|
|
||||||
#:
|
|
||||||
#: This mode is only available for ciphers that operate on 128 bits blocks
|
|
||||||
#: (e.g. AES but not TDES).
|
|
||||||
#:
|
|
||||||
#: See `NIST SP800-38D`_ .
|
|
||||||
#:
|
|
||||||
#: .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
|
|
||||||
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
|
|
||||||
MODE_GCM = 11
|
|
||||||
|
|
||||||
|
|
||||||
def _getParameter(name, index, args, kwargs, default=None):
|
def _getParameter(name, index, args, kwargs, default=None):
|
||||||
"""Find a parameter in tuple and dictionary arguments a function receives"""
|
"""Find a parameter in tuple and dictionary arguments a function receives"""
|
||||||
|
|
||||||
param = kwargs.get(name)
|
param = kwargs.get(name)
|
||||||
if len(args) > index:
|
if len(args)>index:
|
||||||
if param:
|
if param:
|
||||||
raise TypeError("Parameter '%s' is specified twice" % name)
|
raise ValueError("Parameter '%s' is specified twice" % name)
|
||||||
param = args[index]
|
param = args[index]
|
||||||
return param or default
|
return param or default
|
||||||
|
|
||||||
|
|
||||||
class _CBCMAC(_SmoothMAC):
|
|
||||||
|
|
||||||
def __init__(self, key, ciphermod):
|
|
||||||
_SmoothMAC.__init__(self, ciphermod.block_size, None, 0)
|
|
||||||
self._key = key
|
|
||||||
self._factory = ciphermod
|
|
||||||
|
|
||||||
def _ignite(self, data):
|
|
||||||
if self._mac:
|
|
||||||
raise TypeError("_ignite() cannot be called twice")
|
|
||||||
|
|
||||||
self._buffer.insert(0, data)
|
|
||||||
self._buffer_len += len(data)
|
|
||||||
self._mac = self._factory.new(self._key, MODE_CBC, bchr(0) * 16)
|
|
||||||
self.update(b(""))
|
|
||||||
|
|
||||||
def _update(self, block_data):
|
|
||||||
self._t = self._mac.encrypt(block_data)[-16:]
|
|
||||||
|
|
||||||
def _digest(self, left_data):
|
|
||||||
return self._t
|
|
||||||
|
|
||||||
|
|
||||||
class _GHASH(_SmoothMAC):
|
|
||||||
"""GHASH function defined in NIST SP 800-38D, Algorithm 2.
|
|
||||||
|
|
||||||
If X_1, X_2, .. X_m are the blocks of input data, the function
|
|
||||||
computes:
|
|
||||||
|
|
||||||
X_1*H^{m} + X_2*H^{m-1} + ... + X_m*H
|
|
||||||
|
|
||||||
in the Galois field GF(2^256) using the reducing polynomial
|
|
||||||
(x^128 + x^7 + x^2 + x + 1).
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, hash_subkey, block_size, table_size='64K'):
|
|
||||||
_SmoothMAC.__init__(self, block_size, None, 0)
|
|
||||||
if table_size == '64K':
|
|
||||||
self._hash_subkey = galois._ghash_expand(hash_subkey)
|
|
||||||
else:
|
|
||||||
self._hash_subkey = hash_subkey
|
|
||||||
self._last_y = bchr(0) * 16
|
|
||||||
self._mac = galois._ghash
|
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
clone = _GHASH(self._hash_subkey, self._bs, table_size='0K')
|
|
||||||
_SmoothMAC._deep_copy(self, clone)
|
|
||||||
clone._last_y = self._last_y
|
|
||||||
return clone
|
|
||||||
|
|
||||||
def _update(self, block_data):
|
|
||||||
self._last_y = galois._ghash(block_data, self._last_y,
|
|
||||||
self._hash_subkey)
|
|
||||||
|
|
||||||
def _digest(self, left_data):
|
|
||||||
return self._last_y
|
|
||||||
|
|
||||||
|
|
||||||
class BlockAlgo:
|
class BlockAlgo:
|
||||||
"""Class modelling an abstract block cipher."""
|
"""Class modelling an abstract block cipher."""
|
||||||
|
|
||||||
def __init__(self, factory, key, *args, **kwargs):
|
def __init__(self, factory, key, *args, **kwargs):
|
||||||
self.mode = _getParameter('mode', 0, args, kwargs, default=MODE_ECB)
|
self.mode = _getParameter('mode', 0, args, kwargs, default=MODE_ECB)
|
||||||
self.block_size = factory.block_size
|
self.block_size = factory.block_size
|
||||||
self._factory = factory
|
|
||||||
self._tag = None
|
|
||||||
|
|
||||||
if self.mode == MODE_CCM:
|
if self.mode != MODE_OPENPGP:
|
||||||
if self.block_size != 16:
|
|
||||||
raise TypeError("CCM mode is only available for ciphers that operate on 128 bits blocks")
|
|
||||||
|
|
||||||
self._mac_len = kwargs.get('mac_len', 16) # t
|
|
||||||
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")
|
|
||||||
|
|
||||||
self.nonce = _getParameter('nonce', 1, args, kwargs) # N
|
|
||||||
if not (self.nonce and 7 <= len(self.nonce) <= 13):
|
|
||||||
raise ValueError("Length of parameter 'nonce' must be"
|
|
||||||
" in the range 7..13 bytes")
|
|
||||||
|
|
||||||
self._key = key
|
|
||||||
self._msg_len = kwargs.get('msg_len', None) # p
|
|
||||||
self._assoc_len = kwargs.get('assoc_len', None) # a
|
|
||||||
|
|
||||||
self._cipherMAC = _CBCMAC(key, factory)
|
|
||||||
self._done_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()
|
|
||||||
|
|
||||||
elif self.mode == MODE_OPENPGP:
|
|
||||||
self._start_PGP(factory, key, *args, **kwargs)
|
|
||||||
elif self.mode == MODE_EAX:
|
|
||||||
self._start_eax(factory, key, *args, **kwargs)
|
|
||||||
elif self.mode == MODE_SIV:
|
|
||||||
self._start_siv(factory, key, *args, **kwargs)
|
|
||||||
elif self.mode == MODE_GCM:
|
|
||||||
self._start_gcm(factory, key, *args, **kwargs)
|
|
||||||
else:
|
|
||||||
self._cipher = factory.new(key, *args, **kwargs)
|
self._cipher = factory.new(key, *args, **kwargs)
|
||||||
self.IV = self._cipher.IV
|
self.IV = self._cipher.IV
|
||||||
|
|
||||||
def _start_gcm(self, factory, key, *args, **kwargs):
|
|
||||||
|
|
||||||
if self.block_size != 16:
|
|
||||||
raise TypeError("GCM mode is only available for ciphers that operate on 128 bits blocks")
|
|
||||||
|
|
||||||
self.nonce = _getParameter('nonce', 1, args, kwargs)
|
|
||||||
if not self.nonce:
|
|
||||||
raise TypeError("MODE_GCM requires a nonce")
|
|
||||||
|
|
||||||
self._mac_len = kwargs.get('mac_len', 16)
|
|
||||||
if not (self._mac_len and 4 <= self._mac_len <= 16):
|
|
||||||
raise ValueError("Parameter 'mac_len' must not be larger than 16 bytes")
|
|
||||||
|
|
||||||
# Allowed transitions after initialization
|
|
||||||
self._next = [self.update, self.encrypt, self.decrypt,
|
|
||||||
self.digest, self.verify]
|
|
||||||
|
|
||||||
self._done_assoc_data = False
|
|
||||||
|
|
||||||
# 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).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:
|
else:
|
||||||
fill = (16 - (len(self.nonce) % 16)) % 16 + 8
|
|
||||||
ghash_in = (self.nonce +
|
|
||||||
bchr(0) * fill +
|
|
||||||
long_to_bytes(8 * len(self.nonce), 8))
|
|
||||||
|
|
||||||
mac = _GHASH(hash_subkey, factory.block_size, '0K')
|
|
||||||
mac.update(ghash_in)
|
|
||||||
self._j0 = bytes_to_long(mac.digest())
|
|
||||||
|
|
||||||
# Step 3 - Prepare GCTR cipher for encryption/decryption
|
|
||||||
ctr = Counter.new(128, initial_value=self._j0 + 1,
|
|
||||||
allow_wraparound=True)
|
|
||||||
self._cipher = self._factory.new(key, MODE_CTR, counter=ctr)
|
|
||||||
|
|
||||||
# Step 5 - Bootstrat GHASH
|
|
||||||
self._cipherMAC = _GHASH(hash_subkey, factory.block_size, '64K')
|
|
||||||
|
|
||||||
# Step 6 - Prepare GCTR cipher for GMAC
|
|
||||||
ctr = Counter.new(128, initial_value=self._j0, allow_wraparound=True)
|
|
||||||
self._tag_cipher = self._factory.new(key, MODE_CTR, counter=ctr)
|
|
||||||
|
|
||||||
def _start_siv(self, factory, key, *args, **kwargs):
|
|
||||||
|
|
||||||
subkey_size, rem = divmod(len(key), 2)
|
|
||||||
if rem:
|
|
||||||
raise ValueError("MODE_SIV requires a key twice as long as for the underlying cipher")
|
|
||||||
|
|
||||||
# IV is optional
|
|
||||||
self.nonce = _getParameter('nonce', 1, args, kwargs)
|
|
||||||
|
|
||||||
self._cipherMAC = _S2V(key[:subkey_size], ciphermod=factory)
|
|
||||||
self._subkey_ctr = key[subkey_size:]
|
|
||||||
self._mac_len = factory.block_size
|
|
||||||
|
|
||||||
self._cipherMAC = self._cipherMAC
|
|
||||||
|
|
||||||
# Allowed transitions after initialization
|
|
||||||
self._next = [self.update, self.encrypt, self.decrypt,
|
|
||||||
self.digest, self.verify]
|
|
||||||
|
|
||||||
def _siv_ctr_cipher(self, tag):
|
|
||||||
"""Create a new CTR cipher from the MAC in SIV mode"""
|
|
||||||
|
|
||||||
tag_int = bytes_to_long(tag)
|
|
||||||
init_counter = tag_int ^ (tag_int & 0x8000000080000000L)
|
|
||||||
ctr = Counter.new(self._factory.block_size * 8,
|
|
||||||
initial_value=init_counter,
|
|
||||||
allow_wraparound=True)
|
|
||||||
|
|
||||||
return self._factory.new(self._subkey_ctr, MODE_CTR, counter=ctr)
|
|
||||||
|
|
||||||
def _start_eax(self, factory, key, *args, **kwargs):
|
|
||||||
|
|
||||||
self.nonce = _getParameter('nonce', 1, args, kwargs)
|
|
||||||
if not self.nonce:
|
|
||||||
raise TypeError("MODE_EAX requires a nonce")
|
|
||||||
|
|
||||||
# Allowed transitions after initialization
|
|
||||||
self._next = [self.update, self.encrypt, self.decrypt,
|
|
||||||
self.digest, self.verify]
|
|
||||||
|
|
||||||
self._mac_len = kwargs.get('mac_len', self.block_size)
|
|
||||||
if not (self._mac_len and 4 <= self._mac_len <= self.block_size):
|
|
||||||
raise ValueError("Parameter 'mac_len' must not be larger than %d"
|
|
||||||
% self.block_size)
|
|
||||||
|
|
||||||
self._omac = [
|
|
||||||
CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i),
|
|
||||||
ciphermod=factory)
|
|
||||||
for i in xrange(0, 3)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Compute MAC of nonce
|
|
||||||
self._omac[0].update(self.nonce)
|
|
||||||
|
|
||||||
self._cipherMAC = self._omac[1]
|
|
||||||
|
|
||||||
# MAC of the nonce is also the initial counter for CTR encryption
|
|
||||||
counter_int = bytes_to_long(self._omac[0].digest())
|
|
||||||
counter_obj = Crypto.Util.Counter.new(
|
|
||||||
self.block_size * 8,
|
|
||||||
initial_value=counter_int,
|
|
||||||
allow_wraparound=True)
|
|
||||||
self._cipher = factory.new(key, MODE_CTR, counter=counter_obj)
|
|
||||||
|
|
||||||
def _start_PGP(self, factory, key, *args, **kwargs):
|
|
||||||
# OPENPGP mode. For details, see 13.9 in RCC4880.
|
# OPENPGP mode. For details, see 13.9 in RCC4880.
|
||||||
#
|
#
|
||||||
# A few members are specifically created for this mode:
|
# A few members are specifically created for this mode:
|
||||||
@@ -526,38 +150,28 @@ class BlockAlgo:
|
|||||||
|
|
||||||
self._done_first_block = False
|
self._done_first_block = False
|
||||||
self._done_last_block = False
|
self._done_last_block = False
|
||||||
self.IV = _getParameter('IV', 1, args, kwargs)
|
|
||||||
if self.IV is None:
|
|
||||||
# TODO: Decide whether 'IV' or 'iv' should be used going forward,
|
|
||||||
# and deprecate the other. 'IV' is consistent with the rest of
|
|
||||||
# PyCrypto, but 'iv' is more common in Python generally. For now,
|
|
||||||
# we'll support both here. When in doubt, use a positional
|
|
||||||
# parameter for now.
|
|
||||||
self.IV = _getParameter('iv', 1, args, kwargs)
|
self.IV = _getParameter('iv', 1, args, kwargs)
|
||||||
if not self.IV:
|
if not self.IV:
|
||||||
raise ValueError("MODE_OPENPGP requires an IV")
|
raise ValueError("MODE_OPENPGP requires an IV")
|
||||||
|
|
||||||
# Instantiate a temporary cipher to process the IV
|
# Instantiate a temporary cipher to process the IV
|
||||||
IV_cipher = factory.new(
|
IV_cipher = factory.new(key, MODE_CFB,
|
||||||
key,
|
b('\x00')*self.block_size, # IV for CFB
|
||||||
MODE_CFB,
|
segment_size=self.block_size*8)
|
||||||
b('\x00') * self.block_size, # IV for CFB
|
|
||||||
segment_size=self.block_size * 8)
|
|
||||||
|
|
||||||
# The cipher will be used for...
|
# The cipher will be used for...
|
||||||
if len(self.IV) == self.block_size:
|
if len(self.IV) == self.block_size:
|
||||||
# ... encryption
|
# ... encryption
|
||||||
self._encrypted_IV = IV_cipher.encrypt(
|
self._encrypted_IV = IV_cipher.encrypt(
|
||||||
self.IV + self.IV[-2:] + # Plaintext
|
self.IV + self.IV[-2:] + # Plaintext
|
||||||
b('\x00') * (self.block_size - 2) # Padding
|
b('\x00')*(self.block_size-2) # Padding
|
||||||
)[:self.block_size + 2]
|
)[:self.block_size+2]
|
||||||
elif len(self.IV) == self.block_size + 2:
|
elif len(self.IV) == self.block_size+2:
|
||||||
# ... decryption
|
# ... decryption
|
||||||
self._encrypted_IV = self.IV
|
self._encrypted_IV = self.IV
|
||||||
self.IV = IV_cipher.decrypt(
|
self.IV = IV_cipher.decrypt(self.IV + # Ciphertext
|
||||||
self.IV + # Ciphertext
|
b('\x00')*(self.block_size-2) # Padding
|
||||||
b('\x00') * (self.block_size - 2) # Padding
|
)[:self.block_size+2]
|
||||||
)[:self.block_size + 2]
|
|
||||||
if self.IV[-2:] != self.IV[-4:-2]:
|
if self.IV[-2:] != self.IV[-4:-2]:
|
||||||
raise ValueError("Failed integrity check for OPENPGP IV")
|
raise ValueError("Failed integrity check for OPENPGP IV")
|
||||||
self.IV = self.IV[:-2]
|
self.IV = self.IV[:-2]
|
||||||
@@ -566,132 +180,35 @@ class BlockAlgo:
|
|||||||
% (self.block_size, self.block_size+2))
|
% (self.block_size, self.block_size+2))
|
||||||
|
|
||||||
# Instantiate the cipher for the real PGP data
|
# Instantiate the cipher for the real PGP data
|
||||||
self._cipher = factory.new(
|
self._cipher = factory.new(key, MODE_CFB,
|
||||||
key,
|
|
||||||
MODE_CFB,
|
|
||||||
self._encrypted_IV[-self.block_size:],
|
self._encrypted_IV[-self.block_size:],
|
||||||
segment_size=self.block_size * 8
|
segment_size=self.block_size*8)
|
||||||
)
|
|
||||||
|
|
||||||
def _start_ccm(self, assoc_len=None, msg_len=None):
|
|
||||||
# CCM mode. This method creates the 2 ciphers used for the MAC
|
|
||||||
# (self._cipherMAC) and for the encryption/decryption (self._cipher).
|
|
||||||
#
|
|
||||||
# Member _assoc_buffer may already contain user data that needs to be
|
|
||||||
# authenticated.
|
|
||||||
|
|
||||||
if self._cipherMAC.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
|
|
||||||
|
|
||||||
# q is the length of Q, the encoding of the message length
|
|
||||||
q = 15 - len(self.nonce)
|
|
||||||
|
|
||||||
## Compute B_0
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Start CBC MAC with zero IV
|
|
||||||
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._cipherMAC._ignite(b_0 + assoc_len_encoded)
|
|
||||||
|
|
||||||
# Start CTR cipher
|
|
||||||
prefix = bchr(q - 1) + self.nonce
|
|
||||||
ctr = Counter.new(128 - len(prefix) * 8, prefix, initial_value=0)
|
|
||||||
self._cipher = self._factory.new(self._key, MODE_CTR, counter=ctr)
|
|
||||||
# Will XOR against CBC MAC
|
|
||||||
self._s_0 = self._cipher.encrypt(bchr(0) * 16)
|
|
||||||
|
|
||||||
def update(self, assoc_data):
|
|
||||||
"""Protect associated data
|
|
||||||
|
|
||||||
When using an AEAD mode like CCM, EAX, GCM or SIV, and
|
|
||||||
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 and GCM, the *associated data* is also called
|
|
||||||
*additional authenticated data* (AAD).
|
|
||||||
In EAX, the *associated data* is called *header*.
|
|
||||||
|
|
||||||
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.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
|
|
||||||
raise TypeError("update() not supported by this mode of operation")
|
|
||||||
|
|
||||||
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._cipherMAC.update(assoc_data)
|
|
||||||
|
|
||||||
def encrypt(self, plaintext):
|
def encrypt(self, plaintext):
|
||||||
"""Encrypt data with the key and the parameters set at initialization.
|
"""Encrypt data with the key and the parameters set at initialization.
|
||||||
|
|
||||||
A cipher object is stateful: once you have encrypted a message
|
The cipher object is stateful; encryption of a long block
|
||||||
you cannot encrypt (or decrypt) another message using the same
|
of data can be broken up in two or more calls to `encrypt()`.
|
||||||
object.
|
|
||||||
|
|
||||||
For `MODE_SIV` (always) and `MODE_CCM` (when ``msg_len`` was not
|
|
||||||
passed at initialization), this method can be called only **once**.
|
|
||||||
|
|
||||||
For all other modes, the data to encrypt can be broken up in two or
|
|
||||||
more pieces and `encrypt` can be called multiple times.
|
|
||||||
|
|
||||||
That is, the statement:
|
That is, the statement:
|
||||||
|
|
||||||
>>> c.encrypt(a) + c.encrypt(b)
|
>>> c.encrypt(a) + c.encrypt(b)
|
||||||
|
|
||||||
is equivalent to:
|
is always equivalent to:
|
||||||
|
|
||||||
>>> c.encrypt(a+b)
|
>>> c.encrypt(a+b)
|
||||||
|
|
||||||
That also means that you cannot reuse an object for encrypting
|
That also means that you cannot reuse an object for encrypting
|
||||||
or decrypting other data with the same key.
|
or decrypting other data with the same key.
|
||||||
|
|
||||||
This function does not add any padding to the plaintext.
|
This function does not perform any padding.
|
||||||
|
|
||||||
- For `MODE_ECB` and `MODE_CBC`, *plaintext* length (in bytes) must be
|
- For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *plaintext* length
|
||||||
a multiple of *block_size*.
|
(in bytes) must be a multiple of *block_size*.
|
||||||
|
|
||||||
- For `MODE_CFB`, *plaintext* length (in bytes) must be a multiple
|
- For `MODE_CFB`, *plaintext* length (in bytes) must be a multiple
|
||||||
of *segment_size*/8.
|
of *segment_size*/8.
|
||||||
|
|
||||||
- For `MODE_OFB`, `MODE_CTR` and all AEAD modes
|
- For `MODE_CTR`, *plaintext* can be of any length.
|
||||||
*plaintext* can be of any length.
|
|
||||||
|
|
||||||
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
|
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
|
||||||
unless it is the last chunk of the message.
|
unless it is the last chunk of the message.
|
||||||
@@ -708,15 +225,14 @@ class BlockAlgo:
|
|||||||
|
|
||||||
if self.mode == MODE_OPENPGP:
|
if self.mode == MODE_OPENPGP:
|
||||||
padding_length = (self.block_size - len(plaintext) % self.block_size) % self.block_size
|
padding_length = (self.block_size - len(plaintext) % self.block_size) % self.block_size
|
||||||
if padding_length > 0:
|
if padding_length>0:
|
||||||
# CFB mode requires ciphertext to have length multiple
|
# CFB mode requires ciphertext to have length multiple of block size,
|
||||||
# of block size,
|
|
||||||
# but PGP mode allows the last block to be shorter
|
# but PGP mode allows the last block to be shorter
|
||||||
if self._done_last_block:
|
if self._done_last_block:
|
||||||
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
|
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
|
||||||
self.block_size)
|
self.block_size)
|
||||||
self._done_last_block = True
|
self._done_last_block = True
|
||||||
padded = plaintext + b('\x00') * padding_length
|
padded = plaintext + b('\x00')*padding_length
|
||||||
res = self._cipher.encrypt(padded)[:len(plaintext)]
|
res = self._cipher.encrypt(padded)[:len(plaintext)]
|
||||||
else:
|
else:
|
||||||
res = self._cipher.encrypt(plaintext)
|
res = self._cipher.encrypt(plaintext)
|
||||||
@@ -725,312 +241,56 @@ class BlockAlgo:
|
|||||||
self._done_first_block = True
|
self._done_first_block = True
|
||||||
return res
|
return res
|
||||||
|
|
||||||
if self.mode in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
|
return self._cipher.encrypt(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.mode == MODE_CCM:
|
|
||||||
if self._assoc_len is None:
|
|
||||||
self._start_ccm(assoc_len=self._cipherMAC.get_len())
|
|
||||||
if self._msg_len is None:
|
|
||||||
self._start_ccm(msg_len=len(plaintext))
|
|
||||||
self._next = [self.digest]
|
|
||||||
if not self._done_assoc_data:
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
self._done_assoc_data = True
|
|
||||||
|
|
||||||
self._cipherMAC.update(plaintext)
|
|
||||||
|
|
||||||
if self.mode == MODE_SIV:
|
|
||||||
self._next = [self.digest]
|
|
||||||
|
|
||||||
if self.nonce:
|
|
||||||
self._cipherMAC.update(self.nonce)
|
|
||||||
|
|
||||||
self._cipherMAC.update(plaintext)
|
|
||||||
self._cipher = self._siv_ctr_cipher(self._cipherMAC.derive())
|
|
||||||
|
|
||||||
ct = self._cipher.encrypt(plaintext)
|
|
||||||
|
|
||||||
if self.mode == MODE_EAX:
|
|
||||||
self._omac[2].update(ct)
|
|
||||||
|
|
||||||
if self.mode == MODE_GCM:
|
|
||||||
if not self._done_assoc_data:
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
self._done_assoc_data = True
|
|
||||||
self._cipherMAC.update(ct)
|
|
||||||
self._msg_len += len(plaintext)
|
|
||||||
|
|
||||||
return ct
|
|
||||||
|
|
||||||
def decrypt(self, ciphertext):
|
def decrypt(self, ciphertext):
|
||||||
"""Decrypt data with the key and the parameters set at initialization.
|
"""Decrypt data with the key and the parameters set at initialization.
|
||||||
|
|
||||||
A cipher object is stateful: once you have decrypted a message
|
The cipher object is stateful; decryption of a long block
|
||||||
you cannot decrypt (or encrypt) another message with the same
|
of data can be broken up in two or more calls to `decrypt()`.
|
||||||
object.
|
|
||||||
|
|
||||||
For `MODE_SIV` (always) and `MODE_CCM` (when ``msg_len`` was not
|
|
||||||
passed at initialization), this method can be called only **once**.
|
|
||||||
|
|
||||||
For all other modes, the data to decrypt can be broken up in two or
|
|
||||||
more pieces and `decrypt` can be called multiple times.
|
|
||||||
|
|
||||||
That is, the statement:
|
That is, the statement:
|
||||||
|
|
||||||
>>> c.decrypt(a) + c.decrypt(b)
|
>>> c.decrypt(a) + c.decrypt(b)
|
||||||
|
|
||||||
is equivalent to:
|
is always equivalent to:
|
||||||
|
|
||||||
>>> c.decrypt(a+b)
|
>>> c.decrypt(a+b)
|
||||||
|
|
||||||
That also means that you cannot reuse an object for encrypting
|
That also means that you cannot reuse an object for encrypting
|
||||||
or decrypting other data with the same key.
|
or decrypting other data with the same key.
|
||||||
|
|
||||||
This function does not remove any padding from the plaintext.
|
This function does not perform any padding.
|
||||||
|
|
||||||
- For `MODE_ECB` and `MODE_CBC`, *ciphertext* length (in bytes) must
|
- For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *ciphertext* length
|
||||||
be a multiple of *block_size*.
|
(in bytes) must be a multiple of *block_size*.
|
||||||
|
|
||||||
- For `MODE_CFB`, *ciphertext* length (in bytes) must be a multiple
|
- For `MODE_CFB`, *ciphertext* length (in bytes) must be a multiple
|
||||||
of *segment_size*/8.
|
of *segment_size*/8.
|
||||||
|
|
||||||
- For `MODE_OFB`, `MODE_CTR` and all AEAD modes
|
- For `MODE_CTR`, *ciphertext* can be of any length.
|
||||||
*ciphertext* can be of any length.
|
|
||||||
|
|
||||||
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
|
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
|
||||||
unless it is the last chunk of the message.
|
unless it is the last chunk of the message.
|
||||||
|
|
||||||
- For `MODE_SIV`, *ciphertext* can be of any length, but it must also
|
|
||||||
include the MAC (concatenated at the end).
|
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
ciphertext : byte string
|
ciphertext : byte string
|
||||||
The piece of data to decrypt (plus the MAC, for `MODE_SIV` only).
|
The piece of data to decrypt.
|
||||||
|
:Return: the decrypted data (byte string, as long as *ciphertext*).
|
||||||
:Return: the decrypted data (byte string).
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.mode == MODE_OPENPGP:
|
if self.mode == MODE_OPENPGP:
|
||||||
padding_length = (self.block_size - len(ciphertext) % self.block_size) % self.block_size
|
padding_length = (self.block_size - len(ciphertext) % self.block_size) % self.block_size
|
||||||
if padding_length > 0:
|
if padding_length>0:
|
||||||
# CFB mode requires ciphertext to have length multiple
|
# CFB mode requires ciphertext to have length multiple of block size,
|
||||||
# of block size,
|
|
||||||
# but PGP mode allows the last block to be shorter
|
# but PGP mode allows the last block to be shorter
|
||||||
if self._done_last_block:
|
if self._done_last_block:
|
||||||
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
|
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
|
||||||
self.block_size)
|
self.block_size)
|
||||||
self._done_last_block = True
|
self._done_last_block = True
|
||||||
padded = ciphertext + b('\x00') * padding_length
|
padded = ciphertext + b('\x00')*padding_length
|
||||||
res = self._cipher.decrypt(padded)[:len(ciphertext)]
|
res = self._cipher.decrypt(padded)[:len(ciphertext)]
|
||||||
else:
|
else:
|
||||||
res = self._cipher.decrypt(ciphertext)
|
res = self._cipher.decrypt(ciphertext)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
if self.mode == MODE_SIV:
|
return self._cipher.decrypt(ciphertext)
|
||||||
raise TypeError("decrypt() not allowed for SIV mode."
|
|
||||||
" Use decrypt_and_verify() instead.")
|
|
||||||
|
|
||||||
if self.mode in (MODE_CCM, MODE_EAX, MODE_GCM):
|
|
||||||
|
|
||||||
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.mode == MODE_CCM:
|
|
||||||
if self._assoc_len is None:
|
|
||||||
self._start_ccm(assoc_len=self._cipherMAC.get_len())
|
|
||||||
if self._msg_len is None:
|
|
||||||
self._start_ccm(msg_len=len(ciphertext))
|
|
||||||
self._next = [self.verify]
|
|
||||||
if not self._done_assoc_data:
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
self._done_assoc_data = True
|
|
||||||
|
|
||||||
if self.mode == MODE_GCM:
|
|
||||||
if not self._done_assoc_data:
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
self._done_assoc_data = True
|
|
||||||
|
|
||||||
self._cipherMAC.update(ciphertext)
|
|
||||||
self._msg_len += len(ciphertext)
|
|
||||||
|
|
||||||
if self.mode == MODE_EAX:
|
|
||||||
self._omac[2].update(ciphertext)
|
|
||||||
|
|
||||||
pt = self._cipher.decrypt(ciphertext)
|
|
||||||
|
|
||||||
if self.mode == MODE_CCM:
|
|
||||||
self._cipherMAC.update(pt)
|
|
||||||
|
|
||||||
return pt
|
|
||||||
|
|
||||||
def digest(self):
|
|
||||||
"""Compute the *binary* MAC tag in an AEAD mode.
|
|
||||||
|
|
||||||
When using an AEAD mode like CCM or EAX, 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.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
|
|
||||||
raise TypeError("digest() not supported by this mode of operation")
|
|
||||||
|
|
||||||
if self.digest not in self._next:
|
|
||||||
raise TypeError("digest() cannot be called when decrypting or validating a message")
|
|
||||||
self._next = [self.digest]
|
|
||||||
|
|
||||||
return self._compute_mac()
|
|
||||||
|
|
||||||
def _compute_mac(self):
|
|
||||||
"""Compute MAC without any FSM checks."""
|
|
||||||
|
|
||||||
if self._tag:
|
|
||||||
return self._tag
|
|
||||||
|
|
||||||
if self.mode == MODE_CCM:
|
|
||||||
|
|
||||||
if self._assoc_len is None:
|
|
||||||
self._start_ccm(assoc_len=self._cipherMAC.get_len())
|
|
||||||
if self._msg_len is None:
|
|
||||||
self._start_ccm(msg_len=0)
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
self._tag = strxor(self._cipherMAC.digest(),
|
|
||||||
self._s_0)[:self._mac_len]
|
|
||||||
|
|
||||||
if self.mode == MODE_GCM:
|
|
||||||
|
|
||||||
# Step 5 in NIST SP 800-38D, Algorithm 4 - Compute S
|
|
||||||
self._cipherMAC.zero_pad()
|
|
||||||
auth_len = self._cipherMAC.get_len() - self._msg_len
|
|
||||||
for tlen in (auth_len, self._msg_len):
|
|
||||||
self._cipherMAC.update(long_to_bytes(8 * tlen, 8))
|
|
||||||
s_tag = self._cipherMAC.digest()
|
|
||||||
|
|
||||||
# Step 6 - Compute T
|
|
||||||
self._tag = self._tag_cipher.encrypt(s_tag)[:self._mac_len]
|
|
||||||
|
|
||||||
if self.mode == MODE_EAX:
|
|
||||||
tag = bchr(0) * self.block_size
|
|
||||||
for i in xrange(3):
|
|
||||||
tag = strxor(tag, self._omac[i].digest())
|
|
||||||
self._tag = tag[:self._mac_len]
|
|
||||||
|
|
||||||
if self.mode == MODE_SIV:
|
|
||||||
self._tag = self._cipherMAC.derive()
|
|
||||||
|
|
||||||
return self._tag
|
|
||||||
|
|
||||||
def hexdigest(self):
|
|
||||||
"""Compute the *printable* MAC tag in an AEAD mode.
|
|
||||||
|
|
||||||
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, mac_tag):
|
|
||||||
"""Validate the *binary* MAC tag in an AEAD mode.
|
|
||||||
|
|
||||||
When using an AEAD mode like CCM or EAX, 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:
|
|
||||||
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.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
|
|
||||||
raise TypeError("verify() not supported by this mode of operation")
|
|
||||||
|
|
||||||
if self.verify not in self._next:
|
|
||||||
raise TypeError("verify() cannot be called when encrypting a message")
|
|
||||||
self._next = [self.verify]
|
|
||||||
|
|
||||||
res = 0
|
|
||||||
# Constant-time comparison
|
|
||||||
for x, y in zip(self._compute_mac(), mac_tag):
|
|
||||||
res |= bord(x) ^ bord(y)
|
|
||||||
if res or len(mac_tag) != self._mac_len:
|
|
||||||
raise ValueError("MAC check failed")
|
|
||||||
|
|
||||||
def hexverify(self, hex_mac_tag):
|
|
||||||
"""Validate the *printable* MAC tag in an AEAD mode.
|
|
||||||
|
|
||||||
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, mac_tag):
|
|
||||||
"""Perform decrypt() and verify() in one step.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
ciphertext : byte string
|
|
||||||
The piece of data to decrypt.
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self.mode == MODE_SIV:
|
|
||||||
if self.decrypt not in self._next:
|
|
||||||
raise TypeError("decrypt() can only be called"
|
|
||||||
" after initialization or an update()")
|
|
||||||
self._next = [self.verify]
|
|
||||||
|
|
||||||
# Take the MAC and start the cipher for decryption
|
|
||||||
self._mac = mac_tag
|
|
||||||
self._cipher = self._siv_ctr_cipher(self._mac)
|
|
||||||
|
|
||||||
pt = self._cipher.decrypt(ciphertext)
|
|
||||||
|
|
||||||
if self.nonce:
|
|
||||||
self._cipherMAC.update(self.nonce)
|
|
||||||
if pt:
|
|
||||||
self._cipherMAC.update(pt)
|
|
||||||
else:
|
|
||||||
pt = self.decrypt(ciphertext)
|
|
||||||
|
|
||||||
self.verify(mac_tag)
|
|
||||||
return pt
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ The strength of an HMAC depends on:
|
|||||||
- the strength of the hash algorithm
|
- the strength of the hash algorithm
|
||||||
- the length and entropy of the secret key
|
- the length and entropy of the secret key
|
||||||
|
|
||||||
This is an example showing how to *create* a MAC:
|
An example of possible usage is the following:
|
||||||
|
|
||||||
>>> from Crypto.Hash import HMAC
|
>>> from Crypto.Hash import HMAC
|
||||||
>>>
|
>>>
|
||||||
@@ -52,22 +52,6 @@ This is an example showing how to *create* a MAC:
|
|||||||
>>> h.update(b'Hello')
|
>>> h.update(b'Hello')
|
||||||
>>> print h.hexdigest()
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
This is an example showing how to *check* a MAC:
|
|
||||||
|
|
||||||
>>> from Crypto.Hash import HMAC
|
|
||||||
>>>
|
|
||||||
>>> # We have received a message 'msg' together
|
|
||||||
>>> # with its MAC 'mac'
|
|
||||||
>>>
|
|
||||||
>>> secret = b'Swordfish'
|
|
||||||
>>> h = HMAC.new(secret)
|
|
||||||
>>> h.update(msg)
|
|
||||||
>>> try:
|
|
||||||
>>> h.verify(mac)
|
|
||||||
>>> print "The message '%s' is authentic" % msg
|
|
||||||
>>> except ValueError:
|
|
||||||
>>> print "The message or the key is wrong"
|
|
||||||
|
|
||||||
.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt
|
.. _RFC2104: http://www.ietf.org/rfc/rfc2104.txt
|
||||||
.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
|
.. _FIPS-198: http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
|
||||||
"""
|
"""
|
||||||
@@ -79,8 +63,6 @@ __revision__ = "$Id$"
|
|||||||
|
|
||||||
__all__ = ['new', 'digest_size', 'HMAC' ]
|
__all__ = ['new', 'digest_size', 'HMAC' ]
|
||||||
|
|
||||||
from binascii import unhexlify
|
|
||||||
|
|
||||||
from Crypto.Util.strxor import strxor_c
|
from Crypto.Util.strxor import strxor_c
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
@@ -191,30 +173,10 @@ class HMAC:
|
|||||||
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
|
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
|
||||||
characters, including null bytes.
|
characters, including null bytes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
h = self.outer.copy()
|
h = self.outer.copy()
|
||||||
h.update(self.inner.digest())
|
h.update(self.inner.digest())
|
||||||
return h.digest()
|
return h.digest()
|
||||||
|
|
||||||
def verify(self, mac_tag):
|
|
||||||
"""Verify that a given **binary** MAC (computed by another party) is valid.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
mac_tag : byte string
|
|
||||||
The expected MAC of the message.
|
|
||||||
:Raises ValueError:
|
|
||||||
if the MAC does not match. It means that the message
|
|
||||||
has been tampered with or that the MAC key is incorrect.
|
|
||||||
"""
|
|
||||||
|
|
||||||
mac = self.digest()
|
|
||||||
res = 0
|
|
||||||
# Constant-time comparison
|
|
||||||
for x,y in zip(mac, mac_tag):
|
|
||||||
res |= bord(x) ^ bord(y)
|
|
||||||
if res or len(mac_tag)!=self.digest_size:
|
|
||||||
raise ValueError("MAC check failed")
|
|
||||||
|
|
||||||
def hexdigest(self):
|
def hexdigest(self):
|
||||||
"""Return the **printable** MAC of the message that has been
|
"""Return the **printable** MAC of the message that has been
|
||||||
authenticated so far.
|
authenticated so far.
|
||||||
@@ -227,19 +189,6 @@ class HMAC:
|
|||||||
return "".join(["%02x" % bord(x)
|
return "".join(["%02x" % bord(x)
|
||||||
for x in tuple(self.digest())])
|
for x in tuple(self.digest())])
|
||||||
|
|
||||||
def hexverify(self, hex_mac_tag):
|
|
||||||
"""Verify that a given **printable** MAC (computed by another party) is valid.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
hex_mac_tag : string
|
|
||||||
The expected MAC of the message, as a hexadecimal string.
|
|
||||||
:Raises ValueError:
|
|
||||||
if the MAC does not match. It means that the message
|
|
||||||
has been tampered with or that the MAC key is incorrect.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.verify(unhexlify(tobytes(hex_mac_tag)))
|
|
||||||
|
|
||||||
def new(key, msg = None, digestmod = None):
|
def new(key, msg = None, digestmod = None):
|
||||||
"""Create a new HMAC object.
|
"""Create a new HMAC object.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""MD2 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
MD2 is specified in RFC1319_ and it produces the 128 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import MD2
|
||||||
|
>>>
|
||||||
|
>>> h = MD2.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
MD2 stand for Message Digest version 2, and it was invented by Rivest in 1989.
|
||||||
|
|
||||||
|
This algorithm is both slow and insecure. Do not use it for new designs.
|
||||||
|
|
||||||
|
.. _RFC1319: http://tools.ietf.org/html/rfc1319
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'MD2Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
import Crypto.Hash._MD2 as _MD2
|
||||||
|
hashFactory = _MD2
|
||||||
|
|
||||||
|
class MD2Hash(HashAlgo):
|
||||||
|
"""Class that implements an MD2 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-md2 OBJECT IDENTIFIER ::= {
|
||||||
|
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
||||||
|
#: digestAlgorithm(2) 2
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the MD2 algorithm.
|
||||||
|
oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02')
|
||||||
|
|
||||||
|
digest_size = 16
|
||||||
|
block_size = 16
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return MD2Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `MD2Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: An `MD2Hash` object
|
||||||
|
"""
|
||||||
|
return MD2Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = MD2Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = MD2Hash.block_size
|
||||||
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""MD4 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
MD4 is specified in RFC1320_ and produces the 128 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import MD4
|
||||||
|
>>>
|
||||||
|
>>> h = MD4.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990.
|
||||||
|
|
||||||
|
This algorithm is insecure. Do not use it for new designs.
|
||||||
|
|
||||||
|
.. _RFC1320: http://tools.ietf.org/html/rfc1320
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'MD4Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
import Crypto.Hash._MD4 as _MD4
|
||||||
|
hashFactory = _MD4
|
||||||
|
|
||||||
|
class MD4Hash(HashAlgo):
|
||||||
|
"""Class that implements an MD4 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-md2 OBJECT IDENTIFIER ::= {
|
||||||
|
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
||||||
|
#: digestAlgorithm(2) 4
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the MD4 algorithm.
|
||||||
|
oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04')
|
||||||
|
|
||||||
|
digest_size = 16
|
||||||
|
block_size = 64
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return MD4Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `MD4Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `MD4Hash` object
|
||||||
|
"""
|
||||||
|
return MD4Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = MD4Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = MD4Hash.block_size
|
||||||
|
|
||||||
+46
-41
@@ -35,58 +35,63 @@ This algorithm is insecure. Do not use it for new designs.
|
|||||||
.. _RFC1321: http://tools.ietf.org/html/rfc1321
|
.. _RFC1321: http://tools.ietf.org/html/rfc1321
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import nested_scopes
|
|
||||||
|
|
||||||
_revision__ = "$Id$"
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
__all__ = ['new', 'block_size', 'digest_size']
|
__all__ = ['new', 'digest_size', 'MD5Hash' ]
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
|
|
||||||
def __make_constructor():
|
try:
|
||||||
try:
|
|
||||||
# The md5 module is deprecated in Python 2.6, so use hashlib when possible.
|
# The md5 module is deprecated in Python 2.6, so use hashlib when possible.
|
||||||
from hashlib import md5 as _hash_new
|
import hashlib
|
||||||
except ImportError:
|
hashFactory = hashlib.md5
|
||||||
from md5 import new as _hash_new
|
|
||||||
|
except ImportError:
|
||||||
|
import md5
|
||||||
|
hashFactory = md5
|
||||||
|
|
||||||
|
class MD5Hash(HashAlgo):
|
||||||
|
"""Class that implements an MD5 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-md5 OBJECT IDENTIFIER ::= {
|
||||||
|
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
||||||
|
#: digestAlgorithm(2) 5
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the MD5 algorithm.
|
||||||
|
oid = b('\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05')
|
||||||
|
|
||||||
h = _hash_new()
|
|
||||||
if hasattr(h, 'new') and hasattr(h, 'name') and hasattr(h, 'digest_size') and hasattr(h, 'block_size'):
|
|
||||||
# The module from stdlib has the API that we need. Just use it.
|
|
||||||
return _hash_new
|
|
||||||
else:
|
|
||||||
# Wrap the hash object in something that gives us the expected API.
|
|
||||||
_copy_sentinel = object()
|
|
||||||
class _MD5(object):
|
|
||||||
digest_size = 16
|
digest_size = 16
|
||||||
block_size = 64
|
block_size = 64
|
||||||
name = "md5"
|
|
||||||
def __init__(self, *args):
|
|
||||||
if args and args[0] is _copy_sentinel:
|
|
||||||
self._h = args[1]
|
|
||||||
else:
|
|
||||||
self._h = _hash_new(*args)
|
|
||||||
def copy(self):
|
|
||||||
return _MD5(_copy_sentinel, self._h.copy())
|
|
||||||
def update(self, *args):
|
|
||||||
f = self.update = self._h.update
|
|
||||||
f(*args)
|
|
||||||
def digest(self):
|
|
||||||
f = self.digest = self._h.digest
|
|
||||||
return f()
|
|
||||||
def hexdigest(self):
|
|
||||||
f = self.hexdigest = self._h.hexdigest
|
|
||||||
return f()
|
|
||||||
_MD5.new = _MD5
|
|
||||||
return _MD5
|
|
||||||
|
|
||||||
new = __make_constructor()
|
def __init__(self, data=None):
|
||||||
del __make_constructor
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return MD5Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `MD5Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `MD5Hash` object
|
||||||
|
"""
|
||||||
|
return MD5Hash().new(data)
|
||||||
|
|
||||||
#: The size of the resulting hash in bytes.
|
#: The size of the resulting hash in bytes.
|
||||||
digest_size = new().digest_size
|
digest_size = MD5Hash.digest_size
|
||||||
|
|
||||||
#: The internal block size of the hash algorithm in bytes.
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
block_size = new().block_size
|
block_size = MD5Hash.block_size
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,77 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
# This file exists for backward compatibility with old code that refers to
|
"""RIPEMD-160 cryptographic hash algorithm.
|
||||||
# Crypto.Hash.RIPEMD
|
|
||||||
|
|
||||||
"""Deprecated alias for `Crypto.Hash.RIPEMD160`"""
|
RIPEMD-160_ produces the 160 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import RIPEMD
|
||||||
|
>>>
|
||||||
|
>>> h = RIPEMD.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
RIPEMD-160 stands for RACE Integrity Primitives Evaluation Message Digest
|
||||||
|
with a 160 bit digest. It was invented by Dobbertin, Bosselaers, and Preneel.
|
||||||
|
|
||||||
|
This algorithm is considered secure, although it has not been scrutinized as
|
||||||
|
extensively as SHA-1. Moreover, it provides an informal security level of just
|
||||||
|
80bits.
|
||||||
|
|
||||||
|
.. _RIPEMD-160: http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'RIPEMD160Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
import Crypto.Hash._RIPEMD160 as _RIPEMD160
|
||||||
|
hashFactory = _RIPEMD160
|
||||||
|
|
||||||
|
class RIPEMD160Hash(HashAlgo):
|
||||||
|
"""Class that implements a RIPMD-160 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-ripemd160 OBJECT IDENTIFIER ::= {
|
||||||
|
#: iso(1) identified-organization(3) teletrust(36)
|
||||||
|
#: algorithm(3) hashAlgorithm(2) ripemd160(1)
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the RIPMD-160 algorithm.
|
||||||
|
oid = b("\x06\x05\x2b\x24\x03\x02\x01")
|
||||||
|
|
||||||
|
digest_size = 20
|
||||||
|
block_size = 64
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return RIPEMD160Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `RIPEMD160Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `RIPEMD160Hash` object
|
||||||
|
"""
|
||||||
|
return RIPEMD160Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = RIPEMD160Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = RIPEMD160Hash.block_size
|
||||||
|
|
||||||
from Crypto.Hash.RIPEMD160 import new, block_size, digest_size
|
|
||||||
|
|||||||
@@ -18,7 +18,81 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
||||||
# This file exists for backward compatibility with old code that refers to
|
"""SHA-1 cryptographic hash algorithm.
|
||||||
# Crypto.Hash.SHA
|
|
||||||
|
SHA-1_ produces the 160 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import SHA
|
||||||
|
>>>
|
||||||
|
>>> h = SHA.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
*SHA* stands for Secure Hash Algorithm.
|
||||||
|
|
||||||
|
This algorithm is not considered secure. Do not use it for new designs.
|
||||||
|
|
||||||
|
.. _SHA-1: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'SHA1Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
try:
|
||||||
|
# The sha module is deprecated in Python 2.6, so use hashlib when possible.
|
||||||
|
import hashlib
|
||||||
|
hashFactory = hashlib.sha1
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
import sha
|
||||||
|
hashFactory = sha
|
||||||
|
|
||||||
|
class SHA1Hash(HashAlgo):
|
||||||
|
"""Class that implements a SHA-1 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-sha1 OBJECT IDENTIFIER ::= {
|
||||||
|
#: iso(1) identified-organization(3) oiw(14) secsig(3)
|
||||||
|
#: algorithms(2) 26
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the SHA-1 algorithm.
|
||||||
|
oid = b('\x06\x05\x2b\x0e\x03\x02\x1a')
|
||||||
|
|
||||||
|
digest_size = 20
|
||||||
|
block_size = 64
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return SHA1Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `SHA1Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `SHA1Hash` object
|
||||||
|
"""
|
||||||
|
return SHA1Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = SHA1Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = SHA1Hash.block_size
|
||||||
|
|
||||||
|
|
||||||
from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size
|
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""SHA-224 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
SHA-224 belongs to the SHA-2_ family of cryptographic hashes.
|
||||||
|
It produces the 224 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import SHA224
|
||||||
|
>>>
|
||||||
|
>>> h = SHA224.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
*SHA* stands for Secure Hash Algorithm.
|
||||||
|
|
||||||
|
.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'SHA224Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
try:
|
||||||
|
import hashlib
|
||||||
|
hashFactory = hashlib.sha224
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
from Crypto.Hash import _SHA224
|
||||||
|
hashFactory = _SHA224
|
||||||
|
|
||||||
|
class SHA224Hash(HashAlgo):
|
||||||
|
"""Class that implements a SHA-224 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-sha224 OBJECT IDENTIFIER ::= {
|
||||||
|
#: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3)
|
||||||
|
#: nistalgorithm(4) hashalgs(2) 4
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the SHA-224 algorithm.
|
||||||
|
oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04')
|
||||||
|
|
||||||
|
digest_size = 28
|
||||||
|
block_size = 64
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return SHA224Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `SHA224Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `SHA224Hash` object
|
||||||
|
"""
|
||||||
|
return SHA224Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = SHA224Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = SHA224Hash.block_size
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""SHA-256 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
SHA-256 belongs to the SHA-2_ family of cryptographic hashes.
|
||||||
|
It produces the 256 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import SHA256
|
||||||
|
>>>
|
||||||
|
>>> h = SHA256.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
*SHA* stands for Secure Hash Algorithm.
|
||||||
|
|
||||||
|
.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'SHA256Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
try:
|
||||||
|
import hashlib
|
||||||
|
hashFactory = hashlib.sha256
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
from Crypto.Hash import _SHA256
|
||||||
|
hashFactory = _SHA256
|
||||||
|
|
||||||
|
class SHA256Hash(HashAlgo):
|
||||||
|
"""Class that implements a SHA-256 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-sha256 OBJECT IDENTIFIER ::= {
|
||||||
|
#: joint-iso-itu-t(2) country(16) us(840) organization(1)
|
||||||
|
#: gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the SHA-256 algorithm.
|
||||||
|
oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01')
|
||||||
|
|
||||||
|
digest_size = 32
|
||||||
|
block_size = 64
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return SHA256Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `SHA256Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `SHA256Hash` object
|
||||||
|
"""
|
||||||
|
return SHA256Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = SHA256Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = SHA256Hash.block_size
|
||||||
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""SHA-384 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
SHA-384 belongs to the SHA-2_ family of cryptographic hashes.
|
||||||
|
It produces the 384 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import SHA384
|
||||||
|
>>>
|
||||||
|
>>> h = SHA384.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
*SHA* stands for Secure Hash Algorithm.
|
||||||
|
|
||||||
|
.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'SHA384Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
try:
|
||||||
|
import hashlib
|
||||||
|
hashFactory = hashlib.sha384
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
from Crypto.Hash import _SHA384
|
||||||
|
hashFactory = _SHA384
|
||||||
|
|
||||||
|
class SHA384Hash(HashAlgo):
|
||||||
|
"""Class that implements a SHA-384 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-sha384 OBJECT IDENTIFIER ::= {
|
||||||
|
#: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3)
|
||||||
|
#: nistalgorithm(4) hashalgs(2) 2
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the SHA-384 algorithm.
|
||||||
|
oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02')
|
||||||
|
|
||||||
|
digest_size = 48
|
||||||
|
block_size = 128
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return SHA384Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `SHA384Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `SHA384Hash` object
|
||||||
|
"""
|
||||||
|
return SHA384Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = SHA384Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = SHA384Hash.block_size
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""SHA-512 cryptographic hash algorithm.
|
||||||
|
|
||||||
|
SHA-512 belongs to the SHA-2_ family of cryptographic hashes.
|
||||||
|
It produces the 512 bit digest of a message.
|
||||||
|
|
||||||
|
>>> from Crypto.Hash import SHA512
|
||||||
|
>>>
|
||||||
|
>>> h = SHA512.new()
|
||||||
|
>>> h.update(b'Hello')
|
||||||
|
>>> print h.hexdigest()
|
||||||
|
|
||||||
|
*SHA* stands for Secure Hash Algorithm.
|
||||||
|
|
||||||
|
.. _SHA-2: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||||
|
"""
|
||||||
|
|
||||||
|
_revision__ = "$Id$"
|
||||||
|
|
||||||
|
__all__ = ['new', 'digest_size', 'SHA512Hash' ]
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash.hashalgo import HashAlgo
|
||||||
|
|
||||||
|
try:
|
||||||
|
import hashlib
|
||||||
|
hashFactory = hashlib.sha512
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
from Crypto.Hash import _SHA512
|
||||||
|
hashFactory = _SHA512
|
||||||
|
|
||||||
|
class SHA512Hash(HashAlgo):
|
||||||
|
"""Class that implements a SHA-512 hash
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: ASN.1 Object identifier (OID)::
|
||||||
|
#:
|
||||||
|
#: id-sha512 OBJECT IDENTIFIER ::= {
|
||||||
|
#: joint-iso-itu-t(2)
|
||||||
|
#: country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3
|
||||||
|
#: }
|
||||||
|
#:
|
||||||
|
#: This value uniquely identifies the SHA-512 algorithm.
|
||||||
|
oid = b('\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03')
|
||||||
|
|
||||||
|
digest_size = 64
|
||||||
|
block_size = 128
|
||||||
|
|
||||||
|
def __init__(self, data=None):
|
||||||
|
HashAlgo.__init__(self, hashFactory, data)
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
return SHA512Hash(data)
|
||||||
|
|
||||||
|
def new(data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `SHA512Hash.update()`.
|
||||||
|
Optional.
|
||||||
|
|
||||||
|
:Return: A `SHA512Hash` object
|
||||||
|
"""
|
||||||
|
return SHA512Hash().new(data)
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = SHA512Hash.digest_size
|
||||||
|
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = SHA512Hash.block_size
|
||||||
|
|
||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -49,128 +49,8 @@ The hashing modules here all support the interface described in `PEP
|
|||||||
:undocumented: _MD2, _MD4, _RIPEMD160, _SHA224, _SHA256, _SHA384, _SHA512
|
:undocumented: _MD2, _MD4, _RIPEMD160, _SHA224, _SHA256, _SHA384, _SHA512
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1',
|
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD', 'SHA',
|
||||||
'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC']
|
'SHA224', 'SHA256', 'SHA384', 'SHA512']
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
from Crypto.Util.py3compat import *
|
|
||||||
|
|
||||||
def new(algo, *args):
|
|
||||||
"""Initialize a new hash object.
|
|
||||||
|
|
||||||
The first argument to this function may be an algorithm name or another
|
|
||||||
hash object.
|
|
||||||
|
|
||||||
This function has significant overhead. It's recommended that you instead
|
|
||||||
import and use the individual hash modules directly.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Try just invoking algo.new()
|
|
||||||
# We do this first so that this is the fastest.
|
|
||||||
try:
|
|
||||||
new_func = algo.new
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return new_func(*args)
|
|
||||||
|
|
||||||
# Try getting the algorithm name.
|
|
||||||
if isinstance(algo, str):
|
|
||||||
name = algo
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
name = algo.name
|
|
||||||
except AttributeError:
|
|
||||||
raise ValueError("unsupported hash type %r" % (algo,))
|
|
||||||
|
|
||||||
# Got the name. Let's see if we have a PyCrypto implementation.
|
|
||||||
try:
|
|
||||||
new_func = _new_funcs[name]
|
|
||||||
except KeyError:
|
|
||||||
# No PyCrypto implementation. Try hashlib.
|
|
||||||
try:
|
|
||||||
import hashlib
|
|
||||||
except ImportError:
|
|
||||||
# There is no hashlib.
|
|
||||||
raise ValueError("unsupported hash type %s" % (name,))
|
|
||||||
return hashlib.new(name, *args)
|
|
||||||
else:
|
|
||||||
# We have a PyCrypto implementation. Instantiate it.
|
|
||||||
return new_func(*args)
|
|
||||||
|
|
||||||
# This dict originally gets the following _*_new methods, but its members get
|
|
||||||
# replaced with the real new() methods of the various hash modules as they are
|
|
||||||
# used. We do it without locks to improve performance, which is safe in
|
|
||||||
# CPython because dict access is atomic in CPython. This might break PyPI.
|
|
||||||
_new_funcs = {}
|
|
||||||
|
|
||||||
def _md2_new(*args):
|
|
||||||
from Crypto.Hash import MD2
|
|
||||||
_new_funcs['MD2'] = _new_funcs['md2'] = MD2.new
|
|
||||||
return MD2.new(*args)
|
|
||||||
_new_funcs['MD2'] = _new_funcs['md2'] = _md2_new
|
|
||||||
del _md2_new
|
|
||||||
|
|
||||||
def _md4_new(*args):
|
|
||||||
from Crypto.Hash import MD4
|
|
||||||
_new_funcs['MD4'] = _new_funcs['md4'] = MD4.new
|
|
||||||
return MD4.new(*args)
|
|
||||||
_new_funcs['MD4'] = _new_funcs['md4'] = _md4_new
|
|
||||||
del _md4_new
|
|
||||||
|
|
||||||
def _md5_new(*args):
|
|
||||||
from Crypto.Hash import MD5
|
|
||||||
_new_funcs['MD5'] = _new_funcs['md5'] = MD5.new
|
|
||||||
return MD5.new(*args)
|
|
||||||
_new_funcs['MD5'] = _new_funcs['md5'] = _md5_new
|
|
||||||
del _md5_new
|
|
||||||
|
|
||||||
def _ripemd160_new(*args):
|
|
||||||
from Crypto.Hash import RIPEMD160
|
|
||||||
_new_funcs['RIPEMD160'] = _new_funcs['ripemd160'] = \
|
|
||||||
_new_funcs['RIPEMD'] = _new_funcs['ripemd'] = RIPEMD160.new
|
|
||||||
return RIPEMD160.new(*args)
|
|
||||||
_new_funcs['RIPEMD160'] = _new_funcs['ripemd160'] = \
|
|
||||||
_new_funcs['RIPEMD'] = _new_funcs['ripemd'] = _ripemd160_new
|
|
||||||
del _ripemd160_new
|
|
||||||
|
|
||||||
def _sha1_new(*args):
|
|
||||||
from Crypto.Hash import SHA1
|
|
||||||
_new_funcs['SHA1'] = _new_funcs['sha1'] = \
|
|
||||||
_new_funcs['SHA'] = _new_funcs['sha'] = SHA1.new
|
|
||||||
return SHA1.new(*args)
|
|
||||||
_new_funcs['SHA1'] = _new_funcs['sha1'] = \
|
|
||||||
_new_funcs['SHA'] = _new_funcs['sha'] = _sha1_new
|
|
||||||
del _sha1_new
|
|
||||||
|
|
||||||
def _sha224_new(*args):
|
|
||||||
from Crypto.Hash import SHA224
|
|
||||||
_new_funcs['SHA224'] = _new_funcs['sha224'] = SHA224.new
|
|
||||||
return SHA224.new(*args)
|
|
||||||
_new_funcs['SHA224'] = _new_funcs['sha224'] = _sha224_new
|
|
||||||
del _sha224_new
|
|
||||||
|
|
||||||
def _sha256_new(*args):
|
|
||||||
from Crypto.Hash import SHA256
|
|
||||||
_new_funcs['SHA256'] = _new_funcs['sha256'] = SHA256.new
|
|
||||||
return SHA256.new(*args)
|
|
||||||
_new_funcs['SHA256'] = _new_funcs['sha256'] = _sha256_new
|
|
||||||
del _sha256_new
|
|
||||||
|
|
||||||
def _sha384_new(*args):
|
|
||||||
from Crypto.Hash import SHA384
|
|
||||||
_new_funcs['SHA384'] = _new_funcs['sha384'] = SHA384.new
|
|
||||||
return SHA384.new(*args)
|
|
||||||
_new_funcs['SHA384'] = _new_funcs['sha384'] = _sha384_new
|
|
||||||
del _sha384_new
|
|
||||||
|
|
||||||
def _sha512_new(*args):
|
|
||||||
from Crypto.Hash import SHA512
|
|
||||||
_new_funcs['SHA512'] = _new_funcs['sha512'] = SHA512.new
|
|
||||||
return SHA512.new(*args)
|
|
||||||
_new_funcs['SHA512'] = _new_funcs['sha512'] = _sha512_new
|
|
||||||
del _sha512_new
|
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
class HashAlgo:
|
||||||
|
"""A generic class for an abstract cryptographic hash algorithm.
|
||||||
|
|
||||||
|
:undocumented: block_size
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: The size of the resulting hash in bytes.
|
||||||
|
digest_size = None
|
||||||
|
#: The internal block size of the hash algorithm in bytes.
|
||||||
|
block_size = None
|
||||||
|
|
||||||
|
def __init__(self, hashFactory, data=None):
|
||||||
|
"""Initialize the hash object.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
hashFactory : callable
|
||||||
|
An object that will generate the actual hash implementation.
|
||||||
|
*hashFactory* must have a *new()* method, or must be directly
|
||||||
|
callable.
|
||||||
|
data : byte string
|
||||||
|
The very first chunk of the message to hash.
|
||||||
|
It is equivalent to an early call to `update()`.
|
||||||
|
"""
|
||||||
|
if hasattr(hashFactory, 'new'):
|
||||||
|
self._hash = hashFactory.new()
|
||||||
|
else:
|
||||||
|
self._hash = hashFactory()
|
||||||
|
if data:
|
||||||
|
self.update(data)
|
||||||
|
|
||||||
|
def update(self, data):
|
||||||
|
"""Continue hashing of a message by consuming the next chunk of data.
|
||||||
|
|
||||||
|
Repeated calls are equivalent to a single call with the concatenation
|
||||||
|
of all the arguments. In other words:
|
||||||
|
|
||||||
|
>>> m.update(a); m.update(b)
|
||||||
|
|
||||||
|
is equivalent to:
|
||||||
|
|
||||||
|
>>> m.update(a+b)
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The next chunk of the message being hashed.
|
||||||
|
"""
|
||||||
|
return self._hash.update(data)
|
||||||
|
|
||||||
|
def digest(self):
|
||||||
|
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
|
||||||
|
|
||||||
|
This method does not change the state of the hash object.
|
||||||
|
You can continue updating the object after calling this function.
|
||||||
|
|
||||||
|
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
|
||||||
|
characters, including null bytes.
|
||||||
|
"""
|
||||||
|
return self._hash.digest()
|
||||||
|
|
||||||
|
def hexdigest(self):
|
||||||
|
"""Return the **printable** digest of the message that has been hashed so far.
|
||||||
|
|
||||||
|
This method does not change the state of the hash object.
|
||||||
|
|
||||||
|
:Return: A string of 2* `digest_size` characters. It contains only
|
||||||
|
hexadecimal ASCII digits.
|
||||||
|
"""
|
||||||
|
return self._hash.hexdigest()
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""Return a copy ("clone") of the hash object.
|
||||||
|
|
||||||
|
The copy will have the same internal state as the original hash
|
||||||
|
object.
|
||||||
|
This can be used to efficiently compute the digests of strings that
|
||||||
|
share a common initial substring.
|
||||||
|
|
||||||
|
:Return: A hash object of the same type
|
||||||
|
"""
|
||||||
|
return self._hash.copy()
|
||||||
|
|
||||||
|
def new(self, data=None):
|
||||||
|
"""Return a fresh instance of the hash object.
|
||||||
|
|
||||||
|
Unlike the `copy` method, the internal state of the object is empty.
|
||||||
|
|
||||||
|
:Parameters:
|
||||||
|
data : byte string
|
||||||
|
The next chunk of the message being hashed.
|
||||||
|
|
||||||
|
:Return: A hash object of the same type
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
@@ -38,14 +38,9 @@ __revision__ = "$Id$"
|
|||||||
import math
|
import math
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Hash import SHA as SHA1, HMAC
|
||||||
from Crypto.Hash import SHA1, HMAC, CMAC
|
|
||||||
from Crypto.Util.strxor import strxor
|
from Crypto.Util.strxor import strxor
|
||||||
from Crypto.Util.number import long_to_bytes, bytes_to_long
|
|
||||||
|
|
||||||
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
|
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
|
||||||
"""Derive one key from a password (or passphrase).
|
"""Derive one key from a password (or passphrase).
|
||||||
@@ -81,7 +76,7 @@ def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
|
|||||||
pHash = hashAlgo.new(password+salt)
|
pHash = hashAlgo.new(password+salt)
|
||||||
digest = pHash.digest_size
|
digest = pHash.digest_size
|
||||||
if dkLen>digest:
|
if dkLen>digest:
|
||||||
raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest)
|
raise ValueError("Selected hash algorithm has a too short digest (%d bytes)." % digest)
|
||||||
if len(salt)!=8:
|
if len(salt)!=8:
|
||||||
raise ValueError("Salt is not 8 bytes long.")
|
raise ValueError("Salt is not 8 bytes long.")
|
||||||
for i in xrange(count-1):
|
for i in xrange(count-1):
|
||||||
@@ -126,84 +121,3 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None):
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
return key[:dkLen]
|
return key[:dkLen]
|
||||||
|
|
||||||
class _S2V(object):
|
|
||||||
"""String-to-vector PRF as defined in `RFC5297`_.
|
|
||||||
|
|
||||||
This class implements a pseudorandom function family
|
|
||||||
based on CMAC that takes as input a vector of strings.
|
|
||||||
|
|
||||||
.. _RFC5297: http://tools.ietf.org/html/rfc5297
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, key, ciphermod):
|
|
||||||
"""Initialize the S2V PRF.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
key : byte string
|
|
||||||
A secret that can be used as key for CMACs
|
|
||||||
based on ciphers from ``ciphermod``.
|
|
||||||
ciphermod : module
|
|
||||||
A block cipher module from `Crypto.Cipher`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self._key = key
|
|
||||||
self._ciphermod = ciphermod
|
|
||||||
self._last_string = self._cache = bchr(0)*ciphermod.block_size
|
|
||||||
self._n_updates = ciphermod.block_size*8-1
|
|
||||||
|
|
||||||
def new(key, ciphermod):
|
|
||||||
"""Create a new S2V PRF.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
key : byte string
|
|
||||||
A secret that can be used as key for CMACs
|
|
||||||
based on ciphers from ``ciphermod``.
|
|
||||||
ciphermod : module
|
|
||||||
A block cipher module from `Crypto.Cipher`.
|
|
||||||
"""
|
|
||||||
return _S2V(key, ciphermod)
|
|
||||||
new = staticmethod(new)
|
|
||||||
|
|
||||||
def _double(self, bs):
|
|
||||||
doubled = bytes_to_long(bs)<<1
|
|
||||||
if bord(bs[0]) & 0x80:
|
|
||||||
doubled ^= 0x87
|
|
||||||
return long_to_bytes(doubled, len(bs))[-len(bs):]
|
|
||||||
|
|
||||||
def update(self, item):
|
|
||||||
"""Pass the next component of the vector.
|
|
||||||
|
|
||||||
The maximum number of components you can pass is equal to the block
|
|
||||||
length of the cipher (in bits) minus 1.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
item : byte string
|
|
||||||
The next component of the vector.
|
|
||||||
:Raise TypeError: when the limit on the number of components has been reached.
|
|
||||||
:Raise ValueError: when the component is empty
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not item:
|
|
||||||
raise ValueError("A component cannot be empty")
|
|
||||||
|
|
||||||
if self._n_updates==0:
|
|
||||||
raise TypeError("Too many components passed to S2V")
|
|
||||||
self._n_updates -= 1
|
|
||||||
|
|
||||||
mac = CMAC.new(self._key, msg=self._last_string, ciphermod=self._ciphermod)
|
|
||||||
self._cache = strxor(self._double(self._cache), mac.digest())
|
|
||||||
self._last_string = item
|
|
||||||
|
|
||||||
def derive(self):
|
|
||||||
""""Derive a secret from the vector of components.
|
|
||||||
|
|
||||||
:Return: a byte string, as long as the block length of the cipher.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if len(self._last_string)>=16:
|
|
||||||
final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache)
|
|
||||||
else:
|
|
||||||
padded = (self._last_string + bchr(0x80)+ bchr(0)*15)[:16]
|
|
||||||
final = strxor(padded, self._double(self._cache))
|
|
||||||
mac = CMAC.new(self._key, msg=final, ciphermod=self._ciphermod)
|
|
||||||
return mac.digest()
|
|
||||||
|
|||||||
@@ -59,20 +59,14 @@ verification.
|
|||||||
|
|
||||||
>>> from Crypto.Random import random
|
>>> from Crypto.Random import random
|
||||||
>>> from Crypto.PublicKey import DSA
|
>>> from Crypto.PublicKey import DSA
|
||||||
>>> from Crypto.Hash import SHA256
|
>>> from Crypto.Hash import SHA
|
||||||
>>>
|
>>>
|
||||||
>>> message = "Hello"
|
>>> message = "Hello"
|
||||||
>>> key = DSA.generate(2048)
|
>>> key = DSA.generate(1024)
|
||||||
>>> f = open("public_key.pem", "w")
|
>>> h = SHA.new(message).digest()
|
||||||
>>> f.write(key.publickey().exportKey(key))
|
|
||||||
>>> h = SHA256.new(message).digest()
|
|
||||||
>>> k = random.StrongRandom().randint(1,key.q-1)
|
>>> k = random.StrongRandom().randint(1,key.q-1)
|
||||||
>>> sig = key.sign(h,k)
|
>>> sig = key.sign(h,k)
|
||||||
>>> ...
|
>>> ...
|
||||||
>>> ...
|
|
||||||
>>> f = open("public_key.pem", "r")
|
|
||||||
>>> h = SHA256.new(message).digest()
|
|
||||||
>>> key = DSA.importKey(f.read())
|
|
||||||
>>> if key.verify(h,sig):
|
>>> if key.verify(h,sig):
|
||||||
>>> print "OK"
|
>>> print "OK"
|
||||||
>>> else:
|
>>> else:
|
||||||
@@ -85,64 +79,20 @@ verification.
|
|||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
__all__ = ['generate', 'construct', 'error', 'DSAImplementation',
|
__all__ = ['generate', 'construct', 'error', 'DSAImplementation', '_DSAobj']
|
||||||
'_DSAobj', 'importKey']
|
|
||||||
|
|
||||||
import binascii
|
|
||||||
import struct
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
from Crypto.Util.py3compat import *
|
|
||||||
|
|
||||||
|
from Crypto.PublicKey import _DSA, _slowmath, pubkey
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
from Crypto.IO import PKCS8, PEM
|
|
||||||
from Crypto.Util.number import bytes_to_long, long_to_bytes
|
|
||||||
from Crypto.PublicKey import _DSA, _slowmath, pubkey, KeyFormatError
|
|
||||||
from Crypto.Util.asn1 import DerObject, DerSequence,\
|
|
||||||
DerInteger, DerObjectId, DerBitString, newDerSequence, newDerBitString
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Crypto.PublicKey import _fastmath
|
from Crypto.PublicKey import _fastmath
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_fastmath = None
|
_fastmath = None
|
||||||
|
|
||||||
def decode_der(obj_class, binstr):
|
|
||||||
"""Instantiate a DER object class, decode a DER binary string in it,
|
|
||||||
and return the object."""
|
|
||||||
der = obj_class()
|
|
||||||
der.decode(binstr)
|
|
||||||
return der
|
|
||||||
|
|
||||||
# ; The following ASN.1 types are relevant for DSA
|
|
||||||
#
|
|
||||||
# SubjectPublicKeyInfo ::= SEQUENCE {
|
|
||||||
# algorithm AlgorithmIdentifier,
|
|
||||||
# subjectPublicKey BIT STRING
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 }
|
|
||||||
#
|
|
||||||
# ; See RFC3279
|
|
||||||
# Dss-Parms ::= SEQUENCE {
|
|
||||||
# p INTEGER,
|
|
||||||
# q INTEGER,
|
|
||||||
# g INTEGER
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# DSAPublicKey ::= INTEGER
|
|
||||||
#
|
|
||||||
# DSSPrivatKey_OpenSSL ::= SEQUENCE
|
|
||||||
# version INTEGER,
|
|
||||||
# p INTEGER,
|
|
||||||
# q INTEGER,
|
|
||||||
# g INTEGER,
|
|
||||||
# y INTEGER,
|
|
||||||
# x INTEGER
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
|
|
||||||
class _DSAobj(pubkey.pubkey):
|
class _DSAobj(pubkey.pubkey):
|
||||||
"""Class defining an actual DSA key.
|
"""Class defining an actual DSA key.
|
||||||
|
|
||||||
@@ -162,12 +112,9 @@ class _DSAobj(pubkey.pubkey):
|
|||||||
#: - **x**, the private key.
|
#: - **x**, the private key.
|
||||||
keydata = ['y', 'g', 'p', 'q', 'x']
|
keydata = ['y', 'g', 'p', 'q', 'x']
|
||||||
|
|
||||||
def __init__(self, implementation, key, randfunc=None):
|
def __init__(self, implementation, key):
|
||||||
self.implementation = implementation
|
self.implementation = implementation
|
||||||
self.key = key
|
self.key = key
|
||||||
if randfunc is None:
|
|
||||||
randfunc = Random.new().read
|
|
||||||
self._randfunc = randfunc
|
|
||||||
|
|
||||||
def __getattr__(self, attrname):
|
def __getattr__(self, attrname):
|
||||||
if attrname in self.keydata:
|
if attrname in self.keydata:
|
||||||
@@ -270,8 +217,6 @@ class _DSAobj(pubkey.pubkey):
|
|||||||
def __setstate__(self, d):
|
def __setstate__(self, d):
|
||||||
if not hasattr(self, 'implementation'):
|
if not hasattr(self, 'implementation'):
|
||||||
self.implementation = DSAImplementation()
|
self.implementation = DSAImplementation()
|
||||||
if not hasattr(self, '_randfunc'):
|
|
||||||
self._randfunc = Random.new().read
|
|
||||||
t = []
|
t = []
|
||||||
for k in self.keydata:
|
for k in self.keydata:
|
||||||
if not d.has_key(k):
|
if not d.has_key(k):
|
||||||
@@ -291,124 +236,6 @@ class _DSAobj(pubkey.pubkey):
|
|||||||
# PY3K: This is meant to be text, do not change to bytes (data)
|
# PY3K: This is meant to be text, do not change to bytes (data)
|
||||||
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
|
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
|
||||||
|
|
||||||
def exportKey(self, format='PEM', pkcs8=None, passphrase=None,
|
|
||||||
protection=None):
|
|
||||||
"""Export this DSA key.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
format : string
|
|
||||||
The format to use for wrapping the key:
|
|
||||||
|
|
||||||
- *'DER'*. Binary encoding.
|
|
||||||
- *'PEM'*. Textual encoding, done according to `RFC1421`_/
|
|
||||||
`RFC1423`_ (default).
|
|
||||||
- *'OpenSSH'*. Textual encoding, one line of text, see `RFC4253`_.
|
|
||||||
Only suitable for public keys, not private keys.
|
|
||||||
|
|
||||||
passphrase : string
|
|
||||||
For private keys only. The pass phrase to use for deriving
|
|
||||||
the encryption key.
|
|
||||||
|
|
||||||
pkcs8 : boolean
|
|
||||||
For private keys only. If ``True`` (default), the key is arranged
|
|
||||||
according to `PKCS#8`_ and if `False`, according to the custom
|
|
||||||
OpenSSL/OpenSSH encoding.
|
|
||||||
|
|
||||||
protection : string
|
|
||||||
The encryption scheme to use for protecting the private key.
|
|
||||||
It is only meaningful when a pass phrase is present too.
|
|
||||||
|
|
||||||
If ``pkcs8`` takes value ``True``, ``protection`` is the PKCS#8
|
|
||||||
algorithm to use for deriving the secret and encrypting
|
|
||||||
the private DSA key.
|
|
||||||
For a complete list of algorithms, see `Crypto.IO.PKCS8`.
|
|
||||||
The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*.
|
|
||||||
|
|
||||||
If ``pkcs8`` is ``False``, the obsolete PEM encryption scheme is
|
|
||||||
used. It is based on MD5 for key derivation, and Triple DES for
|
|
||||||
encryption. Parameter ``protection`` is ignored.
|
|
||||||
|
|
||||||
The combination ``format='DER'`` and ``pkcs8=False`` is not allowed
|
|
||||||
if a passphrase is present.
|
|
||||||
|
|
||||||
:Return: A byte string with the encoded public or private half
|
|
||||||
of the key.
|
|
||||||
:Raise ValueError:
|
|
||||||
When the format is unknown or when you try to encrypt a private
|
|
||||||
key with *DER* format and OpenSSL/OpenSSH.
|
|
||||||
:attention:
|
|
||||||
If you don't provide a pass phrase, the private key will be
|
|
||||||
exported in the clear!
|
|
||||||
|
|
||||||
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
|
||||||
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
|
||||||
.. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt
|
|
||||||
.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
|
|
||||||
"""
|
|
||||||
if passphrase is not None:
|
|
||||||
passphrase = tobytes(passphrase)
|
|
||||||
if format == 'OpenSSH':
|
|
||||||
tup1 = [long_to_bytes(x) for x in (self.p, self.q, self.g, self.y)]
|
|
||||||
|
|
||||||
def func(x):
|
|
||||||
if (bord(x[0]) & 0x80):
|
|
||||||
return bchr(0) + x
|
|
||||||
else:
|
|
||||||
return x
|
|
||||||
|
|
||||||
tup2 = map(func, tup1)
|
|
||||||
keyparts = [b('ssh-dss')] + tup2
|
|
||||||
keystring = b('').join(
|
|
||||||
[struct.pack(">I", len(kp)) + kp for kp in keyparts]
|
|
||||||
)
|
|
||||||
return b('ssh-dss ') + binascii.b2a_base64(keystring)[:-1]
|
|
||||||
|
|
||||||
# DER format is always used, even in case of PEM, which simply
|
|
||||||
# encodes it into BASE64.
|
|
||||||
params = newDerSequence(self.p, self.q, self.g)
|
|
||||||
if self.has_private():
|
|
||||||
if pkcs8 is None:
|
|
||||||
pkcs8 = True
|
|
||||||
if pkcs8:
|
|
||||||
if not protection:
|
|
||||||
protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
|
|
||||||
private_key = DerInteger(self.x).encode()
|
|
||||||
binary_key = PKCS8.wrap(
|
|
||||||
private_key, oid, passphrase,
|
|
||||||
protection, key_params=params,
|
|
||||||
randfunc=self._randfunc
|
|
||||||
)
|
|
||||||
if passphrase:
|
|
||||||
key_type = 'ENCRYPTED PRIVATE'
|
|
||||||
else:
|
|
||||||
key_type = 'PRIVATE'
|
|
||||||
passphrase = None
|
|
||||||
else:
|
|
||||||
if format != 'PEM' and passphrase:
|
|
||||||
raise ValueError("DSA private key cannot be encrypted")
|
|
||||||
ints = [0, self.p, self.q, self.g, self.y, self.x]
|
|
||||||
binary_key = newDerSequence(*ints).encode()
|
|
||||||
key_type = "DSA PRIVATE"
|
|
||||||
else:
|
|
||||||
if pkcs8:
|
|
||||||
raise ValueError("PKCS#8 is only meaningful for private keys")
|
|
||||||
binary_key = newDerSequence(
|
|
||||||
newDerSequence(DerObjectId(oid), params),
|
|
||||||
newDerBitString(DerInteger(self.y))
|
|
||||||
).encode()
|
|
||||||
key_type = "DSA PUBLIC"
|
|
||||||
|
|
||||||
if format == 'DER':
|
|
||||||
return binary_key
|
|
||||||
if format == 'PEM':
|
|
||||||
pem_str = PEM.encode(
|
|
||||||
binary_key, key_type + " KEY",
|
|
||||||
passphrase, self._randfunc
|
|
||||||
)
|
|
||||||
return tobytes(pem_str)
|
|
||||||
raise ValueError("Unknown key format '%s'. Cannot export the DSA key." % format)
|
|
||||||
|
|
||||||
|
|
||||||
class DSAImplementation(object):
|
class DSAImplementation(object):
|
||||||
"""
|
"""
|
||||||
A DSA key factory.
|
A DSA key factory.
|
||||||
@@ -543,139 +370,9 @@ class DSAImplementation(object):
|
|||||||
key = self._math.dsa_construct(*tup)
|
key = self._math.dsa_construct(*tup)
|
||||||
return _DSAobj(self, key)
|
return _DSAobj(self, key)
|
||||||
|
|
||||||
def _importKeyDER(self, key_data, passphrase=None, params=None):
|
|
||||||
"""Import a DSA key (public or private half), encoded in DER form."""
|
|
||||||
|
|
||||||
try:
|
|
||||||
#
|
|
||||||
# Dss-Parms ::= SEQUENCE {
|
|
||||||
# p OCTET STRING,
|
|
||||||
# q OCTET STRING,
|
|
||||||
# g OCTET STRING
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
|
|
||||||
# Try a simple private key first
|
|
||||||
if params:
|
|
||||||
x = decode_der(DerInteger, key_data).value
|
|
||||||
params = decode_der(DerSequence, params) # Dss-Parms
|
|
||||||
p, q, g = list(params)
|
|
||||||
y = pow(g, x, p)
|
|
||||||
tup = (y, g, p, q, x)
|
|
||||||
return self.construct(tup)
|
|
||||||
|
|
||||||
der = decode_der(DerSequence, key_data)
|
|
||||||
|
|
||||||
# Try OpenSSL format for private keys
|
|
||||||
if len(der) == 6 and der.hasOnlyInts() and der[0] == 0:
|
|
||||||
tup = [der[comp] for comp in (4, 3, 1, 2, 5)]
|
|
||||||
return self.construct(tup)
|
|
||||||
|
|
||||||
# Try SubjectPublicKeyInfo
|
|
||||||
if len(der) == 2:
|
|
||||||
try:
|
|
||||||
algo = decode_der(DerSequence, der[0])
|
|
||||||
algo_oid = decode_der(DerObjectId, algo[0]).value
|
|
||||||
params = decode_der(DerSequence, algo[1]) # Dss-Parms
|
|
||||||
|
|
||||||
if algo_oid == oid and len(params) == 3 and\
|
|
||||||
params.hasOnlyInts():
|
|
||||||
bitmap = decode_der(DerBitString, der[1])
|
|
||||||
pub_key = decode_der(DerInteger, bitmap.value)
|
|
||||||
tup = [pub_key.value]
|
|
||||||
tup += [params[comp] for comp in (2, 0, 1)]
|
|
||||||
return self.construct(tup)
|
|
||||||
except (ValueError, EOFError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Try unencrypted PKCS#8
|
|
||||||
p8_pair = PKCS8.unwrap(key_data, passphrase)
|
|
||||||
if p8_pair[0] == oid:
|
|
||||||
return self._importKeyDER(p8_pair[1], passphrase, p8_pair[2])
|
|
||||||
|
|
||||||
except (ValueError, EOFError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise KeyFormatError("DSA key format is not supported")
|
|
||||||
|
|
||||||
def importKey(self, extern_key, passphrase=None):
|
|
||||||
"""Import a DSA key (public or private).
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
extern_key : (byte) string
|
|
||||||
The DSA key to import.
|
|
||||||
|
|
||||||
An DSA *public* key can be in any of the following formats:
|
|
||||||
|
|
||||||
- X.509 ``subjectPublicKeyInfo`` (binary or PEM)
|
|
||||||
- OpenSSH (one line of text, see `RFC4253`_)
|
|
||||||
|
|
||||||
A DSA *private* key can be in any of the following formats:
|
|
||||||
|
|
||||||
- `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo``
|
|
||||||
DER SEQUENCE (binary or PEM encoding)
|
|
||||||
- OpenSSL/OpenSSH (binary or PEM)
|
|
||||||
|
|
||||||
For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
|
|
||||||
|
|
||||||
The private key may be encrypted by means of a certain pass phrase
|
|
||||||
either at the PEM level or at the PKCS#8 level.
|
|
||||||
|
|
||||||
passphrase : string
|
|
||||||
In case of an encrypted private key, this is the pass phrase
|
|
||||||
from which the decryption key is derived.
|
|
||||||
|
|
||||||
:Return: A DSA key object (`_DSAobj`).
|
|
||||||
:Raise KeyFormatError:
|
|
||||||
When the given key cannot be parsed (possibly because
|
|
||||||
the pass phrase is wrong).
|
|
||||||
|
|
||||||
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
|
||||||
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
|
||||||
.. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt
|
|
||||||
.. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt
|
|
||||||
"""
|
|
||||||
|
|
||||||
extern_key = tobytes(extern_key)
|
|
||||||
if passphrase is not None:
|
|
||||||
passphrase = tobytes(passphrase)
|
|
||||||
|
|
||||||
if extern_key.startswith(b('-----')):
|
|
||||||
# This is probably a PEM encoded key
|
|
||||||
(der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase)
|
|
||||||
if enc_flag:
|
|
||||||
passphrase = None
|
|
||||||
return self._importKeyDER(der, passphrase)
|
|
||||||
|
|
||||||
if extern_key.startswith(b('ssh-dss ')):
|
|
||||||
# This is probably a public OpenSSH key
|
|
||||||
keystring = binascii.a2b_base64(extern_key.split(b(' '))[1])
|
|
||||||
keyparts = []
|
|
||||||
while len(keystring) > 4:
|
|
||||||
length = struct.unpack(">I", keystring[:4])[0]
|
|
||||||
keyparts.append(keystring[4:4 + length])
|
|
||||||
keystring = keystring[4 + length:]
|
|
||||||
if keyparts[0] == b("ssh-dss"):
|
|
||||||
tup = [bytes_to_long(keyparts[x]) for x in (4, 3, 1, 2)]
|
|
||||||
return self.construct(tup)
|
|
||||||
|
|
||||||
if bord(extern_key[0]) == 0x30:
|
|
||||||
# This is probably a DER encoded key
|
|
||||||
return self._importKeyDER(extern_key, passphrase)
|
|
||||||
|
|
||||||
raise KeyFormatError("DSA key format is not supported")
|
|
||||||
|
|
||||||
#: `Object ID`_ for a DSA key.
|
|
||||||
#:
|
|
||||||
#: id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 }
|
|
||||||
#:
|
|
||||||
#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.10040.4.1.html
|
|
||||||
oid = "1.2.840.10040.4.1"
|
|
||||||
|
|
||||||
_impl = DSAImplementation()
|
_impl = DSAImplementation()
|
||||||
generate = _impl.generate
|
generate = _impl.generate
|
||||||
construct = _impl.construct
|
construct = _impl.construct
|
||||||
importKey = _impl.importKey
|
|
||||||
error = _impl.error
|
error = _impl.error
|
||||||
|
|
||||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
|
|||||||
@@ -111,7 +111,6 @@ __all__ = ['generate', 'construct', 'error', 'ElGamalobj']
|
|||||||
|
|
||||||
from Crypto.PublicKey.pubkey import *
|
from Crypto.PublicKey.pubkey import *
|
||||||
from Crypto.Util import number
|
from Crypto.Util import number
|
||||||
from Crypto import Random
|
|
||||||
|
|
||||||
class error (Exception):
|
class error (Exception):
|
||||||
pass
|
pass
|
||||||
@@ -243,11 +242,6 @@ class ElGamalobj(pubkey):
|
|||||||
#: - **x**, the private key.
|
#: - **x**, the private key.
|
||||||
keydata=['p', 'g', 'y', 'x']
|
keydata=['p', 'g', 'y', 'x']
|
||||||
|
|
||||||
def __init__(self, randfunc=None):
|
|
||||||
if randfunc is None:
|
|
||||||
randfunc = Random.new().read
|
|
||||||
self._randfunc = randfunc
|
|
||||||
|
|
||||||
def encrypt(self, plaintext, K):
|
def encrypt(self, plaintext, K):
|
||||||
"""Encrypt a piece of data with ElGamal.
|
"""Encrypt a piece of data with ElGamal.
|
||||||
|
|
||||||
@@ -337,11 +331,8 @@ class ElGamalobj(pubkey):
|
|||||||
def _decrypt(self, M):
|
def _decrypt(self, M):
|
||||||
if (not hasattr(self, 'x')):
|
if (not hasattr(self, 'x')):
|
||||||
raise TypeError('Private key not available in this object')
|
raise TypeError('Private key not available in this object')
|
||||||
r = number.getRandomRange(2, self.p-1, self._randfunc)
|
ax=pow(M[0], self.x, self.p)
|
||||||
a_blind = (M[0] * pow(self.g, r, self.p)) % self.p
|
plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
|
||||||
ax=pow(a_blind, self.x, self.p)
|
|
||||||
plaintext_blind = (M[1] * inverse(ax, self.p ) ) % self.p
|
|
||||||
plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p
|
|
||||||
return plaintext
|
return plaintext
|
||||||
|
|
||||||
def _sign(self, M, K):
|
def _sign(self, M, K):
|
||||||
|
|||||||
+163
-176
@@ -46,7 +46,7 @@ them from known components, exporting them, and importing them.
|
|||||||
>>>
|
>>>
|
||||||
>>> key = RSA.generate(2048)
|
>>> key = RSA.generate(2048)
|
||||||
>>> f = open('mykey.pem','w')
|
>>> f = open('mykey.pem','w')
|
||||||
>>> f.write(key.exportKey('PEM'))
|
>>> f.write(RSA.exportKey('PEM'))
|
||||||
>>> f.close()
|
>>> f.close()
|
||||||
...
|
...
|
||||||
>>> f = open('mykey.pem','r')
|
>>> f = open('mykey.pem','r')
|
||||||
@@ -65,39 +65,31 @@ it is recommended to use one of the standardized schemes instead (like
|
|||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
__all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation',
|
__all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation', '_RSAobj']
|
||||||
'_RSAobj', 'oid' , 'algorithmIdentifier' ]
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
#from Crypto.Util.python_compat import *
|
||||||
from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes
|
from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes
|
||||||
|
|
||||||
from Crypto.PublicKey import _RSA, _slowmath, pubkey
|
from Crypto.PublicKey import _RSA, _slowmath, pubkey
|
||||||
from Crypto.IO import PKCS8, PEM
|
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
|
|
||||||
from Crypto.Util.asn1 import *
|
from Crypto.Util.asn1 import DerObject, DerSequence, DerNull
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from Crypto.Util.number import inverse
|
from Crypto.Util.number import inverse
|
||||||
|
|
||||||
|
from Crypto.Util.number import inverse
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from Crypto.PublicKey import _fastmath
|
from Crypto.PublicKey import _fastmath
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_fastmath = None
|
_fastmath = None
|
||||||
|
|
||||||
def decode_der(obj_class, binstr):
|
|
||||||
"""Instantiate a DER object class, decode a DER binary string in it, and
|
|
||||||
return the object."""
|
|
||||||
der = obj_class()
|
|
||||||
der.decode(binstr)
|
|
||||||
return der
|
|
||||||
|
|
||||||
class _RSAobj(pubkey.pubkey):
|
class _RSAobj(pubkey.pubkey):
|
||||||
"""Class defining an actual RSA key.
|
"""Class defining an actual RSA key.
|
||||||
|
|
||||||
@@ -294,8 +286,6 @@ class _RSAobj(pubkey.pubkey):
|
|||||||
def __setstate__(self, d):
|
def __setstate__(self, d):
|
||||||
if not hasattr(self, 'implementation'):
|
if not hasattr(self, 'implementation'):
|
||||||
self.implementation = RSAImplementation()
|
self.implementation = RSAImplementation()
|
||||||
if not hasattr(self, '_randfunc'):
|
|
||||||
self._randfunc = Random.new().read
|
|
||||||
t = []
|
t = []
|
||||||
for k in self.keydata:
|
for k in self.keydata:
|
||||||
if not d.has_key(k):
|
if not d.has_key(k):
|
||||||
@@ -315,66 +305,36 @@ class _RSAobj(pubkey.pubkey):
|
|||||||
# PY3K: This is meant to be text, do not change to bytes (data)
|
# PY3K: This is meant to be text, do not change to bytes (data)
|
||||||
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
|
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
|
||||||
|
|
||||||
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None):
|
def exportKey(self, format='PEM', passphrase=None, pkcs=1):
|
||||||
"""Export this RSA key.
|
"""Export this RSA key.
|
||||||
|
|
||||||
:Parameters:
|
:Parameter format: The format to use for wrapping the key.
|
||||||
format : string
|
|
||||||
The format to use for wrapping the key:
|
|
||||||
|
|
||||||
- *'DER'*. Binary encoding.
|
- *'DER'*. Binary encoding, always unencrypted.
|
||||||
- *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_.
|
- *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_.
|
||||||
|
Unencrypted (default) or encrypted.
|
||||||
- *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
|
- *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
|
||||||
Only suitable for public keys (not private keys).
|
Only suitable for public keys (not private keys).
|
||||||
|
:Type format: string
|
||||||
|
|
||||||
passphrase : string
|
:Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from.
|
||||||
For private keys only. The pass phrase used for deriving the encryption
|
:Type passphrase: string
|
||||||
key.
|
|
||||||
|
|
||||||
pkcs : integer
|
:Parameter pkcs: The PKCS standard to follow for assembling the key.
|
||||||
For *DER* and *PEM* format only.
|
|
||||||
The PKCS standard to follow for assembling the components of the key.
|
|
||||||
You have two choices:
|
You have two choices:
|
||||||
|
|
||||||
- **1** (default): the public key is embedded into
|
- with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE.
|
||||||
an X.509 ``SubjectPublicKeyInfo`` DER SEQUENCE.
|
The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE.
|
||||||
The private key is embedded into a `PKCS#1`_
|
This mode is the default.
|
||||||
``RSAPrivateKey`` DER SEQUENCE.
|
- with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE.
|
||||||
- **8**: the private key is embedded into a `PKCS#8`_
|
This mode is not available for public keys.
|
||||||
``PrivateKeyInfo`` DER SEQUENCE. This value cannot be used
|
|
||||||
for public keys.
|
|
||||||
|
|
||||||
protection : string
|
PKCS standards are not relevant for the *OpenSSH* format.
|
||||||
The encryption scheme to use for protecting the private key.
|
:Type pkcs: integer
|
||||||
|
|
||||||
If ``None`` (default), the behavior depends on ``format``:
|
:Return: A byte string with the encoded public or private half.
|
||||||
|
|
||||||
- For *DER*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*
|
|
||||||
scheme is used. The following operations are performed:
|
|
||||||
|
|
||||||
1. A 16 byte Triple DES key is derived from the passphrase
|
|
||||||
using `Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt,
|
|
||||||
and 1 000 iterations of `Crypto.Hash.HMAC`.
|
|
||||||
2. The private key is encrypted using CBC.
|
|
||||||
3. The encrypted key is encoded according to PKCS#8.
|
|
||||||
|
|
||||||
- For *PEM*, the obsolete PEM encryption scheme is used.
|
|
||||||
It is based on MD5 for key derivation, and Triple DES for encryption.
|
|
||||||
|
|
||||||
Specifying a value for ``protection`` is only meaningful for PKCS#8
|
|
||||||
(that is, ``pkcs=8``) and only if a pass phrase is present too.
|
|
||||||
|
|
||||||
The supported schemes for PKCS#8 are listed in the
|
|
||||||
`Crypto.IO.PKCS8` module (see ``wrap_algo`` parameter).
|
|
||||||
|
|
||||||
:Return: A byte string with the encoded public or private half
|
|
||||||
of the key.
|
|
||||||
:Raise ValueError:
|
:Raise ValueError:
|
||||||
When the format is unknown or when you try to encrypt a private
|
When the format is unknown.
|
||||||
key with *DER* format and PKCS#1.
|
|
||||||
:attention:
|
|
||||||
If you don't provide a pass phrase, the private key will be
|
|
||||||
exported in the clear!
|
|
||||||
|
|
||||||
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
||||||
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
||||||
@@ -388,52 +348,59 @@ class _RSAobj(pubkey.pubkey):
|
|||||||
nb = long_to_bytes(self.n)
|
nb = long_to_bytes(self.n)
|
||||||
if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb
|
if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb
|
||||||
if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb
|
if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb
|
||||||
keyparts = [ b('ssh-rsa'), eb, nb ]
|
keyparts = [ 'ssh-rsa', eb, nb ]
|
||||||
keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts])
|
keystring = ''.join([ struct.pack(">I",len(kp))+kp for kp in keyparts])
|
||||||
return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1]
|
return 'ssh-rsa '+binascii.b2a_base64(keystring)[:-1]
|
||||||
|
|
||||||
# DER format is always used, even in case of PEM, which simply
|
# DER format is always used, even in case of PEM, which simply
|
||||||
# encodes it into BASE64.
|
# encodes it into BASE64.
|
||||||
|
der = DerSequence()
|
||||||
if self.has_private():
|
if self.has_private():
|
||||||
binary_key = newDerSequence(
|
keyType= { 1: 'RSA PRIVATE', 8: 'PRIVATE' }[pkcs]
|
||||||
0,
|
der[:] = [ 0, self.n, self.e, self.d, self.p, self.q,
|
||||||
self.n,
|
self.d % (self.p-1), self.d % (self.q-1),
|
||||||
self.e,
|
inverse(self.q, self.p) ]
|
||||||
self.d,
|
if pkcs==8:
|
||||||
self.p,
|
derkey = der.encode()
|
||||||
self.q,
|
der = DerSequence([0])
|
||||||
self.d % (self.p-1),
|
der.append(algorithmIdentifier)
|
||||||
self.d % (self.q-1),
|
der.append(DerObject('OCTET STRING', derkey).encode())
|
||||||
inverse(self.q, self.p)
|
|
||||||
).encode()
|
|
||||||
if pkcs==1:
|
|
||||||
keyType = 'RSA PRIVATE'
|
|
||||||
if format=='DER' and passphrase:
|
|
||||||
raise ValueError("PKCS#1 private key cannot be encrypted")
|
|
||||||
else: # PKCS#8
|
|
||||||
if format=='PEM' and protection is None:
|
|
||||||
keyType = 'PRIVATE'
|
|
||||||
binary_key = PKCS8.wrap(binary_key, oid, None)
|
|
||||||
else:
|
else:
|
||||||
keyType = 'ENCRYPTED PRIVATE'
|
keyType = "PUBLIC"
|
||||||
if not protection:
|
der.append(algorithmIdentifier)
|
||||||
protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
|
bitmap = DerObject('BIT STRING')
|
||||||
binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection)
|
derPK = DerSequence( [ self.n, self.e ] )
|
||||||
passphrase = None
|
bitmap.payload = bchr(0x00) + derPK.encode()
|
||||||
else:
|
der.append(bitmap.encode())
|
||||||
keyType = "RSA PUBLIC"
|
|
||||||
binary_key = newDerSequence(
|
|
||||||
algorithmIdentifier,
|
|
||||||
newDerBitString(
|
|
||||||
newDerSequence( self.n, self.e )
|
|
||||||
)
|
|
||||||
).encode()
|
|
||||||
if format=='DER':
|
if format=='DER':
|
||||||
return binary_key
|
return der.encode()
|
||||||
if format=='PEM':
|
if format=='PEM':
|
||||||
pem_str = PEM.encode(binary_key, keyType+" KEY", passphrase, self._randfunc)
|
pem = b("-----BEGIN " + keyType + " KEY-----\n")
|
||||||
return tobytes(pem_str)
|
objenc = None
|
||||||
raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
|
if passphrase and keyType.endswith('PRIVATE'):
|
||||||
|
# We only support 3DES for encryption
|
||||||
|
import Crypto.Hash.MD5
|
||||||
|
from Crypto.Cipher import DES3
|
||||||
|
from Crypto.Protocol.KDF import PBKDF1
|
||||||
|
salt = self._randfunc(8)
|
||||||
|
key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5)
|
||||||
|
key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5)
|
||||||
|
objenc = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt)
|
||||||
|
pem += b('Proc-Type: 4,ENCRYPTED\n')
|
||||||
|
pem += b('DEK-Info: DES-EDE3-CBC,') + binascii.b2a_hex(salt).upper() + b('\n\n')
|
||||||
|
|
||||||
|
binaryKey = der.encode()
|
||||||
|
if objenc:
|
||||||
|
# Add PKCS#7-like padding
|
||||||
|
padding = objenc.block_size-len(binaryKey)%objenc.block_size
|
||||||
|
binaryKey = objenc.encrypt(binaryKey+bchr(padding)*padding)
|
||||||
|
|
||||||
|
# Each BASE64 line can take up to 64 characters (=48 bytes of data)
|
||||||
|
chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ]
|
||||||
|
pem += b('').join(chunks)
|
||||||
|
pem += b("-----END " + keyType + " KEY-----")
|
||||||
|
return pem
|
||||||
|
return ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
|
||||||
|
|
||||||
class RSAImplementation(object):
|
class RSAImplementation(object):
|
||||||
"""
|
"""
|
||||||
@@ -572,139 +539,159 @@ class RSAImplementation(object):
|
|||||||
key = self._math.rsa_construct(*tup)
|
key = self._math.rsa_construct(*tup)
|
||||||
return _RSAobj(self, key)
|
return _RSAobj(self, key)
|
||||||
|
|
||||||
def _importKeyDER(self, extern_key, passphrase=None):
|
def _importKeyDER(self, externKey):
|
||||||
"""Import an RSA key (public or private half), encoded in DER form."""
|
"""Import an RSA key (public or private half), encoded in DER form."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
der = decode_der(DerSequence, extern_key)
|
der = DerSequence()
|
||||||
|
der.decode(externKey, True)
|
||||||
|
|
||||||
# Try PKCS#1 first, for a private key
|
# Try PKCS#1 first, for a private key
|
||||||
if len(der) == 9 and der.hasOnlyInts() and der[0] == 0:
|
if len(der)==9 and der.hasOnlyInts() and der[0]==0:
|
||||||
# ASN.1 RSAPrivateKey element
|
# ASN.1 RSAPrivateKey element
|
||||||
del der[6:] # Remove d mod (p-1),
|
del der[6:] # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p
|
||||||
# d mod (q-1), and
|
der.append(inverse(der[4],der[5])) # Add p^{-1} mod q
|
||||||
# q^{-1} mod p
|
|
||||||
der.append(inverse(der[4], der[5])) # Add p^{-1} mod q
|
|
||||||
del der[0] # Remove version
|
del der[0] # Remove version
|
||||||
return self.construct(der[:])
|
return self.construct(der[:])
|
||||||
|
|
||||||
# Keep on trying PKCS#1, but now for a public key
|
# Keep on trying PKCS#1, but now for a public key
|
||||||
if len(der) == 2:
|
if len(der)==2:
|
||||||
try:
|
# The DER object is an RSAPublicKey SEQUENCE with two elements
|
||||||
# The DER object is an RSAPublicKey SEQUENCE with
|
|
||||||
# two elements
|
|
||||||
if der.hasOnlyInts():
|
if der.hasOnlyInts():
|
||||||
return self.construct(der[:])
|
return self.construct(der[:])
|
||||||
# The DER object is a SubjectPublicKeyInfo SEQUENCE
|
# The DER object is a SubjectPublicKeyInfo SEQUENCE with two elements:
|
||||||
# with two elements: an 'algorithmIdentifier' and a
|
# an 'algorithm' (or 'algorithmIdentifier') SEQUENCE and a 'subjectPublicKey' BIT STRING.
|
||||||
# 'subjectPublicKey'BIT STRING.
|
# 'algorithm' takes the value given a few lines above.
|
||||||
# 'algorithmIdentifier' takes the value given at the
|
# 'subjectPublicKey' encapsulates the actual ASN.1 RSAPublicKey element.
|
||||||
# module level.
|
if der[0]==algorithmIdentifier:
|
||||||
# 'subjectPublicKey' encapsulates the actual ASN.1
|
bitmap = DerObject()
|
||||||
# RSAPublicKey element.
|
bitmap.decode(der[1], True)
|
||||||
if der[0] == algorithmIdentifier:
|
if bitmap.isType('BIT STRING') and bord(bitmap.payload[0])==0x00:
|
||||||
bitmap = decode_der(DerBitString, der[1])
|
der.decode(bitmap.payload[1:], True)
|
||||||
rsaPub = decode_der(DerSequence, bitmap.value)
|
if len(der)==2 and der.hasOnlyInts():
|
||||||
if len(rsaPub) == 2 and rsaPub.hasOnlyInts():
|
return self.construct(der[:])
|
||||||
return self.construct(rsaPub[:])
|
|
||||||
except (ValueError, EOFError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Try PKCS#8 (possibly encrypted)
|
# Try unencrypted PKCS#8
|
||||||
k = PKCS8.unwrap(extern_key, passphrase)
|
if der[0]==0:
|
||||||
if k[0] == oid:
|
# The second element in the SEQUENCE is algorithmIdentifier.
|
||||||
return self._importKeyDER(k[1], passphrase)
|
# It must say RSA (see above for description).
|
||||||
|
if der[1]==algorithmIdentifier:
|
||||||
|
privateKey = DerObject()
|
||||||
|
privateKey.decode(der[2], True)
|
||||||
|
if privateKey.isType('OCTET STRING'):
|
||||||
|
return self._importKeyDER(privateKey.payload)
|
||||||
|
|
||||||
except (ValueError, EOFError):
|
except ValueError, IndexError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
raise ValueError("RSA key format is not supported")
|
raise ValueError("RSA key format is not supported")
|
||||||
|
|
||||||
def importKey(self, extern_key, passphrase=None):
|
def importKey(self, externKey, passphrase=None):
|
||||||
"""Import an RSA key (public or private half), encoded in standard
|
"""Import an RSA key (public or private half), encoded in standard form.
|
||||||
form.
|
|
||||||
|
|
||||||
:Parameter extern_key:
|
:Parameter externKey:
|
||||||
The RSA key to import, encoded as a string.
|
The RSA key to import, encoded as a string.
|
||||||
|
|
||||||
An RSA public key can be in any of the following formats:
|
An RSA public key can be in any of the following formats:
|
||||||
|
|
||||||
- X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM
|
- X.509 `subjectPublicKeyInfo` DER SEQUENCE (binary or PEM encoding)
|
||||||
encoding)
|
- `PKCS#1`_ `RSAPublicKey` DER SEQUENCE (binary or PEM encoding)
|
||||||
- `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding)
|
|
||||||
- OpenSSH (textual public key only)
|
- OpenSSH (textual public key only)
|
||||||
|
|
||||||
An RSA private key can be in any of the following formats:
|
An RSA private key can be in any of the following formats:
|
||||||
|
|
||||||
- PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding)
|
- PKCS#1 `RSAPrivateKey` DER SEQUENCE (binary or PEM encoding)
|
||||||
- `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo``
|
- `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE (binary or PEM encoding)
|
||||||
DER SEQUENCE (binary or PEM encoding)
|
|
||||||
- OpenSSH (textual public key only)
|
- OpenSSH (textual public key only)
|
||||||
|
|
||||||
For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
|
For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
|
||||||
|
|
||||||
The private key may be encrypted by means of a certain pass phrase
|
In case of PEM encoding, the private key can be encrypted with DES or 3TDES according to a certain ``pass phrase``.
|
||||||
either at the PEM level or at the PKCS#8 level.
|
Only OpenSSL-compatible pass phrases are supported.
|
||||||
:Type extern_key: string
|
:Type externKey: string
|
||||||
|
|
||||||
:Parameter passphrase:
|
:Parameter passphrase:
|
||||||
In case of an encrypted private key, this is the pass phrase from
|
In case of an encrypted PEM key, this is the pass phrase from which the encryption key is derived.
|
||||||
which the decryption key is derived.
|
|
||||||
:Type passphrase: string
|
:Type passphrase: string
|
||||||
|
|
||||||
:Return: An RSA key object (`_RSAobj`).
|
:Return: An RSA key object (`_RSAobj`).
|
||||||
|
|
||||||
:Raise ValueError/IndexError/TypeError:
|
:Raise ValueError/IndexError/TypeError:
|
||||||
When the given key cannot be parsed (possibly because the pass
|
When the given key cannot be parsed (possibly because the pass phrase is wrong).
|
||||||
phrase is wrong).
|
|
||||||
|
|
||||||
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
|
||||||
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
|
||||||
.. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
|
.. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
|
||||||
.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
|
.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
|
||||||
"""
|
"""
|
||||||
extern_key = tobytes(extern_key)
|
externKey = tobytes(externKey)
|
||||||
if passphrase is not None:
|
if passphrase is not None:
|
||||||
passphrase = tobytes(passphrase)
|
passphrase = tobytes(passphrase)
|
||||||
|
|
||||||
if extern_key.startswith(b('-----')):
|
if externKey.startswith(b('-----')):
|
||||||
# This is probably a PEM encoded key.
|
# This is probably a PEM encoded key
|
||||||
(der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase)
|
lines = externKey.replace(b(" "),b('')).split()
|
||||||
if enc_flag:
|
keyobj = None
|
||||||
passphrase = None
|
|
||||||
return self._importKeyDER(der, passphrase)
|
|
||||||
|
|
||||||
if extern_key.startswith(b('ssh-rsa ')):
|
# The encrypted PEM format
|
||||||
|
if lines[1].startswith(b('Proc-Type:4,ENCRYPTED')):
|
||||||
|
DEK = lines[2].split(b(':'))
|
||||||
|
if len(DEK)!=2 or DEK[0]!=b('DEK-Info') or not passphrase:
|
||||||
|
raise ValueError("PEM encryption format not supported.")
|
||||||
|
algo, salt = DEK[1].split(b(','))
|
||||||
|
salt = binascii.a2b_hex(salt)
|
||||||
|
import Crypto.Hash.MD5
|
||||||
|
from Crypto.Cipher import DES, DES3
|
||||||
|
from Crypto.Protocol.KDF import PBKDF1
|
||||||
|
if algo==b("DES-CBC"):
|
||||||
|
# This is EVP_BytesToKey in OpenSSL
|
||||||
|
key = PBKDF1(passphrase, salt, 8, 1, Crypto.Hash.MD5)
|
||||||
|
keyobj = DES.new(key, Crypto.Cipher.DES.MODE_CBC, salt)
|
||||||
|
elif algo==b("DES-EDE3-CBC"):
|
||||||
|
# Note that EVP_BytesToKey is note exactly the same as PBKDF1
|
||||||
|
key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5)
|
||||||
|
key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5)
|
||||||
|
keyobj = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupport PEM encryption algorithm.")
|
||||||
|
lines = lines[2:]
|
||||||
|
|
||||||
|
der = binascii.a2b_base64(b('').join(lines[1:-1]))
|
||||||
|
if keyobj:
|
||||||
|
der = keyobj.decrypt(der)
|
||||||
|
padding = bord(der[-1])
|
||||||
|
der = der[:-padding]
|
||||||
|
return self._importKeyDER(der)
|
||||||
|
|
||||||
|
if externKey.startswith(b('ssh-rsa ')):
|
||||||
# This is probably an OpenSSH key
|
# This is probably an OpenSSH key
|
||||||
keystring = binascii.a2b_base64(extern_key.split(b(' '))[1])
|
keystring = binascii.a2b_base64(externKey.split(b(' '))[1])
|
||||||
keyparts = []
|
keyparts = []
|
||||||
while len(keystring) > 4:
|
while len(keystring)>4:
|
||||||
l = struct.unpack(">I", keystring[:4])[0]
|
l = struct.unpack(">I",keystring[:4])[0]
|
||||||
keyparts.append(keystring[4:4 + l])
|
keyparts.append(keystring[4:4+l])
|
||||||
keystring = keystring[4 + l:]
|
keystring = keystring[4+l:]
|
||||||
e = bytes_to_long(keyparts[1])
|
e = bytes_to_long(keyparts[1])
|
||||||
n = bytes_to_long(keyparts[2])
|
n = bytes_to_long(keyparts[2])
|
||||||
return self.construct([n, e])
|
return self.construct([n, e])
|
||||||
|
if bord(externKey[0])==0x30:
|
||||||
if bord(extern_key[0]) == 0x30:
|
|
||||||
# This is probably a DER encoded key
|
# This is probably a DER encoded key
|
||||||
return self._importKeyDER(extern_key, passphrase)
|
return self._importKeyDER(externKey)
|
||||||
|
|
||||||
raise ValueError("RSA key format is not supported")
|
raise ValueError("RSA key format is not supported")
|
||||||
|
|
||||||
#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates
|
#: This is the ASN.1 DER object that qualifies an algorithm as
|
||||||
#: a generic RSA key, even when such key will be actually used for digital
|
#: compliant to PKCS#1 (that is, the standard RSA).
|
||||||
#: signatures.
|
# It is found in all 'algorithm' fields (also called 'algorithmIdentifier').
|
||||||
#:
|
# It is a SEQUENCE with the oid assigned to RSA and with its parameters (none).
|
||||||
#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html
|
# 0x06 0x09 OBJECT IDENTIFIER, 9 bytes of payload
|
||||||
oid = "1.2.840.113549.1.1.1"
|
# 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01
|
||||||
|
# rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1)
|
||||||
#: This is the standard DER object that qualifies a cryptographic algorithm
|
# 0x05 0x00 NULL
|
||||||
#: in ASN.1-based data structures (e.g. X.509 certificates).
|
|
||||||
algorithmIdentifier = DerSequence(
|
algorithmIdentifier = DerSequence(
|
||||||
[DerObjectId(oid).encode(), # algorithm field
|
[ b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'),
|
||||||
DerNull().encode()] # parameters field
|
DerNull().encode() ]
|
||||||
).encode()
|
).encode()
|
||||||
|
|
||||||
_impl = RSAImplementation()
|
_impl = RSAImplementation()
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ __revision__ = "$Id$"
|
|||||||
from Crypto.PublicKey.pubkey import *
|
from Crypto.PublicKey.pubkey import *
|
||||||
from Crypto.Util import number
|
from Crypto.Util import number
|
||||||
from Crypto.Util.number import bytes_to_long, long_to_bytes
|
from Crypto.Util.number import bytes_to_long, long_to_bytes
|
||||||
from Crypto.Hash import SHA1
|
from Crypto.Hash import SHA
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
class error (Exception):
|
class error (Exception):
|
||||||
@@ -38,8 +38,8 @@ class error (Exception):
|
|||||||
|
|
||||||
def generateQ(randfunc):
|
def generateQ(randfunc):
|
||||||
S=randfunc(20)
|
S=randfunc(20)
|
||||||
hash1=SHA1.new(S).digest()
|
hash1=SHA.new(S).digest()
|
||||||
hash2=SHA1.new(long_to_bytes(bytes_to_long(S)+1)).digest()
|
hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
|
||||||
q = bignum(0)
|
q = bignum(0)
|
||||||
for i in range(0,20):
|
for i in range(0,20):
|
||||||
c=bord(hash1[i])^bord(hash2[i])
|
c=bord(hash1[i])^bord(hash2[i])
|
||||||
@@ -77,7 +77,7 @@ def generate_py(bits, randfunc, progress_func=None):
|
|||||||
powL1=pow(bignum(2), bits-1)
|
powL1=pow(bignum(2), bits-1)
|
||||||
while C<4096:
|
while C<4096:
|
||||||
for k in range(0, n+1):
|
for k in range(0, n+1):
|
||||||
V[k]=bytes_to_long(SHA1.new(S+bstr(N)+bstr(k)).digest())
|
V[k]=bytes_to_long(SHA.new(S+bstr(N)+bstr(k)).digest())
|
||||||
W=V[n] % powb
|
W=V[n] % powb
|
||||||
for k in range(n-1, -1, -1):
|
for k in range(n-1, -1, -1):
|
||||||
W=(W<<160L)+V[k]
|
W=(W<<160L)+V[k]
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ Crypto.PublicKey.RSA (Signing, encryption, and blinding)
|
|||||||
:undocumented: _DSA, _RSA, _fastmath, _slowmath, pubkey
|
:undocumented: _DSA, _RSA, _fastmath, _slowmath, pubkey
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class KeyFormatError(ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
__all__ = ['RSA', 'DSA', 'ElGamal']
|
__all__ = ['RSA', 'DSA', 'ElGamal']
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ import warnings
|
|||||||
from Crypto.pct_warnings import ClockRewindWarning
|
from Crypto.pct_warnings import ClockRewindWarning
|
||||||
import SHAd256
|
import SHAd256
|
||||||
|
|
||||||
# If the system has monotonic time, we'll use it.
|
|
||||||
from Crypto.Util._time import maybe_monotonic_time
|
|
||||||
|
|
||||||
import FortunaGenerator
|
import FortunaGenerator
|
||||||
|
|
||||||
class FortunaPool(object):
|
class FortunaPool(object):
|
||||||
@@ -97,25 +94,8 @@ def which_pools(r):
|
|||||||
|
|
||||||
class FortunaAccumulator(object):
|
class FortunaAccumulator(object):
|
||||||
|
|
||||||
# An estimate of how many bytes we must append to pool 0 before it will
|
min_pool_size = 64 # TODO: explain why
|
||||||
# contain 128 bits of entropy (with respect to an attack). We reseed the
|
reseed_interval = 0.100 # 100 ms TODO: explain why
|
||||||
# generator only after pool 0 contains `min_pool_size` bytes. Note that
|
|
||||||
# unlike with some other PRNGs, Fortuna's security does not rely on the
|
|
||||||
# accuracy of this estimate---we can accord to be optimistic here.
|
|
||||||
min_pool_size = 64 # size in bytes
|
|
||||||
|
|
||||||
# If an attacker can predict some (but not all) of our entropy sources, the
|
|
||||||
# `min_pool_size` check may not be sufficient to prevent a successful state
|
|
||||||
# compromise extension attack. To resist this attack, Fortuna spreads the
|
|
||||||
# input across 32 pools, which are then consumed (to reseed the output
|
|
||||||
# generator) with exponentially decreasing frequency.
|
|
||||||
#
|
|
||||||
# In order to prevent an attacker from gaining knowledge of all 32 pools
|
|
||||||
# before we have a chance to fill them with enough information that the
|
|
||||||
# attacker cannot predict, we impose a rate limit of 10 reseeds/second (one
|
|
||||||
# per 100 ms). This ensures that a hypothetical 33rd pool would only be
|
|
||||||
# needed after a minimum of 13 years of sustained attack.
|
|
||||||
reseed_interval = 0.100 # time in seconds
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reseed_count = 0
|
self.reseed_count = 0
|
||||||
@@ -129,17 +109,8 @@ class FortunaAccumulator(object):
|
|||||||
self.pools = [FortunaPool() for i in range(32)] # 32 pools
|
self.pools = [FortunaPool() for i in range(32)] # 32 pools
|
||||||
assert(self.pools[0] is not self.pools[1])
|
assert(self.pools[0] is not self.pools[1])
|
||||||
|
|
||||||
def _forget_last_reseed(self):
|
|
||||||
# This is not part of the standard Fortuna definition, and using this
|
|
||||||
# function frequently can weaken Fortuna's ability to resist a state
|
|
||||||
# compromise extension attack, but we need this in order to properly
|
|
||||||
# implement Crypto.Random.atfork(). Otherwise, forked child processes
|
|
||||||
# might continue to use their parent's PRNG state for up to 100ms in
|
|
||||||
# some cases. (e.g. CVE-2013-1445)
|
|
||||||
self.last_reseed = None
|
|
||||||
|
|
||||||
def random_data(self, bytes):
|
def random_data(self, bytes):
|
||||||
current_time = maybe_monotonic_time()
|
current_time = time.time()
|
||||||
if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
|
if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
|
||||||
warnings.warn("Clock rewind detected. Resetting last_reseed.", ClockRewindWarning)
|
warnings.warn("Clock rewind detected. Resetting last_reseed.", ClockRewindWarning)
|
||||||
self.last_reseed = None
|
self.last_reseed = None
|
||||||
@@ -152,7 +123,7 @@ class FortunaAccumulator(object):
|
|||||||
|
|
||||||
def _reseed(self, current_time=None):
|
def _reseed(self, current_time=None):
|
||||||
if current_time is None:
|
if current_time is None:
|
||||||
current_time = maybe_monotonic_time()
|
current_time = time.time()
|
||||||
seed = []
|
seed = []
|
||||||
self.reseed_count += 1
|
self.reseed_count += 1
|
||||||
self.last_reseed = current_time
|
self.last_reseed = current_time
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
if sys.version_info[0] is 2 and sys.version_info[1] is 1:
|
||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
__all__ = ['WindowsRNG']
|
__all__ = ['WindowsRNG']
|
||||||
|
|
||||||
from Crypto.Random.OSRNG import winrandom
|
import winrandom
|
||||||
from rng_base import BaseRNG
|
from rng_base import BaseRNG
|
||||||
|
|
||||||
class WindowsRNG(BaseRNG):
|
class WindowsRNG(BaseRNG):
|
||||||
|
|||||||
@@ -90,24 +90,9 @@ class _UserFriendlyRNG(object):
|
|||||||
"""Initialize the random number generator and seed it with entropy from
|
"""Initialize the random number generator and seed it with entropy from
|
||||||
the operating system.
|
the operating system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Save the pid (helps ensure that Crypto.Random.atfork() gets called)
|
|
||||||
self._pid = os.getpid()
|
self._pid = os.getpid()
|
||||||
|
|
||||||
# Collect entropy from the operating system and feed it to
|
|
||||||
# FortunaAccumulator
|
|
||||||
self._ec.reinit()
|
self._ec.reinit()
|
||||||
|
|
||||||
# Override FortunaAccumulator's 100ms minimum re-seed interval. This
|
|
||||||
# is necessary to avoid a race condition between this function and
|
|
||||||
# self.read(), which that can otherwise cause forked child processes to
|
|
||||||
# produce identical output. (e.g. CVE-2013-1445)
|
|
||||||
#
|
|
||||||
# Note that if this function can be called frequently by an attacker,
|
|
||||||
# (and if the bits from OSRNG are insufficiently random) it will weaken
|
|
||||||
# Fortuna's ability to resist a state compromise extension attack.
|
|
||||||
self._fa._forget_last_reseed()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.closed = True
|
self.closed = True
|
||||||
self._osrng = None
|
self._osrng = None
|
||||||
|
|||||||
@@ -103,13 +103,13 @@ class StrongRandom(object):
|
|||||||
|
|
||||||
def shuffle(self, x):
|
def shuffle(self, x):
|
||||||
"""Shuffle the sequence in place."""
|
"""Shuffle the sequence in place."""
|
||||||
# Fisher-Yates shuffle. O(n)
|
# Make a (copy) of the list of objects we want to shuffle
|
||||||
# See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
|
items = list(x)
|
||||||
# Working backwards from the end of the array, we choose a random item
|
|
||||||
# from the remaining items until all items have been chosen.
|
# Choose a random item (without replacement) until all the items have been
|
||||||
for i in xrange(len(x)-1, 0, -1): # iterate from len(x)-1 downto 1
|
# chosen.
|
||||||
j = self.randrange(0, i+1) # choose random j such that 0 <= j <= i
|
for i in xrange(len(x)):
|
||||||
x[i], x[j] = x[j], x[i] # exchange x[i] and x[j]
|
x[i] = items.pop(self.randrange(len(items)))
|
||||||
|
|
||||||
def sample(self, population, k):
|
def sample(self, population, k):
|
||||||
"""Return a k-length list of unique elements chosen from the population sequence."""
|
"""Return a k-length list of unique elements chosen from the population sequence."""
|
||||||
|
|||||||
@@ -24,19 +24,12 @@
|
|||||||
|
|
||||||
"""Self-testing for PyCrypto hash modules"""
|
"""Self-testing for PyCrypto hash modules"""
|
||||||
|
|
||||||
from __future__ import nested_scopes
|
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from binascii import a2b_hex, b2a_hex, hexlify
|
from binascii import a2b_hex, b2a_hex
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
from Crypto.Util.strxor import strxor_c
|
|
||||||
|
|
||||||
# For compatibility with Python 2.1 and Python 2.2
|
# For compatibility with Python 2.1 and Python 2.2
|
||||||
if sys.hexversion < 0x02030000:
|
if sys.hexversion < 0x02030000:
|
||||||
@@ -73,22 +66,14 @@ class CipherSelfTest(unittest.TestCase):
|
|||||||
self.plaintext = b(_extract(params, 'plaintext'))
|
self.plaintext = b(_extract(params, 'plaintext'))
|
||||||
self.ciphertext = b(_extract(params, 'ciphertext'))
|
self.ciphertext = b(_extract(params, 'ciphertext'))
|
||||||
self.module_name = _extract(params, 'module_name', None)
|
self.module_name = _extract(params, 'module_name', None)
|
||||||
self.assoc_data = _extract(params, 'assoc_data', None)
|
|
||||||
self.mac = _extract(params, 'mac', None)
|
|
||||||
if self.assoc_data:
|
|
||||||
self.mac = b(self.mac)
|
|
||||||
|
|
||||||
mode = _extract(params, 'mode', None)
|
mode = _extract(params, 'mode', None)
|
||||||
self.mode_name = str(mode)
|
self.mode_name = str(mode)
|
||||||
if mode is not None:
|
if mode is not None:
|
||||||
# Block cipher
|
# Block cipher
|
||||||
self.mode = getattr(self.module, "MODE_" + mode)
|
self.mode = getattr(self.module, "MODE_" + mode)
|
||||||
|
|
||||||
self.iv = _extract(params, 'iv', None)
|
self.iv = _extract(params, 'iv', None)
|
||||||
if self.iv is None:
|
if self.iv is not None: self.iv = b(self.iv)
|
||||||
self.iv = _extract(params, 'nonce', None)
|
|
||||||
if self.iv is not None:
|
|
||||||
self.iv = b(self.iv)
|
|
||||||
|
|
||||||
# Only relevant for OPENPGP mode
|
# Only relevant for OPENPGP mode
|
||||||
self.encrypted_iv = _extract(params, 'encrypted_iv', None)
|
self.encrypted_iv = _extract(params, 'encrypted_iv', None)
|
||||||
@@ -132,60 +117,29 @@ class CipherSelfTest(unittest.TestCase):
|
|||||||
else:
|
else:
|
||||||
return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.iv), **params)
|
return self.module.new(a2b_hex(self.key), self.mode, a2b_hex(self.iv), **params)
|
||||||
|
|
||||||
def isMode(self, name):
|
|
||||||
if not hasattr(self.module, "MODE_"+name):
|
|
||||||
return False
|
|
||||||
return self.mode == getattr(self.module, "MODE_"+name)
|
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
plaintext = a2b_hex(self.plaintext)
|
plaintext = a2b_hex(self.plaintext)
|
||||||
ciphertext = a2b_hex(self.ciphertext)
|
ciphertext = a2b_hex(self.ciphertext)
|
||||||
assoc_data = []
|
|
||||||
if self.assoc_data:
|
|
||||||
assoc_data = [ a2b_hex(b(x)) for x in self.assoc_data]
|
|
||||||
|
|
||||||
ct = None
|
ct1 = b2a_hex(self._new().encrypt(plaintext))
|
||||||
pt = None
|
pt1 = b2a_hex(self._new(1).decrypt(ciphertext))
|
||||||
|
ct2 = b2a_hex(self._new().encrypt(plaintext))
|
||||||
|
pt2 = b2a_hex(self._new(1).decrypt(ciphertext))
|
||||||
|
|
||||||
#
|
if hasattr(self.module, "MODE_OPENPGP") and self.mode == self.module.MODE_OPENPGP:
|
||||||
# Repeat the same encryption or decryption twice and verify
|
|
||||||
# that the result is always the same
|
|
||||||
#
|
|
||||||
for i in xrange(2):
|
|
||||||
cipher = self._new()
|
|
||||||
decipher = self._new(1)
|
|
||||||
|
|
||||||
# Only AEAD modes
|
|
||||||
for comp in assoc_data:
|
|
||||||
cipher.update(comp)
|
|
||||||
decipher.update(comp)
|
|
||||||
|
|
||||||
ctX = b2a_hex(cipher.encrypt(plaintext))
|
|
||||||
if self.isMode("SIV"):
|
|
||||||
ptX = b2a_hex(decipher.decrypt_and_verify(ciphertext, a2b_hex(self.mac)))
|
|
||||||
else:
|
|
||||||
ptX = b2a_hex(decipher.decrypt(ciphertext))
|
|
||||||
|
|
||||||
if ct:
|
|
||||||
self.assertEqual(ct, ctX)
|
|
||||||
self.assertEqual(pt, ptX)
|
|
||||||
ct, pt = ctX, ptX
|
|
||||||
|
|
||||||
if self.isMode("OPENPGP"):
|
|
||||||
# In PGP mode, data returned by the first encrypt()
|
# In PGP mode, data returned by the first encrypt()
|
||||||
# is prefixed with the encrypted IV.
|
# is prefixed with the encrypted IV.
|
||||||
# Here we check it and then remove it from the ciphertexts.
|
# Here we check it and then remove it from the ciphertexts.
|
||||||
eilen = len(self.encrypted_iv)
|
eilen = len(self.encrypted_iv)
|
||||||
self.assertEqual(self.encrypted_iv, ct[:eilen])
|
self.assertEqual(self.encrypted_iv, ct1[:eilen])
|
||||||
ct = ct[eilen:]
|
self.assertEqual(self.encrypted_iv, ct2[:eilen])
|
||||||
|
ct1 = ct1[eilen:]
|
||||||
|
ct2 = ct2[eilen:]
|
||||||
|
|
||||||
self.assertEqual(self.ciphertext, ct) # encrypt
|
self.assertEqual(self.ciphertext, ct1) # encrypt
|
||||||
self.assertEqual(self.plaintext, pt) # decrypt
|
self.assertEqual(self.ciphertext, ct2) # encrypt (second time)
|
||||||
|
self.assertEqual(self.plaintext, pt1) # decrypt
|
||||||
if self.mac:
|
self.assertEqual(self.plaintext, pt2) # decrypt (second time)
|
||||||
mac = b2a_hex(cipher.digest())
|
|
||||||
self.assertEqual(self.mac, mac)
|
|
||||||
decipher.verify(a2b_hex(self.mac))
|
|
||||||
|
|
||||||
class CipherStreamingSelfTest(CipherSelfTest):
|
class CipherStreamingSelfTest(CipherSelfTest):
|
||||||
|
|
||||||
@@ -241,43 +195,18 @@ class CTRWraparoundTest(unittest.TestCase):
|
|||||||
self.module_name = params.get('module_name', None)
|
self.module_name = params.get('module_name', None)
|
||||||
|
|
||||||
def shortDescription(self):
|
def shortDescription(self):
|
||||||
return """Regression test: %s with MODE_CTR raising OverflowError on wraparound""" % (self.module_name,)
|
return """Regression test: %s with MODE_CTR should raise OverflowError on wraparound when shortcut used""" % (self.module_name,)
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
from Crypto.Util import Counter
|
from Crypto.Util import Counter
|
||||||
|
|
||||||
def pythonCounter():
|
for disable_shortcut in (0, 1): # (False, True) Test CTR-mode shortcut and PyObject_CallObject code paths
|
||||||
state = [0]
|
|
||||||
def ctr():
|
|
||||||
# First block succeeds; Second and subsequent blocks raise OverflowError
|
|
||||||
if state[0] == 0:
|
|
||||||
state[0] = 1
|
|
||||||
return b("\xff") * self.module.block_size
|
|
||||||
else:
|
|
||||||
raise OverflowError
|
|
||||||
return ctr
|
|
||||||
|
|
||||||
for little_endian in (0, 1): # (False, True) Test both endiannesses
|
for little_endian in (0, 1): # (False, True) Test both endiannesses
|
||||||
block = b("\x00") * self.module.block_size
|
ctr = Counter.new(8*self.module.block_size, initial_value=2L**(8*self.module.block_size)-1, little_endian=little_endian, disable_shortcut=disable_shortcut)
|
||||||
|
|
||||||
# Test PyObject_CallObject code path: if the counter raises OverflowError
|
|
||||||
cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=pythonCounter())
|
|
||||||
cipher.encrypt(block)
|
|
||||||
self.assertRaises(OverflowError, cipher.encrypt, block)
|
|
||||||
self.assertRaises(OverflowError, cipher.encrypt, block)
|
|
||||||
|
|
||||||
# Test PyObject_CallObject code path: counter object should raise OverflowError
|
|
||||||
ctr = Counter.new(8*self.module.block_size, initial_value=2L**(8*self.module.block_size)-1, little_endian=little_endian)
|
|
||||||
ctr()
|
|
||||||
self.assertRaises(OverflowError, ctr)
|
|
||||||
self.assertRaises(OverflowError, ctr)
|
|
||||||
|
|
||||||
# Test the CTR-mode shortcut
|
|
||||||
ctr = Counter.new(8*self.module.block_size, initial_value=2L**(8*self.module.block_size)-1, little_endian=little_endian)
|
|
||||||
cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=ctr)
|
cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=ctr)
|
||||||
|
block = b("\x00") * self.module.block_size
|
||||||
cipher.encrypt(block)
|
cipher.encrypt(block)
|
||||||
self.assertRaises(OverflowError, cipher.encrypt, block)
|
self.assertRaises(OverflowError, cipher.encrypt, block)
|
||||||
self.assertRaises(OverflowError, cipher.encrypt, block)
|
|
||||||
|
|
||||||
class CFBSegmentSizeTest(unittest.TestCase):
|
class CFBSegmentSizeTest(unittest.TestCase):
|
||||||
|
|
||||||
@@ -296,301 +225,6 @@ class CFBSegmentSizeTest(unittest.TestCase):
|
|||||||
self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CFB, segment_size=i)
|
self.assertRaises(ValueError, self.module.new, a2b_hex(self.key), self.module.MODE_CFB, segment_size=i)
|
||||||
self.module.new(a2b_hex(self.key), self.module.MODE_CFB, "\0"*self.module.block_size, segment_size=8) # should succeed
|
self.module.new(a2b_hex(self.key), self.module.MODE_CFB, "\0"*self.module.block_size, segment_size=8) # should succeed
|
||||||
|
|
||||||
class CCMMACLengthTest(unittest.TestCase):
|
|
||||||
"""CCM specific tests about MAC"""
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
unittest.TestCase.__init__(self)
|
|
||||||
self.module = module
|
|
||||||
self.key = b('\xFF')*16
|
|
||||||
self.iv = b('\x00')*10
|
|
||||||
|
|
||||||
def shortDescription(self):
|
|
||||||
return self.description
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
"""Verify that MAC can only be 4,6,8,..,16 bytes long."""
|
|
||||||
for i in range(3,16,2):
|
|
||||||
self.description = "CCM MAC length check (%d bytes)" % i
|
|
||||||
self.assertRaises(ValueError, self.module.new, self.key,
|
|
||||||
self.module.MODE_CCM, self.iv, msg_len=10, mac_len=i)
|
|
||||||
|
|
||||||
"""Verify that default MAC length is 16."""
|
|
||||||
self.description = "CCM default MAC length check"
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv, msg_len=4)
|
|
||||||
cipher.encrypt(b('z')*4)
|
|
||||||
self.assertEqual(len(cipher.digest()), 16)
|
|
||||||
|
|
||||||
class CCMSplitEncryptionTest(unittest.TestCase):
|
|
||||||
"""CCM specific tests to validate how encrypt()
|
|
||||||
decrypt() can be called multiple times on the
|
|
||||||
same object."""
|
|
||||||
|
|
||||||
def __init__(self, module):
|
|
||||||
unittest.TestCase.__init__(self)
|
|
||||||
self.module = module
|
|
||||||
self.key = b('\xFF')*16
|
|
||||||
self.iv = b('\x00')*10
|
|
||||||
self.description = "CCM Split Encryption Test"
|
|
||||||
|
|
||||||
def shortDescription(self):
|
|
||||||
return self.description
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
"""Verify that CCM update()/encrypt() can be called multiple times,
|
|
||||||
provided that lengths are declared beforehand"""
|
|
||||||
|
|
||||||
data = b("AUTH DATA")
|
|
||||||
pt1 = b("PLAINTEXT1") # Short
|
|
||||||
pt2 = b("PLAINTEXT2") # Long
|
|
||||||
pt_ref = pt1+pt2
|
|
||||||
|
|
||||||
# REFERENCE: Run with 1 update() and 1 encrypt()
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv)
|
|
||||||
cipher.update(data)
|
|
||||||
ct_ref = cipher.encrypt(pt_ref)
|
|
||||||
mac_ref = cipher.digest()
|
|
||||||
|
|
||||||
# Verify that calling CCM encrypt()/decrypt() twice is not
|
|
||||||
# possible without the 'msg_len' parameter and regardless
|
|
||||||
# of the 'assoc_len' parameter
|
|
||||||
for ad_len in None, len(data):
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv, assoc_len=ad_len)
|
|
||||||
cipher.update(data)
|
|
||||||
cipher.encrypt(pt1)
|
|
||||||
self.assertRaises(TypeError, cipher.encrypt, pt2)
|
|
||||||
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv, assoc_len=ad_len)
|
|
||||||
cipher.update(data)
|
|
||||||
cipher.decrypt(ct_ref[:len(pt1)])
|
|
||||||
self.assertRaises(TypeError, cipher.decrypt, ct_ref[len(pt1):])
|
|
||||||
|
|
||||||
# Run with 2 encrypt()/decrypt(). Results must be the same
|
|
||||||
# regardless of the 'assoc_len' parameter
|
|
||||||
for ad_len in None, len(data):
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv, assoc_len=ad_len, msg_len=len(pt_ref))
|
|
||||||
cipher.update(data)
|
|
||||||
ct = cipher.encrypt(pt1)
|
|
||||||
ct += cipher.encrypt(pt2)
|
|
||||||
mac = cipher.digest()
|
|
||||||
self.assertEqual(ct_ref, ct)
|
|
||||||
self.assertEqual(mac_ref, mac)
|
|
||||||
|
|
||||||
cipher = self.module.new(self.key, self.module.MODE_CCM,
|
|
||||||
self.iv, msg_len=len(pt1+pt2))
|
|
||||||
cipher.update(data)
|
|
||||||
pt = cipher.decrypt(ct[:len(pt1)])
|
|
||||||
pt += cipher.decrypt(ct[len(pt1):])
|
|
||||||
mac = cipher.verify(mac_ref)
|
|
||||||
self.assertEqual(pt_ref, pt)
|
|
||||||
|
|
||||||
class AEADTests(unittest.TestCase):
|
|
||||||
"""Tests generic to all AEAD modes"""
|
|
||||||
|
|
||||||
def __init__(self, module, mode_name, key_size):
|
|
||||||
unittest.TestCase.__init__(self)
|
|
||||||
self.module = module
|
|
||||||
self.mode_name = mode_name
|
|
||||||
self.mode = getattr(module, mode_name)
|
|
||||||
if not self.isMode("SIV"):
|
|
||||||
self.key = b('\xFF')*key_size
|
|
||||||
else:
|
|
||||||
self.key = b('\xFF')*key_size*2
|
|
||||||
self.iv = b('\x00')*10
|
|
||||||
self.description = "AEAD Test"
|
|
||||||
|
|
||||||
def isMode(self, name):
|
|
||||||
if not hasattr(self.module, "MODE_"+name):
|
|
||||||
return False
|
|
||||||
return self.mode == getattr(self.module, "MODE_"+name)
|
|
||||||
|
|
||||||
def right_mac_test(self):
|
|
||||||
"""Positive tests for MAC"""
|
|
||||||
|
|
||||||
self.description = "Test for right MAC in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
|
|
||||||
ad_ref = b("Reference AD")
|
|
||||||
pt_ref = b("Reference plaintext")
|
|
||||||
|
|
||||||
# Encrypt and create the reference MAC
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.update(ad_ref)
|
|
||||||
ct_ref = cipher.encrypt(pt_ref)
|
|
||||||
mac_ref = cipher.digest()
|
|
||||||
|
|
||||||
# Decrypt and verify that MAC is accepted
|
|
||||||
decipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
decipher.update(ad_ref)
|
|
||||||
pt = decipher.decrypt_and_verify(ct_ref, mac_ref)
|
|
||||||
self.assertEqual(pt, pt_ref)
|
|
||||||
|
|
||||||
# Verify that hexverify work
|
|
||||||
decipher.hexverify(hexlify(mac_ref))
|
|
||||||
|
|
||||||
def wrong_mac_test(self):
|
|
||||||
"""Negative tests for MAC"""
|
|
||||||
|
|
||||||
self.description = "Test for wrong MAC in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
|
|
||||||
ad_ref = b("Reference AD")
|
|
||||||
pt_ref = b("Reference plaintext")
|
|
||||||
|
|
||||||
# Encrypt and create the reference MAC
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.update(ad_ref)
|
|
||||||
ct_ref = cipher.encrypt(pt_ref)
|
|
||||||
mac_ref = cipher.digest()
|
|
||||||
|
|
||||||
# Modify the MAC and verify it is NOT ACCEPTED
|
|
||||||
wrong_mac = strxor_c(mac_ref, 255)
|
|
||||||
decipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
decipher.update(ad_ref)
|
|
||||||
self.assertRaises(ValueError, decipher.decrypt_and_verify,
|
|
||||||
ct_ref, wrong_mac)
|
|
||||||
|
|
||||||
def zero_data(self):
|
|
||||||
"""Verify transition from INITIALIZED to FINISHED"""
|
|
||||||
|
|
||||||
self.description = "Test for zero data in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.digest()
|
|
||||||
|
|
||||||
def multiple_updates(self):
|
|
||||||
"""Verify that update() can be called multiple times"""
|
|
||||||
|
|
||||||
self.description = "Test for multiple updates in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
|
|
||||||
# In all modes other than SIV, the associated data is a single
|
|
||||||
# component that can be arbitrarilly split and submitted to update().
|
|
||||||
#
|
|
||||||
# In SIV, associated data is instead organized in a vector or multiple
|
|
||||||
# components. Each component is passed to update() as a whole.
|
|
||||||
# This test is therefore not meaningful to SIV.
|
|
||||||
if self.isMode("SIV"):
|
|
||||||
return
|
|
||||||
|
|
||||||
ad = b("").join([bchr(x) for x in xrange(0,128)])
|
|
||||||
|
|
||||||
mac1, mac2, mac3 = (None,)*3
|
|
||||||
for chunk_length in 1,10,40,80,128:
|
|
||||||
chunks = [ad[i:i+chunk_length] for i in range(0, len(ad), chunk_length)]
|
|
||||||
|
|
||||||
# No encryption/decryption
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
for c in chunks:
|
|
||||||
cipher.update(c)
|
|
||||||
if mac1:
|
|
||||||
cipher.verify(mac1)
|
|
||||||
else:
|
|
||||||
mac1 = cipher.digest()
|
|
||||||
|
|
||||||
# Encryption
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
for c in chunks:
|
|
||||||
cipher.update(c)
|
|
||||||
ct = cipher.encrypt(b("PT"))
|
|
||||||
mac2 = cipher.digest()
|
|
||||||
|
|
||||||
# Decryption
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
for c in chunks:
|
|
||||||
cipher.update(c)
|
|
||||||
cipher.decrypt(ct)
|
|
||||||
cipher.verify(mac2)
|
|
||||||
|
|
||||||
def no_mix_encrypt_decrypt(self):
|
|
||||||
"""Verify that encrypt and decrypt cannot be mixed up"""
|
|
||||||
|
|
||||||
self.description = "Test for mix of encrypt and decrypt in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
|
|
||||||
# Calling decrypt after encrypt raises an exception
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.encrypt(b("PT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.decrypt, b("XYZ")*40)
|
|
||||||
|
|
||||||
# Calling encrypt() after decrypt() raises an exception
|
|
||||||
# (excluded for SIV, since decrypt() is not valid)
|
|
||||||
if not self.isMode("SIV"):
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.decrypt(b("CT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.encrypt, b("XYZ")*40)
|
|
||||||
|
|
||||||
# Calling verify after encrypt raises an exception
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.encrypt(b("PT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.verify, b("XYZ"))
|
|
||||||
self.assertRaises(TypeError, cipher.hexverify, "12")
|
|
||||||
|
|
||||||
# Calling digest() after decrypt() raises an exception
|
|
||||||
# (excluded for SIV, since decrypt() is not valid)
|
|
||||||
if not self.isMode("SIV"):
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.decrypt(b("CT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.digest)
|
|
||||||
self.assertRaises(TypeError, cipher.hexdigest)
|
|
||||||
|
|
||||||
def no_late_update(self):
|
|
||||||
"""Verify that update cannot be called after encrypt or decrypt"""
|
|
||||||
|
|
||||||
self.description = "Test for late update in %s of %s" % \
|
|
||||||
(self.mode_name, self.module.__name__)
|
|
||||||
|
|
||||||
# Calling update after encrypt raises an exception
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.update(b("XX"))
|
|
||||||
cipher.encrypt(b("PT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.update, b("XYZ"))
|
|
||||||
|
|
||||||
# Calling update() after decrypt() raises an exception
|
|
||||||
# (excluded for SIV, since decrypt() is not valid)
|
|
||||||
if not self.isMode("SIV"):
|
|
||||||
cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
cipher.update(b("XX"))
|
|
||||||
cipher.decrypt(b("CT")*40)
|
|
||||||
self.assertRaises(TypeError, cipher.update, b("XYZ"))
|
|
||||||
|
|
||||||
def loopback(self):
|
|
||||||
"""Verify composition of encrypt_and_digest() and decrypt_and_verify()
|
|
||||||
is the identity function."""
|
|
||||||
|
|
||||||
self.description = "Lookback test decrypt_and_verify(encrypt_and_digest)"\
|
|
||||||
"for %s in %s" % (self.mode_name,
|
|
||||||
self.module.__name__)
|
|
||||||
|
|
||||||
enc_cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
dec_cipher = self.module.new(self.key, self.mode, self.iv)
|
|
||||||
|
|
||||||
enc_cipher.update(b("XXX"))
|
|
||||||
dec_cipher.update(b("XXX"))
|
|
||||||
|
|
||||||
plaintext = b("Reference") * 10
|
|
||||||
ct, mac = enc_cipher.encrypt_and_digest(plaintext)
|
|
||||||
pt = dec_cipher.decrypt_and_verify(ct, mac)
|
|
||||||
|
|
||||||
self.assertEqual(plaintext, pt)
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
self.right_mac_test()
|
|
||||||
self.wrong_mac_test()
|
|
||||||
self.zero_data()
|
|
||||||
self.multiple_updates()
|
|
||||||
self.no_mix_encrypt_decrypt()
|
|
||||||
self.no_late_update()
|
|
||||||
self.loopback()
|
|
||||||
|
|
||||||
def shortDescription(self):
|
|
||||||
return self.description
|
|
||||||
|
|
||||||
class RoundtripTest(unittest.TestCase):
|
class RoundtripTest(unittest.TestCase):
|
||||||
def __init__(self, module, params):
|
def __init__(self, module, params):
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
@@ -649,17 +283,13 @@ class IVLengthTest(unittest.TestCase):
|
|||||||
self.module.MODE_OFB, "")
|
self.module.MODE_OFB, "")
|
||||||
self.assertRaises(ValueError, self.module.new, a2b_hex(self.key),
|
self.assertRaises(ValueError, self.module.new, a2b_hex(self.key),
|
||||||
self.module.MODE_OPENPGP, "")
|
self.module.MODE_OPENPGP, "")
|
||||||
if hasattr(self.module, "MODE_CCM"):
|
|
||||||
for ivlen in (0,6,14):
|
|
||||||
self.assertRaises(ValueError, self.module.new, a2b_hex(self.key),
|
|
||||||
self.module.MODE_CCM, bchr(0)*ivlen, msg_len=10)
|
|
||||||
self.module.new(a2b_hex(self.key), self.module.MODE_ECB, "")
|
self.module.new(a2b_hex(self.key), self.module.MODE_ECB, "")
|
||||||
self.module.new(a2b_hex(self.key), self.module.MODE_CTR, "", counter=self._dummy_counter)
|
self.module.new(a2b_hex(self.key), self.module.MODE_CTR, "", counter=self._dummy_counter)
|
||||||
|
|
||||||
def _dummy_counter(self):
|
def _dummy_counter(self):
|
||||||
return "\0" * self.module.block_size
|
return "\0" * self.module.block_size
|
||||||
|
|
||||||
def make_block_tests(module, module_name, test_data, additional_params=dict()):
|
def make_block_tests(module, module_name, test_data):
|
||||||
tests = []
|
tests = []
|
||||||
extra_tests_added = 0
|
extra_tests_added = 0
|
||||||
for i in range(len(test_data)):
|
for i in range(len(test_data)):
|
||||||
@@ -696,7 +326,6 @@ def make_block_tests(module, module_name, test_data, additional_params=dict()):
|
|||||||
name = "%s #%d: %s" % (module_name, i+1, description)
|
name = "%s #%d: %s" % (module_name, i+1, description)
|
||||||
params['description'] = name
|
params['description'] = name
|
||||||
params['module_name'] = module_name
|
params['module_name'] = module_name
|
||||||
params.update(additional_params)
|
|
||||||
|
|
||||||
# Add extra test(s) to the test suite before the current test
|
# Add extra test(s) to the test suite before the current test
|
||||||
if not extra_tests_added:
|
if not extra_tests_added:
|
||||||
@@ -710,18 +339,11 @@ def make_block_tests(module, module_name, test_data, additional_params=dict()):
|
|||||||
]
|
]
|
||||||
extra_tests_added = 1
|
extra_tests_added = 1
|
||||||
|
|
||||||
# Extract associated data and MAC for AEAD modes
|
|
||||||
if p_mode in ('CCM', 'EAX', 'SIV', 'GCM'):
|
|
||||||
assoc_data, params['plaintext'] = params['plaintext'].split('|')
|
|
||||||
assoc_data2, params['ciphertext'], params['mac'] = params['ciphertext'].split('|')
|
|
||||||
params['assoc_data'] = assoc_data.split("-")
|
|
||||||
params['mac_len'] = len(params['mac'])>>1
|
|
||||||
|
|
||||||
# Add the current test to the test suite
|
# Add the current test to the test suite
|
||||||
tests.append(CipherSelfTest(module, params))
|
tests.append(CipherSelfTest(module, params))
|
||||||
|
|
||||||
# When using CTR mode, test that the interface behaves like a stream cipher
|
# When using CTR mode, test that the interface behaves like a stream cipher
|
||||||
if p_mode in ('OFB', 'CTR'):
|
if p_mode == 'CTR':
|
||||||
tests.append(CipherStreamingSelfTest(module, params))
|
tests.append(CipherStreamingSelfTest(module, params))
|
||||||
|
|
||||||
# When using CTR mode, test the non-shortcut code path.
|
# When using CTR mode, test the non-shortcut code path.
|
||||||
@@ -733,25 +355,6 @@ def make_block_tests(module, module_name, test_data, additional_params=dict()):
|
|||||||
if not params2['ctr_params'].has_key('disable_shortcut'):
|
if not params2['ctr_params'].has_key('disable_shortcut'):
|
||||||
params2['ctr_params']['disable_shortcut'] = 1
|
params2['ctr_params']['disable_shortcut'] = 1
|
||||||
tests.append(CipherSelfTest(module, params2))
|
tests.append(CipherSelfTest(module, params2))
|
||||||
|
|
||||||
# Add tests that don't use test vectors
|
|
||||||
if hasattr(module, "MODE_CCM"):
|
|
||||||
tests += [
|
|
||||||
CCMMACLengthTest(module),
|
|
||||||
CCMSplitEncryptionTest(module),
|
|
||||||
]
|
|
||||||
for aead_mode in ("MODE_CCM","MODE_EAX", "MODE_SIV", "MODE_GCM"):
|
|
||||||
if hasattr(module, aead_mode):
|
|
||||||
key_sizes = []
|
|
||||||
try:
|
|
||||||
key_sizes += module.key_size
|
|
||||||
except TypeError:
|
|
||||||
key_sizes = [ module.key_size ]
|
|
||||||
for ks in key_sizes:
|
|
||||||
tests += [
|
|
||||||
AEADTests(module, aead_mode, ks),
|
|
||||||
]
|
|
||||||
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
def make_stream_tests(module, module_name, test_data):
|
def make_stream_tests(module, module_name, test_data):
|
||||||
|
|||||||
@@ -26,11 +26,8 @@
|
|||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import sys
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
from Crypto.Util.py3compat import *
|
|
||||||
from common import dict # For compatibility with Python 2.1 and 2.2
|
from common import dict # For compatibility with Python 2.1 and 2.2
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples.
|
# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples.
|
||||||
@@ -1323,30 +1320,6 @@ test_data = [
|
|||||||
'NIST 800-38A, F.4.5, OFB and AES-256',
|
'NIST 800-38A, F.4.5, OFB and AES-256',
|
||||||
dict(mode='OFB', iv='000102030405060708090a0b0c0d0e0f')),
|
dict(mode='OFB', iv='000102030405060708090a0b0c0d0e0f')),
|
||||||
|
|
||||||
('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
|
||||||
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17',
|
|
||||||
'3b3fd92eb72dad20333449f8e83cfb4a'+'7789508d16918f03f53c52dac54ed825'+
|
|
||||||
'9740051e9c5fecf64344f7a82260edcc'+'304c6528f659c778',
|
|
||||||
'2b7e151628aed2a6abf7158809cf4f3c',
|
|
||||||
'NIST 800-38A, F.4.1, OFB and AES-128 (partial last block)',
|
|
||||||
dict(mode='OFB', iv='000102030405060708090a0b0c0d0e0f')),
|
|
||||||
|
|
||||||
('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
|
||||||
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17',
|
|
||||||
'cdc80d6fddf18cab34c25909c99a4174'+'fcc28b8d4c63837c09e81700c1100401'+
|
|
||||||
'8d9a9aeac0f6596f559c6d4daf59a5f2'+'6d9f200857ca6c3e',
|
|
||||||
'8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b',
|
|
||||||
'NIST 800-38A, F.4.3, OFB and AES-192 (partial last block)',
|
|
||||||
dict(mode='OFB', iv='000102030405060708090a0b0c0d0e0f')),
|
|
||||||
|
|
||||||
('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
|
||||||
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17',
|
|
||||||
'dc7e84bfda79164b7ecd8486985d3860'+'4febdc6740d20b3ac88f6ad82a4fb08d'+
|
|
||||||
'71ab47a086e86eedf39d1c5bba97c408'+'0126141d67f37be8',
|
|
||||||
'603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4',
|
|
||||||
'NIST 800-38A, F.4.5, OFB and AES-256 (partial last block)',
|
|
||||||
dict(mode='OFB', iv='000102030405060708090a0b0c0d0e0f')),
|
|
||||||
|
|
||||||
('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+
|
||||||
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
|
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
|
||||||
'874d6191b620e3261bef6864990db6ce'+'9806f66b7970fdff8617187bb9fffdff'+
|
'874d6191b620e3261bef6864990db6ce'+'9806f66b7970fdff8617187bb9fffdff'+
|
||||||
@@ -1445,565 +1418,12 @@ test_data = [
|
|||||||
'5baa61e4c9b93f3f0682250b6cf8331b', # Key (hash of 'password')
|
'5baa61e4c9b93f3f0682250b6cf8331b', # Key (hash of 'password')
|
||||||
'GPG Test Vector #1',
|
'GPG Test Vector #1',
|
||||||
dict(mode='OPENPGP', iv='3d7d3e62282add7eb203eeba5c800733', encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' ) ),
|
dict(mode='OPENPGP', iv='3d7d3e62282add7eb203eeba5c800733', encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' ) ),
|
||||||
|
|
||||||
# NIST SP 800-38C test vectors for CCM
|
|
||||||
# This is a list of tuples with 5 items:
|
|
||||||
#
|
|
||||||
# 1. Associated data + '|' + plaintext
|
|
||||||
# 2. Associated data + '|' + ciphertext + '|' + MAC
|
|
||||||
# 3. AES-128 key
|
|
||||||
# 4. Description
|
|
||||||
# 5. Dictionary of parameters to be passed to AES.new().
|
|
||||||
# It must include the nonce.
|
|
||||||
#
|
|
||||||
( '0001020304050607|20212223',
|
|
||||||
'0001020304050607|7162015b|4dac255d',
|
|
||||||
'404142434445464748494a4b4c4d4e4f',
|
|
||||||
'NIST SP 800-38C Appex C.1',
|
|
||||||
dict(mode='CCM', nonce='10111213141516')
|
|
||||||
),
|
|
||||||
( '000102030405060708090a0b0c0d0e0f|202122232425262728292a2b2c2d2e2f',
|
|
||||||
'000102030405060708090a0b0c0d0e0f|d2a1f0e051ea5f62081a7792073d593d|1fc64fbfaccd',
|
|
||||||
'404142434445464748494a4b4c4d4e4f',
|
|
||||||
'NIST SP 800-38C Appex C.2',
|
|
||||||
dict(mode='CCM', nonce='1011121314151617')
|
|
||||||
),
|
|
||||||
( '000102030405060708090a0b0c0d0e0f10111213|'+
|
|
||||||
'202122232425262728292a2b2c2d2e2f3031323334353637',
|
|
||||||
'000102030405060708090a0b0c0d0e0f10111213|'+
|
|
||||||
'e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5|484392fbc1b09951',
|
|
||||||
'404142434445464748494a4b4c4d4e4f',
|
|
||||||
'NIST SP 800-38C Appex C.3',
|
|
||||||
dict(mode='CCM', nonce='101112131415161718191a1b')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
(''.join(["%02X" % (x*16+y) for x in xrange(0,16) for y in xrange(0,16)]))*256+'|'+
|
|
||||||
'202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f',
|
|
||||||
(''.join(["%02X" % (x*16+y) for x in xrange(0,16) for y in xrange(0,16)]))*256+'|'+
|
|
||||||
'69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72|'+
|
|
||||||
'b4ac6bec93e8598e7f0dadbcea5b',
|
|
||||||
'404142434445464748494a4b4c4d4e4f',
|
|
||||||
'NIST SP 800-38C Appex C.4',
|
|
||||||
dict(mode='CCM', nonce='101112131415161718191a1b1c')
|
|
||||||
),
|
|
||||||
# RFC3610 test vectors
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e',
|
|
||||||
'0001020304050607|588c979a61c663d2f066d0c2c0f989806d5f6b61dac384|'+
|
|
||||||
'17e8d12cfdf926e0',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #1',
|
|
||||||
dict(mode='CCM', nonce='00000003020100a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
|
||||||
'0001020304050607|72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b|'+
|
|
||||||
'a091d56e10400916',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #2',
|
|
||||||
dict(mode='CCM', nonce='00000004030201a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
|
|
||||||
'0001020304050607|51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657|'+
|
|
||||||
'4adaa76fbd9fb0c5',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #3',
|
|
||||||
dict(mode='CCM', nonce='00000005040302A0A1A2A3A4A5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e',
|
|
||||||
'000102030405060708090a0b|a28c6865939a9a79faaa5c4c2a9d4a91cdac8c|'+
|
|
||||||
'96c861b9c9e61ef1',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #4',
|
|
||||||
dict(mode='CCM', nonce='00000006050403a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
|
||||||
'000102030405060708090a0b|dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e|'+
|
|
||||||
'51e83f077d9c2d93',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #5',
|
|
||||||
dict(mode='CCM', nonce='00000007060504a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e1f20',
|
|
||||||
'000102030405060708090a0b|6fc1b011f006568b5171a42d953d469b2570a4bd87|'+
|
|
||||||
'405a0443ac91cb94',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #6',
|
|
||||||
dict(mode='CCM', nonce='00000008070605a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e',
|
|
||||||
'0001020304050607|0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c|'+
|
|
||||||
'048c56602c97acbb7490',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #7',
|
|
||||||
dict(mode='CCM', nonce='00000009080706a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
|
||||||
'0001020304050607|7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24|'+
|
|
||||||
'c17b4433f434963f34b4',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #8',
|
|
||||||
dict(mode='CCM', nonce='0000000a090807a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0001020304050607|08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
|
|
||||||
'0001020304050607|82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197|'+
|
|
||||||
'ea9c07e56b5eb17e5f4e',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #9',
|
|
||||||
dict(mode='CCM', nonce='0000000b0a0908a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e',
|
|
||||||
'000102030405060708090a0b|07342594157785152b074098330abb141b947b|'+
|
|
||||||
'566aa9406b4d999988dd',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #10',
|
|
||||||
dict(mode='CCM', nonce='0000000c0b0a09a0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e1f',
|
|
||||||
'000102030405060708090a0b|676bb20380b0e301e8ab79590a396da78b834934|'+
|
|
||||||
'f53aa2e9107a8b6c022c',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #11',
|
|
||||||
dict(mode='CCM', nonce='0000000d0c0b0aa0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'000102030405060708090a0b|0c0d0e0f101112131415161718191a1b1c1d1e1f20',
|
|
||||||
'000102030405060708090a0b|c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43|'+
|
|
||||||
'cd1aa31662e7ad65d6db',
|
|
||||||
'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf',
|
|
||||||
'RFC3610 Packet Vector #12',
|
|
||||||
dict(mode='CCM', nonce='0000000e0d0c0ba0a1a2a3a4a5')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0be1a88bace018b1|08e8cf97d820ea258460e96ad9cf5289054d895ceac47c',
|
|
||||||
'0be1a88bace018b1|4cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8|'+
|
|
||||||
'e78cf7cb0cddd7b3',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #13',
|
|
||||||
dict(mode='CCM', nonce='00412b4ea9cdbe3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'63018f76dc8a1bcb|9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec',
|
|
||||||
'63018f76dc8a1bcb|4ccb1e7ca981befaa0726c55d378061298c85c92814abc33|'+
|
|
||||||
'c52ee81d7d77c08a',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #14',
|
|
||||||
dict(mode='CCM', nonce='0033568ef7b2633c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'aa6cfa36cae86b40|b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e',
|
|
||||||
'aa6cfa36cae86b40|b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708|'+
|
|
||||||
'a776796edb723506',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #15',
|
|
||||||
dict(mode='CCM', nonce='00103fe41336713c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'd0d0735c531e1becf049c244|12daac5630efa5396f770ce1a66b21f7b2101c',
|
|
||||||
'd0d0735c531e1becf049c244|14d253c3967b70609b7cbb7c49916028324526|'+
|
|
||||||
'9a6f49975bcadeaf',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #16',
|
|
||||||
dict(mode='CCM', nonce='00764c63b8058e3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'77b60f011c03e1525899bcae|e88b6a46c78d63e52eb8c546efb5de6f75e9cc0d',
|
|
||||||
'77b60f011c03e1525899bcae|5545ff1a085ee2efbf52b2e04bee1e2336c73e3f|'+
|
|
||||||
'762c0c7744fe7e3c',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #17',
|
|
||||||
dict(mode='CCM', nonce='00f8b678094e3b3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'cd9044d2b71fdb8120ea60c0|6435acbafb11a82e2f071d7ca4a5ebd93a803ba87f',
|
|
||||||
'cd9044d2b71fdb8120ea60c0|009769ecabdf48625594c59251e6035722675e04c8|'+
|
|
||||||
'47099e5ae0704551',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #18',
|
|
||||||
dict(mode='CCM', nonce='00d560912d3f703c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'd85bc7e69f944fb8|8a19b950bcf71a018e5e6701c91787659809d67dbedd18',
|
|
||||||
'd85bc7e69f944fb8|bc218daa947427b6db386a99ac1aef23ade0b52939cb6a|'+
|
|
||||||
'637cf9bec2408897c6ba',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #19',
|
|
||||||
dict(mode='CCM', nonce='0042fff8f1951c3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'74a0ebc9069f5b37|1761433c37c5a35fc1f39f406302eb907c6163be38c98437',
|
|
||||||
'74a0ebc9069f5b37|5810e6fd25874022e80361a478e3e9cf484ab04f447efff6|'+
|
|
||||||
'f0a477cc2fc9bf548944',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #20',
|
|
||||||
dict(mode='CCM', nonce='00920f40e56cdc3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'44a3aa3aae6475ca|a434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa',
|
|
||||||
'44a3aa3aae6475ca|f2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f154|'+
|
|
||||||
'4d4151a4ed3a8b87b9ce',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #21',
|
|
||||||
dict(mode='CCM', nonce='0027ca0c7120bc3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'ec46bb63b02520c33c49fd70|b96b49e21d621741632875db7f6c9243d2d7c2',
|
|
||||||
'ec46bb63b02520c33c49fd70|31d750a09da3ed7fddd49a2032aabf17ec8ebf|'+
|
|
||||||
'7d22c8088c666be5c197',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #22',
|
|
||||||
dict(mode='CCM', nonce='005b8ccbcd9af83c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'47a65ac78b3d594227e85e71|e2fcfbb880442c731bf95167c8ffd7895e337076',
|
|
||||||
'47a65ac78b3d594227e85e71|e882f1dbd38ce3eda7c23f04dd65071eb41342ac|'+
|
|
||||||
'df7e00dccec7ae52987d',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #23',
|
|
||||||
dict(mode='CCM', nonce='003ebe94044b9a3c9696766cfa')
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'6e37a6ef546d955d34ab6059|abf21c0b02feb88f856df4a37381bce3cc128517d4',
|
|
||||||
'6e37a6ef546d955d34ab6059|f32905b88a641b04b9c9ffb58cc390900f3da12ab1|'+
|
|
||||||
'6dce9e82efa16da62059',
|
|
||||||
'd7828d13b2b0bdc325a76236df93cc6b',
|
|
||||||
'RFC3610 Packet Vector #24',
|
|
||||||
dict(mode='CCM', nonce='008d493b30ae8b3c9696766cfa')
|
|
||||||
),
|
|
||||||
|
|
||||||
# Test vectors for EAX taken from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
|
|
||||||
# This is a list of tuples with 5 items:
|
|
||||||
#
|
|
||||||
# 1. Header + '|' + plaintext
|
|
||||||
# 2. Header + '|' + ciphertext + '|' + MAC
|
|
||||||
# 3. AES-128 key
|
|
||||||
# 4. Description
|
|
||||||
# 5. Dictionary of parameters to be passed to AES.new(). It must
|
|
||||||
# include the nonce.
|
|
||||||
#
|
|
||||||
( '6bfb914fd07eae6b|',
|
|
||||||
'6bfb914fd07eae6b||e037830e8389f27b025a2d6527e79d01',
|
|
||||||
'233952dee4d5ed5f9b9c6d6ff80ff478',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='62EC67F9C3A4A407FCB2A8C49031A8B3')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'fa3bfd4806eb53fa|f7fb',
|
|
||||||
'fa3bfd4806eb53fa|19dd|5c4c9331049d0bdab0277408f67967e5',
|
|
||||||
'91945d3f4dcbee0bf45ef52255f095a4',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='BECAF043B0A23D843194BA972C66DEBD')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '234a3463c1264ac6|1a47cb4933',
|
|
||||||
'234a3463c1264ac6|d851d5bae0|3a59f238a23e39199dc9266626c40f80',
|
|
||||||
'01f74ad64077f2e704c0f60ada3dd523',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='70C3DB4F0D26368400A10ED05D2BFF5E')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '33cce2eabff5a79d|481c9e39b1',
|
|
||||||
'33cce2eabff5a79d|632a9d131a|d4c168a4225d8e1ff755939974a7bede',
|
|
||||||
'd07cf6cbb7f313bdde66b727afd3c5e8',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='8408DFFF3C1A2B1292DC199E46B7D617')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'aeb96eaebe2970e9|40d0c07da5e4',
|
|
||||||
'aeb96eaebe2970e9|071dfe16c675|cb0677e536f73afe6a14b74ee49844dd',
|
|
||||||
'35b6d0580005bbc12b0587124557d2c2',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='FDB6B06676EEDC5C61D74276E1F8E816')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'd4482d1ca78dce0f|4de3b35c3fc039245bd1fb7d',
|
|
||||||
'd4482d1ca78dce0f|835bb4f15d743e350e728414|abb8644fd6ccb86947c5e10590210a4f',
|
|
||||||
'bd8e6e11475e60b268784c38c62feb22',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='6EAC5C93072D8E8513F750935E46DA1B')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '65d2017990d62528|8b0a79306c9ce7ed99dae4f87f8dd61636',
|
|
||||||
'65d2017990d62528|02083e3979da014812f59f11d52630da30|137327d10649b0aa6e1c181db617d7f2',
|
|
||||||
'7c77d6e813bed5ac98baa417477a2e7d',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='1A8C98DCD73D38393B2BF1569DEEFC19')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '54b9f04e6a09189a|1bda122bce8a8dbaf1877d962b8592dd2d56',
|
|
||||||
'54b9f04e6a09189a|2ec47b2c4954a489afc7ba4897edcdae8cc3|3b60450599bd02c96382902aef7f832a',
|
|
||||||
'5fff20cafab119ca2fc73549e20f5b0d',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='DDE59B97D722156D4D9AFF2BC7559826')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '899a175897561d7e|6cf36720872b8513f6eab1a8a44438d5ef11',
|
|
||||||
'899a175897561d7e|0de18fd0fdd91e7af19f1d8ee8733938b1e8|e7f6d2231618102fdb7fe55ff1991700',
|
|
||||||
'a4a4782bcffd3ec5e7ef6d8c34a56123',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='B781FCF2F75FA5A8DE97A9CA48E522EC')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '126735fcc320d25a|ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7',
|
|
||||||
'126735fcc320d25a|cb8920f87a6c75cff39627b56e3ed197c552d295a7|cfc46afc253b4652b1af3795b124ab6e',
|
|
||||||
'8395fcf1e95bebd697bd010bc766aac3',
|
|
||||||
'EAX spec Appendix G',
|
|
||||||
dict(mode='EAX', nonce='22E7ADD93CFC6393C57EC0B3C17D6B44')
|
|
||||||
),
|
|
||||||
|
|
||||||
# Test vectors for SIV taken from RFC5297
|
|
||||||
# This is a list of tuples with 5 items:
|
|
||||||
#
|
|
||||||
# 1. Header + '|' + plaintext
|
|
||||||
# 2. Header + '|' + ciphertext + '|' + MAC
|
|
||||||
# 3. AES-128 key
|
|
||||||
# 4. Description
|
|
||||||
# 5. Dictionary of parameters to be passed to AES.new().
|
|
||||||
# It must include the nonce.
|
|
||||||
#
|
|
||||||
# A "Header" is a dash ('-') separated sequece of components.
|
|
||||||
#
|
|
||||||
( '101112131415161718191a1b1c1d1e1f2021222324252627|112233445566778899aabbccddee',
|
|
||||||
'101112131415161718191a1b1c1d1e1f2021222324252627|40c02b9690c4dc04daef7f6afe5c|' +
|
|
||||||
'85632d07c6e8f37f950acd320a2ecc93',
|
|
||||||
'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff',
|
|
||||||
'RFC5297 A.1',
|
|
||||||
dict(mode='SIV', nonce=None)
|
|
||||||
),
|
|
||||||
|
|
||||||
( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' +
|
|
||||||
'7766554433221100-102030405060708090a0|' +
|
|
||||||
'7468697320697320736f6d6520706c61696e7465787420746f20656e63727970' +
|
|
||||||
'74207573696e67205349562d414553',
|
|
||||||
|
|
||||||
'00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' +
|
|
||||||
'7766554433221100-102030405060708090a0|' +
|
|
||||||
'cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829' +
|
|
||||||
'ea64ad544a272e9c485b62a3fd5c0d|' +
|
|
||||||
'7bdb6e3b432667eb06f4d14bff2fbd0f',
|
|
||||||
|
|
||||||
'7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f',
|
|
||||||
'RFC5297 A.2',
|
|
||||||
dict(mode='SIV', nonce='09f911029d74e35bd84156c5635688c0')
|
|
||||||
),
|
|
||||||
|
|
||||||
# Test vectors for GCM taken from
|
|
||||||
# http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
|
|
||||||
# This is a list of tuples with 5 items:
|
|
||||||
#
|
|
||||||
# 1. Header + '|' + plaintext
|
|
||||||
# 2. Header + '|' + ciphertext + '|' + MAC
|
|
||||||
# 3. AES-128 key
|
|
||||||
# 4. Description
|
|
||||||
# 5. Dictionary of parameters to be passed to AES.new().
|
|
||||||
# It must include the nonce.
|
|
||||||
#
|
|
||||||
( '|',
|
|
||||||
'||58e2fccefa7e3061367f1d57a4e7455a',
|
|
||||||
'00000000000000000000000000000000',
|
|
||||||
'GCM Test Case 1',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|00000000000000000000000000000000',
|
|
||||||
'|0388dace60b6a392f328c2b971b2fe78|ab6e47d42cec13bdf53a67b21257bddf',
|
|
||||||
'00000000000000000000000000000000',
|
|
||||||
'GCM Test Case 2',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
|
|
||||||
'|42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' +
|
|
||||||
'21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985|' +
|
|
||||||
'4d5c2af327cd64a62cf35abd2ba6fab4',
|
|
||||||
'feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 3',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' +
|
|
||||||
'21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091|' +
|
|
||||||
'5bc94fbc3221a5db94fae95ae7121a47',
|
|
||||||
'feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 4',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c7423' +
|
|
||||||
'73806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598|' +
|
|
||||||
'3612d2e79e3b0785561be14aaca2fccb',
|
|
||||||
'feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 5',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbad')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca7' +
|
|
||||||
'01e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5|' +
|
|
||||||
'619cc5aefffe0bfa462af43c1699d050',
|
|
||||||
'feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 6',
|
|
||||||
dict(mode='GCM', nonce='9313225df88406e555909c5aff5269aa'+
|
|
||||||
'6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254'+
|
|
||||||
'16aedbf5a0de6a57a637b39b' )
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|',
|
|
||||||
'||cd33b28ac773f74ba00ed1f312572435',
|
|
||||||
'000000000000000000000000000000000000000000000000',
|
|
||||||
'GCM Test Case 7',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|00000000000000000000000000000000',
|
|
||||||
'|98e7247c07f0fe411c267e4384b0f600|2ff58d80033927ab8ef4d4587514f0fb',
|
|
||||||
'000000000000000000000000000000000000000000000000',
|
|
||||||
'GCM Test Case 8',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
|
|
||||||
'|3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' +
|
|
||||||
'7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256|' +
|
|
||||||
'9924a7c8587336bfb118024db8674a14',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c',
|
|
||||||
'GCM Test Case 9',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' +
|
|
||||||
'7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710|' +
|
|
||||||
'2519498e80f1478f37ba55bd6d27618c',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c',
|
|
||||||
'GCM Test Case 10',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057' +
|
|
||||||
'fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7|' +
|
|
||||||
'65dcc57fcf623a24094fcca40d3533f8',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c',
|
|
||||||
'GCM Test Case 11',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbad')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e45' +
|
|
||||||
'81e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b|' +
|
|
||||||
'dcf566ff291c25bbb8568fc3d376a6d9',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c',
|
|
||||||
'GCM Test Case 12',
|
|
||||||
dict(mode='GCM', nonce='9313225df88406e555909c5aff5269aa'+
|
|
||||||
'6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254'+
|
|
||||||
'16aedbf5a0de6a57a637b39b' )
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|',
|
|
||||||
'||530f8afbc74536b9a963b4f1c4cb738b',
|
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
||||||
'GCM Test Case 13',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|00000000000000000000000000000000',
|
|
||||||
'|cea7403d4d606b6e074ec5d3baf39d18|d0d1c8a799996bf0265b98b5d48ab919',
|
|
||||||
'0000000000000000000000000000000000000000000000000000000000000000',
|
|
||||||
'GCM Test Case 14',
|
|
||||||
dict(mode='GCM', nonce='000000000000000000000000')
|
|
||||||
),
|
|
||||||
|
|
||||||
( '|d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255',
|
|
||||||
'|522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' +
|
|
||||||
'8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad|' +
|
|
||||||
'b094dac5d93471bdec1a502270e3cc6c',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 15',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' +
|
|
||||||
'8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662|' +
|
|
||||||
'76fc6ece0f4e1768cddf8853bb2d551b',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 16',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbaddecaf888')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0' +
|
|
||||||
'feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f|' +
|
|
||||||
'3a337dbf46a792c45e454913fe2ea8f2',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 17',
|
|
||||||
dict(mode='GCM', nonce='cafebabefacedbad')
|
|
||||||
),
|
|
||||||
|
|
||||||
( 'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' +
|
|
||||||
'1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39',
|
|
||||||
'feedfacedeadbeeffeedfacedeadbeefabaddad2|' +
|
|
||||||
'5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf4' +
|
|
||||||
'0fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f|' +
|
|
||||||
'a44a8266ee1c8eb0c8b5d4cf5ae9f19a',
|
|
||||||
'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308',
|
|
||||||
'GCM Test Case 18',
|
|
||||||
dict(mode='GCM', nonce='9313225df88406e555909c5aff5269aa'+
|
|
||||||
'6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254'+
|
|
||||||
'16aedbf5a0de6a57a637b39b' )
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Util import cpuid
|
|
||||||
from common import make_block_tests
|
from common import make_block_tests
|
||||||
|
return make_block_tests(AES, "AES", test_data)
|
||||||
tests = make_block_tests(AES, "AES", test_data, {'use_aesni': False})
|
|
||||||
if cpuid.have_aes_ni():
|
|
||||||
# Run tests with AES-NI instructions if they are available.
|
|
||||||
tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True})
|
|
||||||
return tests
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -27,10 +27,6 @@
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
from Crypto.SelfTest.st_common import *
|
|
||||||
from binascii import unhexlify
|
|
||||||
|
|
||||||
from Crypto.Cipher import ARC4
|
|
||||||
|
|
||||||
# This is a list of (plaintext, ciphertext, key[, description]) tuples.
|
# This is a list of (plaintext, ciphertext, key[, description]) tuples.
|
||||||
test_data = [
|
test_data = [
|
||||||
@@ -72,382 +68,10 @@ test_data = [
|
|||||||
"Test vector 4"),
|
"Test vector 4"),
|
||||||
]
|
]
|
||||||
|
|
||||||
class RFC6229_Tests(unittest.TestCase):
|
|
||||||
# Test vectors from RFC 6229. Each test vector is a tuple with two items:
|
|
||||||
# the ARC4 key and a dictionary. The dictionary has keystream offsets as keys
|
|
||||||
# and the 16-byte keystream starting at the relevant offset as value.
|
|
||||||
rfc6229_data = [
|
|
||||||
# Page 3
|
|
||||||
(
|
|
||||||
'0102030405',
|
|
||||||
{
|
|
||||||
0: 'b2 39 63 05 f0 3d c0 27 cc c3 52 4a 0a 11 18 a8',
|
|
||||||
16: '69 82 94 4f 18 fc 82 d5 89 c4 03 a4 7a 0d 09 19',
|
|
||||||
240: '28 cb 11 32 c9 6c e2 86 42 1d ca ad b8 b6 9e ae',
|
|
||||||
256: '1c fc f6 2b 03 ed db 64 1d 77 df cf 7f 8d 8c 93',
|
|
||||||
496: '42 b7 d0 cd d9 18 a8 a3 3d d5 17 81 c8 1f 40 41',
|
|
||||||
512: '64 59 84 44 32 a7 da 92 3c fb 3e b4 98 06 61 f6',
|
|
||||||
752: 'ec 10 32 7b de 2b ee fd 18 f9 27 76 80 45 7e 22',
|
|
||||||
768: 'eb 62 63 8d 4f 0b a1 fe 9f ca 20 e0 5b f8 ff 2b',
|
|
||||||
1008:'45 12 90 48 e6 a0 ed 0b 56 b4 90 33 8f 07 8d a5',
|
|
||||||
1024:'30 ab bc c7 c2 0b 01 60 9f 23 ee 2d 5f 6b b7 df',
|
|
||||||
1520:'32 94 f7 44 d8 f9 79 05 07 e7 0f 62 e5 bb ce ea',
|
|
||||||
1536:'d8 72 9d b4 18 82 25 9b ee 4f 82 53 25 f5 a1 30',
|
|
||||||
2032:'1e b1 4a 0c 13 b3 bf 47 fa 2a 0b a9 3a d4 5b 8b',
|
|
||||||
2048:'cc 58 2f 8b a9 f2 65 e2 b1 be 91 12 e9 75 d2 d7',
|
|
||||||
3056:'f2 e3 0f 9b d1 02 ec bf 75 aa ad e9 bc 35 c4 3c',
|
|
||||||
3072:'ec 0e 11 c4 79 dc 32 9d c8 da 79 68 fe 96 56 81',
|
|
||||||
4080:'06 83 26 a2 11 84 16 d2 1f 9d 04 b2 cd 1c a0 50',
|
|
||||||
4096:'ff 25 b5 89 95 99 67 07 e5 1f bd f0 8b 34 d8 75'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 4
|
|
||||||
(
|
|
||||||
'01020304050607',
|
|
||||||
{
|
|
||||||
0: '29 3f 02 d4 7f 37 c9 b6 33 f2 af 52 85 fe b4 6b',
|
|
||||||
16: 'e6 20 f1 39 0d 19 bd 84 e2 e0 fd 75 20 31 af c1',
|
|
||||||
240: '91 4f 02 53 1c 92 18 81 0d f6 0f 67 e3 38 15 4c',
|
|
||||||
256: 'd0 fd b5 83 07 3c e8 5a b8 39 17 74 0e c0 11 d5',
|
|
||||||
496: '75 f8 14 11 e8 71 cf fa 70 b9 0c 74 c5 92 e4 54',
|
|
||||||
512: '0b b8 72 02 93 8d ad 60 9e 87 a5 a1 b0 79 e5 e4',
|
|
||||||
752: 'c2 91 12 46 b6 12 e7 e7 b9 03 df ed a1 da d8 66',
|
|
||||||
768: '32 82 8f 91 50 2b 62 91 36 8d e8 08 1d e3 6f c2',
|
|
||||||
1008:'f3 b9 a7 e3 b2 97 bf 9a d8 04 51 2f 90 63 ef f1',
|
|
||||||
1024:'8e cb 67 a9 ba 1f 55 a5 a0 67 e2 b0 26 a3 67 6f',
|
|
||||||
1520:'d2 aa 90 2b d4 2d 0d 7c fd 34 0c d4 58 10 52 9f',
|
|
||||||
1536:'78 b2 72 c9 6e 42 ea b4 c6 0b d9 14 e3 9d 06 e3',
|
|
||||||
2032:'f4 33 2f d3 1a 07 93 96 ee 3c ee 3f 2a 4f f0 49',
|
|
||||||
2048:'05 45 97 81 d4 1f da 7f 30 c1 be 7e 12 46 c6 23',
|
|
||||||
3056:'ad fd 38 68 b8 e5 14 85 d5 e6 10 01 7e 3d d6 09',
|
|
||||||
3072:'ad 26 58 1c 0c 5b e4 5f 4c ea 01 db 2f 38 05 d5',
|
|
||||||
4080:'f3 17 2c ef fc 3b 3d 99 7c 85 cc d5 af 1a 95 0c',
|
|
||||||
4096:'e7 4b 0b 97 31 22 7f d3 7c 0e c0 8a 47 dd d8 b8'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0102030405060708',
|
|
||||||
{
|
|
||||||
0: '97 ab 8a 1b f0 af b9 61 32 f2 f6 72 58 da 15 a8',
|
|
||||||
16: '82 63 ef db 45 c4 a1 86 84 ef 87 e6 b1 9e 5b 09',
|
|
||||||
240: '96 36 eb c9 84 19 26 f4 f7 d1 f3 62 bd df 6e 18',
|
|
||||||
256: 'd0 a9 90 ff 2c 05 fe f5 b9 03 73 c9 ff 4b 87 0a',
|
|
||||||
496: '73 23 9f 1d b7 f4 1d 80 b6 43 c0 c5 25 18 ec 63',
|
|
||||||
512: '16 3b 31 99 23 a6 bd b4 52 7c 62 61 26 70 3c 0f',
|
|
||||||
752: '49 d6 c8 af 0f 97 14 4a 87 df 21 d9 14 72 f9 66',
|
|
||||||
768: '44 17 3a 10 3b 66 16 c5 d5 ad 1c ee 40 c8 63 d0',
|
|
||||||
1008:'27 3c 9c 4b 27 f3 22 e4 e7 16 ef 53 a4 7d e7 a4',
|
|
||||||
1024:'c6 d0 e7 b2 26 25 9f a9 02 34 90 b2 61 67 ad 1d',
|
|
||||||
1520:'1f e8 98 67 13 f0 7c 3d 9a e1 c1 63 ff 8c f9 d3',
|
|
||||||
1536:'83 69 e1 a9 65 61 0b e8 87 fb d0 c7 91 62 aa fb',
|
|
||||||
2032:'0a 01 27 ab b4 44 84 b9 fb ef 5a bc ae 1b 57 9f',
|
|
||||||
2048:'c2 cd ad c6 40 2e 8e e8 66 e1 f3 7b db 47 e4 2c',
|
|
||||||
3056:'26 b5 1e a3 7d f8 e1 d6 f7 6f c3 b6 6a 74 29 b3',
|
|
||||||
3072:'bc 76 83 20 5d 4f 44 3d c1 f2 9d da 33 15 c8 7b',
|
|
||||||
4080:'d5 fa 5a 34 69 d2 9a aa f8 3d 23 58 9d b8 c8 5b',
|
|
||||||
4096:'3f b4 6e 2c 8f 0f 06 8e dc e8 cd cd 7d fc 58 62'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 5
|
|
||||||
(
|
|
||||||
'0102030405060708090a',
|
|
||||||
{
|
|
||||||
0: 'ed e3 b0 46 43 e5 86 cc 90 7d c2 18 51 70 99 02',
|
|
||||||
16: '03 51 6b a7 8f 41 3b eb 22 3a a5 d4 d2 df 67 11',
|
|
||||||
240: '3c fd 6c b5 8e e0 fd de 64 01 76 ad 00 00 04 4d',
|
|
||||||
256: '48 53 2b 21 fb 60 79 c9 11 4c 0f fd 9c 04 a1 ad',
|
|
||||||
496: '3e 8c ea 98 01 71 09 97 90 84 b1 ef 92 f9 9d 86',
|
|
||||||
512: 'e2 0f b4 9b db 33 7e e4 8b 8d 8d c0 f4 af ef fe',
|
|
||||||
752: '5c 25 21 ea cd 79 66 f1 5e 05 65 44 be a0 d3 15',
|
|
||||||
768: 'e0 67 a7 03 19 31 a2 46 a6 c3 87 5d 2f 67 8a cb',
|
|
||||||
1008:'a6 4f 70 af 88 ae 56 b6 f8 75 81 c0 e2 3e 6b 08',
|
|
||||||
1024:'f4 49 03 1d e3 12 81 4e c6 f3 19 29 1f 4a 05 16',
|
|
||||||
1520:'bd ae 85 92 4b 3c b1 d0 a2 e3 3a 30 c6 d7 95 99',
|
|
||||||
1536:'8a 0f ed db ac 86 5a 09 bc d1 27 fb 56 2e d6 0a',
|
|
||||||
2032:'b5 5a 0a 5b 51 a1 2a 8b e3 48 99 c3 e0 47 51 1a',
|
|
||||||
2048:'d9 a0 9c ea 3c e7 5f e3 96 98 07 03 17 a7 13 39',
|
|
||||||
3056:'55 22 25 ed 11 77 f4 45 84 ac 8c fa 6c 4e b5 fc',
|
|
||||||
3072:'7e 82 cb ab fc 95 38 1b 08 09 98 44 21 29 c2 f8',
|
|
||||||
4080:'1f 13 5e d1 4c e6 0a 91 36 9d 23 22 be f2 5e 3c',
|
|
||||||
4096:'08 b6 be 45 12 4a 43 e2 eb 77 95 3f 84 dc 85 53'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0102030405060708090a0b0c0d0e0f10',
|
|
||||||
{
|
|
||||||
0: '9a c7 cc 9a 60 9d 1e f7 b2 93 28 99 cd e4 1b 97',
|
|
||||||
16: '52 48 c4 95 90 14 12 6a 6e 8a 84 f1 1d 1a 9e 1c',
|
|
||||||
240: '06 59 02 e4 b6 20 f6 cc 36 c8 58 9f 66 43 2f 2b',
|
|
||||||
256: 'd3 9d 56 6b c6 bc e3 01 07 68 15 15 49 f3 87 3f',
|
|
||||||
496: 'b6 d1 e6 c4 a5 e4 77 1c ad 79 53 8d f2 95 fb 11',
|
|
||||||
512: 'c6 8c 1d 5c 55 9a 97 41 23 df 1d bc 52 a4 3b 89',
|
|
||||||
752: 'c5 ec f8 8d e8 97 fd 57 fe d3 01 70 1b 82 a2 59',
|
|
||||||
768: 'ec cb e1 3d e1 fc c9 1c 11 a0 b2 6c 0b c8 fa 4d',
|
|
||||||
1008:'e7 a7 25 74 f8 78 2a e2 6a ab cf 9e bc d6 60 65',
|
|
||||||
1024:'bd f0 32 4e 60 83 dc c6 d3 ce dd 3c a8 c5 3c 16',
|
|
||||||
1520:'b4 01 10 c4 19 0b 56 22 a9 61 16 b0 01 7e d2 97',
|
|
||||||
1536:'ff a0 b5 14 64 7e c0 4f 63 06 b8 92 ae 66 11 81',
|
|
||||||
2032:'d0 3d 1b c0 3c d3 3d 70 df f9 fa 5d 71 96 3e bd',
|
|
||||||
2048:'8a 44 12 64 11 ea a7 8b d5 1e 8d 87 a8 87 9b f5',
|
|
||||||
3056:'fa be b7 60 28 ad e2 d0 e4 87 22 e4 6c 46 15 a3',
|
|
||||||
3072:'c0 5d 88 ab d5 03 57 f9 35 a6 3c 59 ee 53 76 23',
|
|
||||||
4080:'ff 38 26 5c 16 42 c1 ab e8 d3 c2 fe 5e 57 2b f8',
|
|
||||||
4096:'a3 6a 4c 30 1a e8 ac 13 61 0c cb c1 22 56 ca cc'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 6
|
|
||||||
(
|
|
||||||
'0102030405060708090a0b0c0d0e0f101112131415161718',
|
|
||||||
{
|
|
||||||
0: '05 95 e5 7f e5 f0 bb 3c 70 6e da c8 a4 b2 db 11',
|
|
||||||
16: 'df de 31 34 4a 1a f7 69 c7 4f 07 0a ee 9e 23 26',
|
|
||||||
240: 'b0 6b 9b 1e 19 5d 13 d8 f4 a7 99 5c 45 53 ac 05',
|
|
||||||
256: '6b d2 37 8e c3 41 c9 a4 2f 37 ba 79 f8 8a 32 ff',
|
|
||||||
496: 'e7 0b ce 1d f7 64 5a db 5d 2c 41 30 21 5c 35 22',
|
|
||||||
512: '9a 57 30 c7 fc b4 c9 af 51 ff da 89 c7 f1 ad 22',
|
|
||||||
752: '04 85 05 5f d4 f6 f0 d9 63 ef 5a b9 a5 47 69 82',
|
|
||||||
768: '59 1f c6 6b cd a1 0e 45 2b 03 d4 55 1f 6b 62 ac',
|
|
||||||
1008:'27 53 cc 83 98 8a fa 3e 16 88 a1 d3 b4 2c 9a 02',
|
|
||||||
1024:'93 61 0d 52 3d 1d 3f 00 62 b3 c2 a3 bb c7 c7 f0',
|
|
||||||
1520:'96 c2 48 61 0a ad ed fe af 89 78 c0 3d e8 20 5a',
|
|
||||||
1536:'0e 31 7b 3d 1c 73 b9 e9 a4 68 8f 29 6d 13 3a 19',
|
|
||||||
2032:'bd f0 e6 c3 cc a5 b5 b9 d5 33 b6 9c 56 ad a1 20',
|
|
||||||
2048:'88 a2 18 b6 e2 ec e1 e6 24 6d 44 c7 59 d1 9b 10',
|
|
||||||
3056:'68 66 39 7e 95 c1 40 53 4f 94 26 34 21 00 6e 40',
|
|
||||||
3072:'32 cb 0a 1e 95 42 c6 b3 b8 b3 98 ab c3 b0 f1 d5',
|
|
||||||
4080:'29 a0 b8 ae d5 4a 13 23 24 c6 2e 42 3f 54 b4 c8',
|
|
||||||
4096:'3c b0 f3 b5 02 0a 98 b8 2a f9 fe 15 44 84 a1 68'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20',
|
|
||||||
{
|
|
||||||
0: 'ea a6 bd 25 88 0b f9 3d 3f 5d 1e 4c a2 61 1d 91',
|
|
||||||
16: 'cf a4 5c 9f 7e 71 4b 54 bd fa 80 02 7c b1 43 80',
|
|
||||||
240: '11 4a e3 44 de d7 1b 35 f2 e6 0f eb ad 72 7f d8',
|
|
||||||
256: '02 e1 e7 05 6b 0f 62 39 00 49 64 22 94 3e 97 b6',
|
|
||||||
496: '91 cb 93 c7 87 96 4e 10 d9 52 7d 99 9c 6f 93 6b',
|
|
||||||
512: '49 b1 8b 42 f8 e8 36 7c be b5 ef 10 4b a1 c7 cd',
|
|
||||||
752: '87 08 4b 3b a7 00 ba de 95 56 10 67 27 45 b3 74',
|
|
||||||
768: 'e7 a7 b9 e9 ec 54 0d 5f f4 3b db 12 79 2d 1b 35',
|
|
||||||
1008:'c7 99 b5 96 73 8f 6b 01 8c 76 c7 4b 17 59 bd 90',
|
|
||||||
1024:'7f ec 5b fd 9f 9b 89 ce 65 48 30 90 92 d7 e9 58',
|
|
||||||
1520:'40 f2 50 b2 6d 1f 09 6a 4a fd 4c 34 0a 58 88 15',
|
|
||||||
1536:'3e 34 13 5c 79 db 01 02 00 76 76 51 cf 26 30 73',
|
|
||||||
2032:'f6 56 ab cc f8 8d d8 27 02 7b 2c e9 17 d4 64 ec',
|
|
||||||
2048:'18 b6 25 03 bf bc 07 7f ba bb 98 f2 0d 98 ab 34',
|
|
||||||
3056:'8a ed 95 ee 5b 0d cb fb ef 4e b2 1d 3a 3f 52 f9',
|
|
||||||
3072:'62 5a 1a b0 0e e3 9a 53 27 34 6b dd b0 1a 9c 18',
|
|
||||||
4080:'a1 3a 7c 79 c7 e1 19 b5 ab 02 96 ab 28 c3 00 b9',
|
|
||||||
4096:'f3 e4 c0 a2 e0 2d 1d 01 f7 f0 a7 46 18 af 2b 48'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 7
|
|
||||||
(
|
|
||||||
'833222772a',
|
|
||||||
{
|
|
||||||
0: '80 ad 97 bd c9 73 df 8a 2e 87 9e 92 a4 97 ef da',
|
|
||||||
16: '20 f0 60 c2 f2 e5 12 65 01 d3 d4 fe a1 0d 5f c0',
|
|
||||||
240: 'fa a1 48 e9 90 46 18 1f ec 6b 20 85 f3 b2 0e d9',
|
|
||||||
256: 'f0 da f5 ba b3 d5 96 83 98 57 84 6f 73 fb fe 5a',
|
|
||||||
496: '1c 7e 2f c4 63 92 32 fe 29 75 84 b2 96 99 6b c8',
|
|
||||||
512: '3d b9 b2 49 40 6c c8 ed ff ac 55 cc d3 22 ba 12',
|
|
||||||
752: 'e4 f9 f7 e0 06 61 54 bb d1 25 b7 45 56 9b c8 97',
|
|
||||||
768: '75 d5 ef 26 2b 44 c4 1a 9c f6 3a e1 45 68 e1 b9',
|
|
||||||
1008:'6d a4 53 db f8 1e 82 33 4a 3d 88 66 cb 50 a1 e3',
|
|
||||||
1024:'78 28 d0 74 11 9c ab 5c 22 b2 94 d7 a9 bf a0 bb',
|
|
||||||
1520:'ad b8 9c ea 9a 15 fb e6 17 29 5b d0 4b 8c a0 5c',
|
|
||||||
1536:'62 51 d8 7f d4 aa ae 9a 7e 4a d5 c2 17 d3 f3 00',
|
|
||||||
2032:'e7 11 9b d6 dd 9b 22 af e8 f8 95 85 43 28 81 e2',
|
|
||||||
2048:'78 5b 60 fd 7e c4 e9 fc b6 54 5f 35 0d 66 0f ab',
|
|
||||||
3056:'af ec c0 37 fd b7 b0 83 8e b3 d7 0b cd 26 83 82',
|
|
||||||
3072:'db c1 a7 b4 9d 57 35 8c c9 fa 6d 61 d7 3b 7c f0',
|
|
||||||
4080:'63 49 d1 26 a3 7a fc ba 89 79 4f 98 04 91 4f dc',
|
|
||||||
4096:'bf 42 c3 01 8c 2f 7c 66 bf de 52 49 75 76 81 15'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'1910833222772a',
|
|
||||||
{
|
|
||||||
0: 'bc 92 22 db d3 27 4d 8f c6 6d 14 cc bd a6 69 0b',
|
|
||||||
16: '7a e6 27 41 0c 9a 2b e6 93 df 5b b7 48 5a 63 e3',
|
|
||||||
240: '3f 09 31 aa 03 de fb 30 0f 06 01 03 82 6f 2a 64',
|
|
||||||
256: 'be aa 9e c8 d5 9b b6 81 29 f3 02 7c 96 36 11 81',
|
|
||||||
496: '74 e0 4d b4 6d 28 64 8d 7d ee 8a 00 64 b0 6c fe',
|
|
||||||
512: '9b 5e 81 c6 2f e0 23 c5 5b e4 2f 87 bb f9 32 b8',
|
|
||||||
752: 'ce 17 8f c1 82 6e fe cb c1 82 f5 79 99 a4 61 40',
|
|
||||||
768: '8b df 55 cd 55 06 1c 06 db a6 be 11 de 4a 57 8a',
|
|
||||||
1008:'62 6f 5f 4d ce 65 25 01 f3 08 7d 39 c9 2c c3 49',
|
|
||||||
1024:'42 da ac 6a 8f 9a b9 a7 fd 13 7c 60 37 82 56 82',
|
|
||||||
1520:'cc 03 fd b7 91 92 a2 07 31 2f 53 f5 d4 dc 33 d9',
|
|
||||||
1536:'f7 0f 14 12 2a 1c 98 a3 15 5d 28 b8 a0 a8 a4 1d',
|
|
||||||
2032:'2a 3a 30 7a b2 70 8a 9c 00 fe 0b 42 f9 c2 d6 a1',
|
|
||||||
2048:'86 26 17 62 7d 22 61 ea b0 b1 24 65 97 ca 0a e9',
|
|
||||||
3056:'55 f8 77 ce 4f 2e 1d db bf 8e 13 e2 cd e0 fd c8',
|
|
||||||
3072:'1b 15 56 cb 93 5f 17 33 37 70 5f bb 5d 50 1f c1',
|
|
||||||
4080:'ec d0 e9 66 02 be 7f 8d 50 92 81 6c cc f2 c2 e9',
|
|
||||||
4096:'02 78 81 fa b4 99 3a 1c 26 20 24 a9 4f ff 3f 61'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 8
|
|
||||||
(
|
|
||||||
'641910833222772a',
|
|
||||||
{
|
|
||||||
0: 'bb f6 09 de 94 13 17 2d 07 66 0c b6 80 71 69 26',
|
|
||||||
16: '46 10 1a 6d ab 43 11 5d 6c 52 2b 4f e9 36 04 a9',
|
|
||||||
240: 'cb e1 ff f2 1c 96 f3 ee f6 1e 8f e0 54 2c bd f0',
|
|
||||||
256: '34 79 38 bf fa 40 09 c5 12 cf b4 03 4b 0d d1 a7',
|
|
||||||
496: '78 67 a7 86 d0 0a 71 47 90 4d 76 dd f1 e5 20 e3',
|
|
||||||
512: '8d 3e 9e 1c ae fc cc b3 fb f8 d1 8f 64 12 0b 32',
|
|
||||||
752: '94 23 37 f8 fd 76 f0 fa e8 c5 2d 79 54 81 06 72',
|
|
||||||
768: 'b8 54 8c 10 f5 16 67 f6 e6 0e 18 2f a1 9b 30 f7',
|
|
||||||
1008:'02 11 c7 c6 19 0c 9e fd 12 37 c3 4c 8f 2e 06 c4',
|
|
||||||
1024:'bd a6 4f 65 27 6d 2a ac b8 f9 02 12 20 3a 80 8e',
|
|
||||||
1520:'bd 38 20 f7 32 ff b5 3e c1 93 e7 9d 33 e2 7c 73',
|
|
||||||
1536:'d0 16 86 16 86 19 07 d4 82 e3 6c da c8 cf 57 49',
|
|
||||||
2032:'97 b0 f0 f2 24 b2 d2 31 71 14 80 8f b0 3a f7 a0',
|
|
||||||
2048:'e5 96 16 e4 69 78 79 39 a0 63 ce ea 9a f9 56 d1',
|
|
||||||
3056:'c4 7e 0d c1 66 09 19 c1 11 01 20 8f 9e 69 aa 1f',
|
|
||||||
3072:'5a e4 f1 28 96 b8 37 9a 2a ad 89 b5 b5 53 d6 b0',
|
|
||||||
4080:'6b 6b 09 8d 0c 29 3b c2 99 3d 80 bf 05 18 b6 d9',
|
|
||||||
4096:'81 70 cc 3c cd 92 a6 98 62 1b 93 9d d3 8f e7 b9'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'8b37641910833222772a',
|
|
||||||
{
|
|
||||||
0: 'ab 65 c2 6e dd b2 87 60 0d b2 fd a1 0d 1e 60 5c',
|
|
||||||
16: 'bb 75 90 10 c2 96 58 f2 c7 2d 93 a2 d1 6d 29 30',
|
|
||||||
240: 'b9 01 e8 03 6e d1 c3 83 cd 3c 4c 4d d0 a6 ab 05',
|
|
||||||
256: '3d 25 ce 49 22 92 4c 55 f0 64 94 33 53 d7 8a 6c',
|
|
||||||
496: '12 c1 aa 44 bb f8 7e 75 e6 11 f6 9b 2c 38 f4 9b',
|
|
||||||
512: '28 f2 b3 43 4b 65 c0 98 77 47 00 44 c6 ea 17 0d',
|
|
||||||
752: 'bd 9e f8 22 de 52 88 19 61 34 cf 8a f7 83 93 04',
|
|
||||||
768: '67 55 9c 23 f0 52 15 84 70 a2 96 f7 25 73 5a 32',
|
|
||||||
1008:'8b ab 26 fb c2 c1 2b 0f 13 e2 ab 18 5e ab f2 41',
|
|
||||||
1024:'31 18 5a 6d 69 6f 0c fa 9b 42 80 8b 38 e1 32 a2',
|
|
||||||
1520:'56 4d 3d ae 18 3c 52 34 c8 af 1e 51 06 1c 44 b5',
|
|
||||||
1536:'3c 07 78 a7 b5 f7 2d 3c 23 a3 13 5c 7d 67 b9 f4',
|
|
||||||
2032:'f3 43 69 89 0f cf 16 fb 51 7d ca ae 44 63 b2 dd',
|
|
||||||
2048:'02 f3 1c 81 e8 20 07 31 b8 99 b0 28 e7 91 bf a7',
|
|
||||||
3056:'72 da 64 62 83 22 8c 14 30 08 53 70 17 95 61 6f',
|
|
||||||
3072:'4e 0a 8c 6f 79 34 a7 88 e2 26 5e 81 d6 d0 c8 f4',
|
|
||||||
4080:'43 8d d5 ea fe a0 11 1b 6f 36 b4 b9 38 da 2a 68',
|
|
||||||
4096:'5f 6b fc 73 81 58 74 d9 71 00 f0 86 97 93 57 d8'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 9
|
|
||||||
(
|
|
||||||
'ebb46227c6cc8b37641910833222772a',
|
|
||||||
{
|
|
||||||
0: '72 0c 94 b6 3e df 44 e1 31 d9 50 ca 21 1a 5a 30',
|
|
||||||
16: 'c3 66 fd ea cf 9c a8 04 36 be 7c 35 84 24 d2 0b',
|
|
||||||
240: 'b3 39 4a 40 aa bf 75 cb a4 22 82 ef 25 a0 05 9f',
|
|
||||||
256: '48 47 d8 1d a4 94 2d bc 24 9d ef c4 8c 92 2b 9f',
|
|
||||||
496: '08 12 8c 46 9f 27 53 42 ad da 20 2b 2b 58 da 95',
|
|
||||||
512: '97 0d ac ef 40 ad 98 72 3b ac 5d 69 55 b8 17 61',
|
|
||||||
752: '3c b8 99 93 b0 7b 0c ed 93 de 13 d2 a1 10 13 ac',
|
|
||||||
768: 'ef 2d 67 6f 15 45 c2 c1 3d c6 80 a0 2f 4a db fe',
|
|
||||||
1008:'b6 05 95 51 4f 24 bc 9f e5 22 a6 ca d7 39 36 44',
|
|
||||||
1024:'b5 15 a8 c5 01 17 54 f5 90 03 05 8b db 81 51 4e',
|
|
||||||
1520:'3c 70 04 7e 8c bc 03 8e 3b 98 20 db 60 1d a4 95',
|
|
||||||
1536:'11 75 da 6e e7 56 de 46 a5 3e 2b 07 56 60 b7 70',
|
|
||||||
2032:'00 a5 42 bb a0 21 11 cc 2c 65 b3 8e bd ba 58 7e',
|
|
||||||
2048:'58 65 fd bb 5b 48 06 41 04 e8 30 b3 80 f2 ae de',
|
|
||||||
3056:'34 b2 1a d2 ad 44 e9 99 db 2d 7f 08 63 f0 d9 b6',
|
|
||||||
3072:'84 a9 21 8f c3 6e 8a 5f 2c cf be ae 53 a2 7d 25',
|
|
||||||
4080:'a2 22 1a 11 b8 33 cc b4 98 a5 95 40 f0 54 5f 4a',
|
|
||||||
4096:'5b be b4 78 7d 59 e5 37 3f db ea 6c 6f 75 c2 9b'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
'c109163908ebe51debb46227c6cc8b37641910833222772a',
|
|
||||||
{
|
|
||||||
0: '54 b6 4e 6b 5a 20 b5 e2 ec 84 59 3d c7 98 9d a7',
|
|
||||||
16: 'c1 35 ee e2 37 a8 54 65 ff 97 dc 03 92 4f 45 ce',
|
|
||||||
240: 'cf cc 92 2f b4 a1 4a b4 5d 61 75 aa bb f2 d2 01',
|
|
||||||
256: '83 7b 87 e2 a4 46 ad 0e f7 98 ac d0 2b 94 12 4f',
|
|
||||||
496: '17 a6 db d6 64 92 6a 06 36 b3 f4 c3 7a 4f 46 94',
|
|
||||||
512: '4a 5f 9f 26 ae ee d4 d4 a2 5f 63 2d 30 52 33 d9',
|
|
||||||
752: '80 a3 d0 1e f0 0c 8e 9a 42 09 c1 7f 4e eb 35 8c',
|
|
||||||
768: 'd1 5e 7d 5f fa aa bc 02 07 bf 20 0a 11 77 93 a2',
|
|
||||||
1008:'34 96 82 bf 58 8e aa 52 d0 aa 15 60 34 6a ea fa',
|
|
||||||
1024:'f5 85 4c db 76 c8 89 e3 ad 63 35 4e 5f 72 75 e3',
|
|
||||||
1520:'53 2c 7c ec cb 39 df 32 36 31 84 05 a4 b1 27 9c',
|
|
||||||
1536:'ba ef e6 d9 ce b6 51 84 22 60 e0 d1 e0 5e 3b 90',
|
|
||||||
2032:'e8 2d 8c 6d b5 4e 3c 63 3f 58 1c 95 2b a0 42 07',
|
|
||||||
2048:'4b 16 e5 0a bd 38 1b d7 09 00 a9 cd 9a 62 cb 23',
|
|
||||||
3056:'36 82 ee 33 bd 14 8b d9 f5 86 56 cd 8f 30 d9 fb',
|
|
||||||
3072:'1e 5a 0b 84 75 04 5d 9b 20 b2 62 86 24 ed fd 9e',
|
|
||||||
4080:'63 ed d6 84 fb 82 62 82 fe 52 8f 9c 0e 92 37 bc',
|
|
||||||
4096:'e4 dd 2e 98 d6 96 0f ae 0b 43 54 54 56 74 33 91'
|
|
||||||
}
|
|
||||||
),
|
|
||||||
# Page 10
|
|
||||||
(
|
|
||||||
'1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a',
|
|
||||||
{
|
|
||||||
0: 'dd 5b cb 00 18 e9 22 d4 94 75 9d 7c 39 5d 02 d3',
|
|
||||||
16: 'c8 44 6f 8f 77 ab f7 37 68 53 53 eb 89 a1 c9 eb',
|
|
||||||
240: 'af 3e 30 f9 c0 95 04 59 38 15 15 75 c3 fb 90 98',
|
|
||||||
256: 'f8 cb 62 74 db 99 b8 0b 1d 20 12 a9 8e d4 8f 0e',
|
|
||||||
496: '25 c3 00 5a 1c b8 5d e0 76 25 98 39 ab 71 98 ab',
|
|
||||||
512: '9d cb c1 83 e8 cb 99 4b 72 7b 75 be 31 80 76 9c',
|
|
||||||
752: 'a1 d3 07 8d fa 91 69 50 3e d9 d4 49 1d ee 4e b2',
|
|
||||||
768: '85 14 a5 49 58 58 09 6f 59 6e 4b cd 66 b1 06 65',
|
|
||||||
1008:'5f 40 d5 9e c1 b0 3b 33 73 8e fa 60 b2 25 5d 31',
|
|
||||||
1024:'34 77 c7 f7 64 a4 1b ac ef f9 0b f1 4f 92 b7 cc',
|
|
||||||
1520:'ac 4e 95 36 8d 99 b9 eb 78 b8 da 8f 81 ff a7 95',
|
|
||||||
1536:'8c 3c 13 f8 c2 38 8b b7 3f 38 57 6e 65 b7 c4 46',
|
|
||||||
2032:'13 c4 b9 c1 df b6 65 79 ed dd 8a 28 0b 9f 73 16',
|
|
||||||
2048:'dd d2 78 20 55 01 26 69 8e fa ad c6 4b 64 f6 6e',
|
|
||||||
3056:'f0 8f 2e 66 d2 8e d1 43 f3 a2 37 cf 9d e7 35 59',
|
|
||||||
3072:'9e a3 6c 52 55 31 b8 80 ba 12 43 34 f5 7b 0b 70',
|
|
||||||
4080:'d5 a3 9e 3d fc c5 02 80 ba c4 a6 b5 aa 0d ca 7d',
|
|
||||||
4096:'37 0b 1c 1f e6 55 91 6d 97 fd 0d 47 ca 1d 72 b8'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_keystream(self):
|
|
||||||
for tv in self.rfc6229_data:
|
|
||||||
key = unhexlify(b((tv[0])))
|
|
||||||
cipher = ARC4.new(key)
|
|
||||||
count = 0
|
|
||||||
for offset in range(0,4096+1,16):
|
|
||||||
ct = cipher.encrypt(b('\x00')*16)
|
|
||||||
expected = tv[1].get(offset)
|
|
||||||
if expected:
|
|
||||||
expected = unhexlify(b(expected.replace(" ",'')))
|
|
||||||
self.assertEquals(ct, expected)
|
|
||||||
count += 1
|
|
||||||
self.assertEqual(count, len(tv[1]))
|
|
||||||
|
|
||||||
class Drop_Tests(unittest.TestCase):
|
|
||||||
key = b('\xAA')*16
|
|
||||||
data = b('\x00')*5000
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.cipher = ARC4.new(self.key)
|
|
||||||
|
|
||||||
def test_drop256_encrypt(self):
|
|
||||||
cipher_drop = ARC4.new(self.key, 256)
|
|
||||||
ct_drop = cipher_drop.encrypt(self.data[:16])
|
|
||||||
ct = self.cipher.encrypt(self.data)[256:256+16]
|
|
||||||
self.assertEquals(ct_drop, ct)
|
|
||||||
|
|
||||||
def test_drop256_decrypt(self):
|
|
||||||
cipher_drop = ARC4.new(self.key, 256)
|
|
||||||
pt_drop = cipher_drop.decrypt(self.data[:16])
|
|
||||||
pt = self.cipher.decrypt(self.data)[256:256+16]
|
|
||||||
self.assertEquals(pt_drop, pt)
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
|
from Crypto.Cipher import ARC4
|
||||||
from common import make_stream_tests
|
from common import make_stream_tests
|
||||||
tests = make_stream_tests(ARC4, "ARC4", test_data)
|
return make_stream_tests(ARC4, "ARC4", test_data)
|
||||||
tests += list_test_cases(RFC6229_Tests)
|
|
||||||
tests += list_test_cases(Drop_Tests)
|
|
||||||
return tests
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
|||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.Cipher import PKCS1_OAEP as PKCS
|
from Crypto.Cipher import PKCS1_OAEP as PKCS
|
||||||
from Crypto.Hash import MD2,MD5,SHA1,SHA256,RIPEMD160
|
from Crypto.Hash import MD2,MD5,SHA as SHA1,SHA256,RIPEMD
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
|
|
||||||
def rws(t):
|
def rws(t):
|
||||||
@@ -314,12 +314,11 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
|
|||||||
# Encrypt/Decrypt messages of length [0..128-2*20-2]
|
# Encrypt/Decrypt messages of length [0..128-2*20-2]
|
||||||
for pt_len in xrange(0,128-2*20-2):
|
for pt_len in xrange(0,128-2*20-2):
|
||||||
pt = self.rng(pt_len)
|
pt = self.rng(pt_len)
|
||||||
cipher = PKCS.new(self.key1024)
|
ct = PKCS.encrypt(pt, self.key1024)
|
||||||
ct = cipher.encrypt(pt)
|
pt2 = PKCS.decrypt(ct, self.key1024)
|
||||||
pt2 = cipher.decrypt(ct)
|
|
||||||
self.assertEqual(pt,pt2)
|
self.assertEqual(pt,pt2)
|
||||||
|
|
||||||
def testEncryptDecrypt2(self):
|
def testEncryptDecrypt1(self):
|
||||||
# Helper function to monitor what's requested from RNG
|
# Helper function to monitor what's requested from RNG
|
||||||
global asked
|
global asked
|
||||||
def localRng(N):
|
def localRng(N):
|
||||||
@@ -327,7 +326,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
|
|||||||
asked += N
|
asked += N
|
||||||
return self.rng(N)
|
return self.rng(N)
|
||||||
# Verify that OAEP is friendly to all hashes
|
# Verify that OAEP is friendly to all hashes
|
||||||
for hashmod in (MD2,MD5,SHA1,SHA256,RIPEMD160):
|
for hashmod in (MD2,MD5,SHA1,SHA256,RIPEMD):
|
||||||
# Verify that encrypt() asks for as many random bytes
|
# Verify that encrypt() asks for as many random bytes
|
||||||
# as the hash output size
|
# as the hash output size
|
||||||
asked = 0
|
asked = 0
|
||||||
@@ -338,7 +337,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
|
|||||||
self.assertEqual(cipher.decrypt(ct), pt)
|
self.assertEqual(cipher.decrypt(ct), pt)
|
||||||
self.failUnless(asked > hashmod.digest_size)
|
self.failUnless(asked > hashmod.digest_size)
|
||||||
|
|
||||||
def testEncryptDecrypt3(self):
|
def testEncryptDecrypt2(self):
|
||||||
# Verify that OAEP supports labels
|
# Verify that OAEP supports labels
|
||||||
pt = self.rng(35)
|
pt = self.rng(35)
|
||||||
xlabel = self.rng(22)
|
xlabel = self.rng(22)
|
||||||
@@ -346,7 +345,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
|
|||||||
ct = cipher.encrypt(pt)
|
ct = cipher.encrypt(pt)
|
||||||
self.assertEqual(cipher.decrypt(ct), pt)
|
self.assertEqual(cipher.decrypt(ct), pt)
|
||||||
|
|
||||||
def testEncryptDecrypt4(self):
|
def testEncryptDecrypt3(self):
|
||||||
# Verify that encrypt() uses the custom MGF
|
# Verify that encrypt() uses the custom MGF
|
||||||
global mgfcalls
|
global mgfcalls
|
||||||
# Helper function to monitor what's requested from MGF
|
# Helper function to monitor what's requested from MGF
|
||||||
|
|||||||
@@ -29,12 +29,11 @@ __revision__ = "$Id$"
|
|||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
tests = []
|
tests = []
|
||||||
from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_CMAC; tests += test_CMAC.get_tests(config=config)
|
|
||||||
from Crypto.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_RIPEMD160; tests += test_RIPEMD160.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_RIPEMD; tests += test_RIPEMD.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_SHA1; tests += test_SHA1.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_SHA; tests += test_SHA.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config)
|
||||||
try:
|
try:
|
||||||
from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config)
|
from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config)
|
||||||
|
|||||||
@@ -29,10 +29,7 @@ __revision__ = "$Id$"
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import binascii
|
import binascii
|
||||||
import Crypto.Hash
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
|
|
||||||
# For compatibility with Python 2.1 and Python 2.2
|
# For compatibility with Python 2.1 and Python 2.2
|
||||||
if sys.hexversion < 0x02030000:
|
if sys.hexversion < 0x02030000:
|
||||||
@@ -43,7 +40,6 @@ if sys.hexversion < 0x02030000:
|
|||||||
else:
|
else:
|
||||||
dict = dict
|
dict = dict
|
||||||
|
|
||||||
from Crypto.Util.strxor import strxor_c
|
|
||||||
|
|
||||||
class HashDigestSizeSelfTest(unittest.TestCase):
|
class HashDigestSizeSelfTest(unittest.TestCase):
|
||||||
|
|
||||||
@@ -98,28 +94,12 @@ class HashSelfTest(unittest.TestCase):
|
|||||||
self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest()
|
self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest()
|
||||||
self.assertEqual(self.expected, out4) # h = .new(data); h.digest()
|
self.assertEqual(self.expected, out4) # h = .new(data); h.digest()
|
||||||
|
|
||||||
# Verify that the .new() method produces a fresh hash object, except
|
# Verify that new() object method produces a fresh hash object
|
||||||
# for MD5 and SHA1, which are hashlib objects. (But test any .new()
|
|
||||||
# method that does exist.)
|
|
||||||
if self.hashmod.__name__ not in ('Crypto.Hash.MD5', 'Crypto.Hash.SHA1') or hasattr(h, 'new'):
|
|
||||||
h2 = h.new()
|
h2 = h.new()
|
||||||
h2.update(self.input)
|
h2.update(self.input)
|
||||||
out5 = binascii.b2a_hex(h2.digest())
|
out5 = binascii.b2a_hex(h2.digest())
|
||||||
self.assertEqual(self.expected, out5)
|
self.assertEqual(self.expected, out5)
|
||||||
|
|
||||||
# Verify that Crypto.Hash.new(h) produces a fresh hash object
|
|
||||||
h3 = Crypto.Hash.new(h)
|
|
||||||
h3.update(self.input)
|
|
||||||
out6 = binascii.b2a_hex(h3.digest())
|
|
||||||
self.assertEqual(self.expected, out6)
|
|
||||||
|
|
||||||
if hasattr(h, 'name'):
|
|
||||||
# Verify that Crypto.Hash.new(h.name) produces a fresh hash object
|
|
||||||
h4 = Crypto.Hash.new(h.name)
|
|
||||||
h4.update(self.input)
|
|
||||||
out7 = binascii.b2a_hex(h4.digest())
|
|
||||||
self.assertEqual(self.expected, out7)
|
|
||||||
|
|
||||||
class HashTestOID(unittest.TestCase):
|
class HashTestOID(unittest.TestCase):
|
||||||
def __init__(self, hashmod, oid):
|
def __init__(self, hashmod, oid):
|
||||||
unittest.TestCase.__init__(self)
|
unittest.TestCase.__init__(self)
|
||||||
@@ -127,76 +107,46 @@ class HashTestOID(unittest.TestCase):
|
|||||||
self.oid = oid
|
self.oid = oid
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
from Crypto.Signature import PKCS1_v1_5
|
|
||||||
h = self.hashmod.new()
|
h = self.hashmod.new()
|
||||||
self.assertEqual(PKCS1_v1_5._HASH_OIDS[h.name], self.oid)
|
if self.oid==None:
|
||||||
|
try:
|
||||||
class HashDocStringTest(unittest.TestCase):
|
raised = 0
|
||||||
def __init__(self, hashmod):
|
a = h.oid
|
||||||
unittest.TestCase.__init__(self)
|
except AttributeError:
|
||||||
self.hashmod = hashmod
|
raised = 1
|
||||||
|
self.assertEqual(raised,1)
|
||||||
def runTest(self):
|
else:
|
||||||
docstring = self.hashmod.__doc__
|
self.assertEqual(h.oid, self.oid)
|
||||||
self.assert_(hasattr(self.hashmod, '__doc__'))
|
|
||||||
self.assert_(isinstance(self.hashmod.__doc__, str))
|
|
||||||
|
|
||||||
class GenericHashConstructorTest(unittest.TestCase):
|
|
||||||
def __init__(self, hashmod):
|
|
||||||
unittest.TestCase.__init__(self)
|
|
||||||
self.hashmod = hashmod
|
|
||||||
|
|
||||||
def runTest(self):
|
|
||||||
obj1 = self.hashmod.new("foo")
|
|
||||||
obj2 = self.hashmod.new()
|
|
||||||
obj3 = Crypto.Hash.new(obj1.name, "foo")
|
|
||||||
obj4 = Crypto.Hash.new(obj1.name)
|
|
||||||
obj5 = Crypto.Hash.new(obj1, "foo")
|
|
||||||
obj6 = Crypto.Hash.new(obj1)
|
|
||||||
self.assert_(isinstance(self.hashmod, obj1))
|
|
||||||
self.assert_(isinstance(self.hashmod, obj2))
|
|
||||||
self.assert_(isinstance(self.hashmod, obj3))
|
|
||||||
self.assert_(isinstance(self.hashmod, obj4))
|
|
||||||
self.assert_(isinstance(self.hashmod, obj5))
|
|
||||||
self.assert_(isinstance(self.hashmod, obj6))
|
|
||||||
|
|
||||||
class MACSelfTest(unittest.TestCase):
|
class MACSelfTest(unittest.TestCase):
|
||||||
|
|
||||||
def __init__(self, module, description, result, input, key, params):
|
def __init__(self, hashmod, description, expected_dict, input, key, hashmods):
|
||||||
unittest.TestCase.__init__(self)
|
unittest.TestCase.__init__(self)
|
||||||
self.module = module
|
self.hashmod = hashmod
|
||||||
self.result = result
|
self.expected_dict = expected_dict
|
||||||
self.input = input
|
self.input = input
|
||||||
self.key = key
|
self.key = key
|
||||||
self.params = params
|
self.hashmods = hashmods
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
||||||
def shortDescription(self):
|
def shortDescription(self):
|
||||||
return self.description
|
return self.description
|
||||||
|
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
|
for hashname in self.expected_dict.keys():
|
||||||
|
hashmod = self.hashmods[hashname]
|
||||||
key = binascii.a2b_hex(b(self.key))
|
key = binascii.a2b_hex(b(self.key))
|
||||||
data = binascii.a2b_hex(b(self.input))
|
data = binascii.a2b_hex(b(self.input))
|
||||||
|
|
||||||
# Strip whitespace from the expected string (which should be in lowercase-hex)
|
# Strip whitespace from the expected string (which should be in lowercase-hex)
|
||||||
expected = b("".join(self.result.split()))
|
expected = b("".join(self.expected_dict[hashname].split()))
|
||||||
|
|
||||||
h = self.module.new(key, **self.params)
|
h = self.hashmod.new(key, digestmod=hashmod)
|
||||||
h.update(data)
|
h.update(data)
|
||||||
out1_bin = h.digest()
|
|
||||||
out1 = binascii.b2a_hex(h.digest())
|
out1 = binascii.b2a_hex(h.digest())
|
||||||
out2 = h.hexdigest()
|
out2 = h.hexdigest()
|
||||||
|
|
||||||
# Verify that correct MAC does not raise any exception
|
h = self.hashmod.new(key, data, hashmod)
|
||||||
h.hexverify(out1)
|
|
||||||
h.verify(out1_bin)
|
|
||||||
|
|
||||||
# Verify that incorrect MAC does raise ValueError exception
|
|
||||||
wrong_mac = strxor_c(out1_bin, 255)
|
|
||||||
self.assertRaises(ValueError, h.verify, wrong_mac)
|
|
||||||
self.assertRaises(ValueError, h.hexverify, "4556")
|
|
||||||
|
|
||||||
h = self.module.new(key, data, **self.params)
|
|
||||||
|
|
||||||
out3 = h.hexdigest()
|
out3 = h.hexdigest()
|
||||||
out4 = binascii.b2a_hex(h.digest())
|
out4 = binascii.b2a_hex(h.digest())
|
||||||
@@ -206,17 +156,7 @@ class MACSelfTest(unittest.TestCase):
|
|||||||
h.update(b("blah blah blah")) # Corrupt the original hash object
|
h.update(b("blah blah blah")) # Corrupt the original hash object
|
||||||
out5 = binascii.b2a_hex(h2.digest()) # The copied hash object should return the correct result
|
out5 = binascii.b2a_hex(h2.digest()) # The copied hash object should return the correct result
|
||||||
|
|
||||||
# PY3K: Check that hexdigest() returns str and digest() returns bytes
|
# PY3K: hexdigest() should return str(), and digest() bytes
|
||||||
if sys.version_info[0] > 2:
|
|
||||||
self.assertTrue(isinstance(h.digest(), type(b(""))))
|
|
||||||
self.assertTrue(isinstance(h.hexdigest(), type("")))
|
|
||||||
|
|
||||||
# PY3K: Check that .hexverify() accepts bytes or str
|
|
||||||
if sys.version_info[0] > 2:
|
|
||||||
h.hexverify(h.hexdigest())
|
|
||||||
h.hexverify(h.hexdigest().encode('ascii'))
|
|
||||||
|
|
||||||
# PY3K: hexdigest() should return str, and digest() should return bytes
|
|
||||||
self.assertEqual(expected, out1)
|
self.assertEqual(expected, out1)
|
||||||
if sys.version_info[0] == 2:
|
if sys.version_info[0] == 2:
|
||||||
self.assertEqual(expected, out2)
|
self.assertEqual(expected, out2)
|
||||||
@@ -238,22 +178,20 @@ def make_hash_tests(module, module_name, test_data, digest_size, oid=None):
|
|||||||
description = row[2].encode('latin-1')
|
description = row[2].encode('latin-1')
|
||||||
name = "%s #%d: %s" % (module_name, i+1, description)
|
name = "%s #%d: %s" % (module_name, i+1, description)
|
||||||
tests.append(HashSelfTest(module, name, expected, input))
|
tests.append(HashSelfTest(module, name, expected, input))
|
||||||
|
if oid is not None:
|
||||||
|
oid = b(oid)
|
||||||
name = "%s #%d: digest_size" % (module_name, i+1)
|
name = "%s #%d: digest_size" % (module_name, i+1)
|
||||||
tests.append(HashDigestSizeSelfTest(module, name, digest_size))
|
tests.append(HashDigestSizeSelfTest(module, name, digest_size))
|
||||||
if oid is not None:
|
|
||||||
tests.append(HashTestOID(module, oid))
|
tests.append(HashTestOID(module, oid))
|
||||||
tests.append(HashDocStringTest(module))
|
|
||||||
if getattr(module, 'name', None) is not None:
|
|
||||||
tests.append(GenericHashConstructorTest(module))
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
def make_mac_tests(module, module_name, test_data):
|
def make_mac_tests(module, module_name, test_data, hashmods):
|
||||||
tests = []
|
tests = []
|
||||||
for i in range(len(test_data)):
|
for i in range(len(test_data)):
|
||||||
row = test_data[i]
|
row = test_data[i]
|
||||||
(key, data, results, description, params) = row
|
(key, data, results, description) = row
|
||||||
name = "%s #%d: %s" % (module_name, i+1, description)
|
name = "%s #%d: %s" % (module_name, i+1, description)
|
||||||
tests.append(MACSelfTest(module, name, results, data, key, params))
|
tests.append(MACSelfTest(module, name, results, data, key, hashmods))
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
|
|||||||
@@ -29,17 +29,13 @@ __revision__ = "$Id$"
|
|||||||
from common import dict # For compatibility with Python 2.1 and 2.2
|
from common import dict # For compatibility with Python 2.1 and 2.2
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
from Crypto.Hash import MD5, SHA1, SHA224, SHA256, SHA384, SHA512, HMAC
|
|
||||||
|
|
||||||
default_hash = None
|
|
||||||
|
|
||||||
# This is a list of (key, data, results, description) tuples.
|
# This is a list of (key, data, results, description) tuples.
|
||||||
test_data = [
|
test_data = [
|
||||||
## Test vectors from RFC 2202 ##
|
## Test vectors from RFC 2202 ##
|
||||||
# Test that the default hashmod is MD5
|
# Test that the default hashmod is MD5
|
||||||
('0b' * 16,
|
('0b' * 16,
|
||||||
'4869205468657265',
|
'4869205468657265',
|
||||||
dict(default_hash='9294727a3638bb1c13f48ef8158bfc9d'),
|
dict(default='9294727a3638bb1c13f48ef8158bfc9d'),
|
||||||
'default-is-MD5'),
|
'default-is-MD5'),
|
||||||
|
|
||||||
# Test case 1 (MD5)
|
# Test case 1 (MD5)
|
||||||
@@ -179,7 +175,9 @@ test_data = [
|
|||||||
bfdc63644f0713938a7f51535c3a35e2
|
bfdc63644f0713938a7f51535c3a35e2
|
||||||
'''),
|
'''),
|
||||||
'RFC 4231 #7 (HMAC-SHA256)'),
|
'RFC 4231 #7 (HMAC-SHA256)'),
|
||||||
|
]
|
||||||
|
|
||||||
|
hashlib_test_data = [
|
||||||
# Test case 8 (SHA224)
|
# Test case 8 (SHA224)
|
||||||
('4a656665',
|
('4a656665',
|
||||||
'7768617420646f2079612077616e74'
|
'7768617420646f2079612077616e74'
|
||||||
@@ -205,25 +203,17 @@ test_data = [
|
|||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
global test_data
|
global test_data
|
||||||
|
from Crypto.Hash import HMAC, MD5, SHA as SHA1, SHA256
|
||||||
from common import make_mac_tests
|
from common import make_mac_tests
|
||||||
|
hashmods = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256, default=None)
|
||||||
# A test vector contains multiple results, each one for a
|
|
||||||
# different hash algorithm.
|
|
||||||
# Here we expand each test vector into multiple ones,
|
|
||||||
# and add the relevant parameters that will be passed to new()
|
|
||||||
exp_test_data = []
|
|
||||||
for row in test_data:
|
|
||||||
for modname in row[2].keys():
|
|
||||||
t = list(row)
|
|
||||||
t[2] = row[2][modname]
|
|
||||||
try:
|
try:
|
||||||
t.append(dict(digestmod=globals()[modname]))
|
from Crypto.Hash import SHA224, SHA384, SHA512
|
||||||
exp_test_data.append(t)
|
hashmods.update(dict(SHA224=SHA224, SHA384=SHA384, SHA512=SHA512))
|
||||||
except AttributeError:
|
test_data += hashlib_test_data
|
||||||
|
except ImportError:
|
||||||
import sys
|
import sys
|
||||||
sys.stderr.write("SelfTest: warning: not testing HMAC-%s (not available)\n" % modname)
|
sys.stderr.write("SelfTest: warning: not testing HMAC-SHA224/384/512 (not available)\n")
|
||||||
|
return make_mac_tests(HMAC, "HMAC", test_data, hashmods)
|
||||||
return make_mac_tests(HMAC, "HMAC", exp_test_data)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(MD2, "MD2", test_data,
|
return make_hash_tests(MD2, "MD2", test_data,
|
||||||
digest_size=16,
|
digest_size=16,
|
||||||
oid="1.2.840.113549.2.2")
|
oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(MD4, "MD4", test_data,
|
return make_hash_tests(MD4, "MD4", test_data,
|
||||||
digest_size=16,
|
digest_size=16,
|
||||||
oid="1.2.840.113549.2.4")
|
oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(MD5, "MD5", test_data,
|
return make_hash_tests(MD5, "MD5", test_data,
|
||||||
digest_size=16,
|
digest_size=16,
|
||||||
oid="1.2.840.113549.2.5")
|
oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# SelfTest/Hash/test_RIPEMD.py: Self-test for the RIPEMD-160 hash function
|
||||||
|
#
|
||||||
|
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
#"""Self-test suite for Crypto.Hash.RIPEMD"""
|
||||||
|
|
||||||
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
|
# This is a list of (expected_result, input[, description]) tuples.
|
||||||
|
test_data = [
|
||||||
|
# Test vectors downloaded 2008-09-12 from
|
||||||
|
# http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||||
|
('9c1185a5c5e9fc54612808977ee8f548b2258d31', '', "'' (empty string)"),
|
||||||
|
('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', 'a'),
|
||||||
|
('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc', 'abc'),
|
||||||
|
('5d0689ef49d2fae572b881b123a85ffa21595f36', 'message digest'),
|
||||||
|
|
||||||
|
('f71c27109c692c1b56bbdceb5b9d2865b3708dbc',
|
||||||
|
'abcdefghijklmnopqrstuvwxyz',
|
||||||
|
'a-z'),
|
||||||
|
|
||||||
|
('12a053384a9c0c88e405a06c27dcf49ada62eb2b',
|
||||||
|
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
|
||||||
|
'abcdbcd...pnopq'),
|
||||||
|
|
||||||
|
('b0e20b6e3116640286ed3a87a5713079b21f5189',
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
|
||||||
|
'A-Z, a-z, 0-9'),
|
||||||
|
|
||||||
|
('9b752e45573d4b39f4dbd3323cab82bf63326bfb',
|
||||||
|
'1234567890' * 8,
|
||||||
|
"'1234567890' * 8"),
|
||||||
|
|
||||||
|
('52783243c1697bdbe16d37f97f68f08325dc1528',
|
||||||
|
'a' * 10**6,
|
||||||
|
'"a" * 10**6'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_tests(config={}):
|
||||||
|
from Crypto.Hash import RIPEMD
|
||||||
|
from common import make_hash_tests
|
||||||
|
return make_hash_tests(RIPEMD, "RIPEMD", test_data,
|
||||||
|
digest_size=20,
|
||||||
|
oid="\x06\x05\x2b\x24\x03\02\x01")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import unittest
|
||||||
|
suite = lambda: unittest.TestSuite(get_tests())
|
||||||
|
unittest.main(defaultTest='suite')
|
||||||
|
|
||||||
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# SelfTest/Hash/SHA.py: Self-test for the SHA-1 hash function
|
||||||
|
#
|
||||||
|
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
"""Self-test suite for Crypto.Hash.SHA"""
|
||||||
|
|
||||||
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
|
# Test vectors from various sources
|
||||||
|
# This is a list of (expected_result, input[, description]) tuples.
|
||||||
|
test_data = [
|
||||||
|
# FIPS PUB 180-2, A.1 - "One-Block Message"
|
||||||
|
('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'),
|
||||||
|
|
||||||
|
# FIPS PUB 180-2, A.2 - "Multi-Block Message"
|
||||||
|
('84983e441c3bd26ebaae4aa1f95129e5e54670f1',
|
||||||
|
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'),
|
||||||
|
|
||||||
|
# FIPS PUB 180-2, A.3 - "Long Message"
|
||||||
|
# ('34aa973cd4c4daa4f61eeb2bdbad27316534016f',
|
||||||
|
# 'a' * 10**6,
|
||||||
|
# '"a" * 10**6'),
|
||||||
|
|
||||||
|
# RFC 3174: Section 7.3, "TEST4" (multiple of 512 bits)
|
||||||
|
('dea356a2cddd90c7a7ecedc5ebb563934f460452',
|
||||||
|
'01234567' * 80,
|
||||||
|
'"01234567" * 80'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_tests(config={}):
|
||||||
|
from Crypto.Hash import SHA
|
||||||
|
from common import make_hash_tests
|
||||||
|
return make_hash_tests(SHA, "SHA", test_data,
|
||||||
|
digest_size=20,
|
||||||
|
oid="\x06\x05\x2B\x0E\x03\x02\x1A")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import unittest
|
||||||
|
suite = lambda: unittest.TestSuite(get_tests())
|
||||||
|
unittest.main(defaultTest='suite')
|
||||||
|
|
||||||
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
@@ -55,7 +55,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(SHA224, "SHA224", test_data,
|
return make_hash_tests(SHA224, "SHA224", test_data,
|
||||||
digest_size=28,
|
digest_size=28,
|
||||||
oid='2.16.840.1.101.3.4.2.4')
|
oid='\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
tests = make_hash_tests(SHA256, "SHA256", test_data,
|
tests = make_hash_tests(SHA256, "SHA256", test_data,
|
||||||
digest_size=32,
|
digest_size=32,
|
||||||
oid="2.16.840.1.101.3.4.2.1")
|
oid="\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01")
|
||||||
|
|
||||||
if config.get('slow_tests'):
|
if config.get('slow_tests'):
|
||||||
tests += [LargeSHA256Test()]
|
tests += [LargeSHA256Test()]
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(SHA384, "SHA384", test_data,
|
return make_hash_tests(SHA384, "SHA384", test_data,
|
||||||
digest_size=48,
|
digest_size=48,
|
||||||
oid='2.16.840.1.101.3.4.2.2')
|
oid='\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02')
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ def get_tests(config={}):
|
|||||||
from common import make_hash_tests
|
from common import make_hash_tests
|
||||||
return make_hash_tests(SHA512, "SHA512", test_data,
|
return make_hash_tests(SHA512, "SHA512", test_data,
|
||||||
digest_size=64,
|
digest_size=64,
|
||||||
oid="2.16.840.1.101.3.4.2.3")
|
oid="\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import unittest
|
import unittest
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ def get_tests(config={}):
|
|||||||
from Crypto.SelfTest.Protocol import test_chaffing; tests += test_chaffing.get_tests(config=config)
|
from Crypto.SelfTest.Protocol import test_chaffing; tests += test_chaffing.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config)
|
from Crypto.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Protocol import test_AllOrNothing; tests += test_AllOrNothing.get_tests(config=config)
|
from Crypto.SelfTest.Protocol import test_AllOrNothing; tests += test_AllOrNothing.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Protocol import test_KDF; tests += test_KDF.get_tests(config=config)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -25,13 +25,10 @@ __revision__ = "$Id$"
|
|||||||
import unittest
|
import unittest
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
|
||||||
|
|
||||||
from Crypto.SelfTest.st_common import list_test_cases
|
from Crypto.SelfTest.st_common import list_test_cases
|
||||||
from Crypto.Hash import SHA1, HMAC
|
from Crypto.Hash import SHA as SHA1,HMAC
|
||||||
from Crypto.Cipher import AES, DES3
|
|
||||||
|
|
||||||
from Crypto.Protocol.KDF import PBKDF1, PBKDF2, _S2V
|
from Crypto.Protocol.KDF import *
|
||||||
|
|
||||||
def t2b(t): return unhexlify(b(t))
|
def t2b(t): return unhexlify(b(t))
|
||||||
|
|
||||||
@@ -88,67 +85,10 @@ class PBKDF2_Tests(unittest.TestCase):
|
|||||||
self.assertEqual(res, t2b(v[4]))
|
self.assertEqual(res, t2b(v[4]))
|
||||||
self.assertEqual(res, res2)
|
self.assertEqual(res, res2)
|
||||||
|
|
||||||
class S2V_Tests(unittest.TestCase):
|
|
||||||
|
|
||||||
# Sequence of test vectors.
|
|
||||||
# Each test vector is made up by:
|
|
||||||
# Item #0: a tuple of strings
|
|
||||||
# Item #1: an AES key
|
|
||||||
# Item #2: the result
|
|
||||||
# Item #3: the cipher module S2V is based on
|
|
||||||
# Everything is hex encoded
|
|
||||||
_testData = [
|
|
||||||
|
|
||||||
# RFC5297, A.1
|
|
||||||
(
|
|
||||||
( '101112131415161718191a1b1c1d1e1f2021222324252627',
|
|
||||||
'112233445566778899aabbccddee' ),
|
|
||||||
'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0',
|
|
||||||
'85632d07c6e8f37f950acd320a2ecc93',
|
|
||||||
AES
|
|
||||||
),
|
|
||||||
|
|
||||||
# RFC5297, A.2
|
|
||||||
(
|
|
||||||
( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddcc'+
|
|
||||||
'bbaa99887766554433221100',
|
|
||||||
'102030405060708090a0',
|
|
||||||
'09f911029d74e35bd84156c5635688c0',
|
|
||||||
'7468697320697320736f6d6520706c61'+
|
|
||||||
'696e7465787420746f20656e63727970'+
|
|
||||||
'74207573696e67205349562d414553'),
|
|
||||||
'7f7e7d7c7b7a79787776757473727170',
|
|
||||||
'7bdb6e3b432667eb06f4d14bff2fbd0f',
|
|
||||||
AES
|
|
||||||
),
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
def test1(self):
|
|
||||||
"""Verify correctness of test vector"""
|
|
||||||
for tv in self._testData:
|
|
||||||
s2v = _S2V.new(t2b(tv[1]), tv[3])
|
|
||||||
for s in tv[0]:
|
|
||||||
s2v.update(t2b(s))
|
|
||||||
result = s2v.derive()
|
|
||||||
self.assertEqual(result, t2b(tv[2]))
|
|
||||||
|
|
||||||
def test2(self):
|
|
||||||
"""Verify that no more than 127(AES) and 63(TDES)
|
|
||||||
components are accepted."""
|
|
||||||
key = bchr(0)*16
|
|
||||||
for module in (AES, DES3):
|
|
||||||
s2v = _S2V.new(key, module)
|
|
||||||
max_comps = module.block_size*8-1
|
|
||||||
for i in xrange(max_comps):
|
|
||||||
s2v.update(b("XX"))
|
|
||||||
self.assertRaises(TypeError, s2v.update, b("YY"))
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
tests = []
|
tests = []
|
||||||
tests += list_test_cases(PBKDF1_Tests)
|
tests += list_test_cases(PBKDF1_Tests)
|
||||||
tests += list_test_cases(PBKDF2_Tests)
|
tests += list_test_cases(PBKDF2_Tests)
|
||||||
tests += list_test_cases(S2V_Tests)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -32,13 +32,7 @@ def get_tests(config={}):
|
|||||||
tests = []
|
tests = []
|
||||||
from Crypto.SelfTest.PublicKey import test_DSA; tests += test_DSA.get_tests(config=config)
|
from Crypto.SelfTest.PublicKey import test_DSA; tests += test_DSA.get_tests(config=config)
|
||||||
from Crypto.SelfTest.PublicKey import test_RSA; tests += test_RSA.get_tests(config=config)
|
from Crypto.SelfTest.PublicKey import test_RSA; tests += test_RSA.get_tests(config=config)
|
||||||
|
from Crypto.SelfTest.PublicKey import test_importKey; tests += test_importKey.get_tests(config=config)
|
||||||
from Crypto.SelfTest.PublicKey import test_import_DSA
|
|
||||||
tests +=test_import_DSA.get_tests(config=config)
|
|
||||||
|
|
||||||
from Crypto.SelfTest.PublicKey import test_import_RSA
|
|
||||||
tests += test_import_RSA.get_tests(config=config)
|
|
||||||
|
|
||||||
from Crypto.SelfTest.PublicKey import test_ElGamal; tests += test_ElGamal.get_tests(config=config)
|
from Crypto.SelfTest.PublicKey import test_ElGamal; tests += test_ElGamal.get_tests(config=config)
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import unittest
|
|||||||
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
from Crypto.PublicKey import ElGamal
|
from Crypto.PublicKey import ElGamal
|
||||||
from Crypto.Util.number import bytes_to_long
|
from Crypto.Util.number import *
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
class ElGamalTest(unittest.TestCase):
|
class ElGamalTest(unittest.TestCase):
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ __revision__ = "$Id$"
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import pickle
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
@@ -88,21 +87,6 @@ class RSATest(unittest.TestCase):
|
|||||||
ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03
|
ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The same key, in pickled format (from pycrypto 2.3)
|
|
||||||
# to ensure backward compatibility
|
|
||||||
pickled_key_2_3 = \
|
|
||||||
"(iCrypto.PublicKey.RSA\n_RSAobj\np0\n(dp2\nS'e'\np3\nL17L\nsS'd'\np4"\
|
|
||||||
"\nL11646763154293086160147889314553506764606353688284149120983587488"\
|
|
||||||
"79382229568306696406525871631480713149376749558222371890533687587223"\
|
|
||||||
"51580531956820574156366843733156436163097164007967904900300775223658"\
|
|
||||||
"03543233292399245064743971969473468304536714979010219881003396235861"\
|
|
||||||
"8370829441895425705728523874962107052993L\nsS'n'\np5\nL1319966490819"\
|
|
||||||
"88309815009412231606409998872008467220356704480658206329986017741425"\
|
|
||||||
"59273959878490114749026269828326520214759381792655199845793621772998"\
|
|
||||||
"40439054838068985140623386496543388290455526885872858516219460533763"\
|
|
||||||
"92312680578795692682905599590422046720587710762927130740460442438533"\
|
|
||||||
"124053848898103790124491L\nsb."
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
global RSA, Random, bytes_to_long
|
global RSA, Random, bytes_to_long
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
@@ -194,31 +178,6 @@ class RSATest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1])
|
self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1])
|
||||||
|
|
||||||
def test_serialization(self):
|
|
||||||
"""RSA (default implementation) serialize/unserialize key"""
|
|
||||||
rsaObj_orig = self.rsa.generate(1024)
|
|
||||||
rsaObj = pickle.loads(pickle.dumps(rsaObj_orig))
|
|
||||||
self._check_private_key(rsaObj)
|
|
||||||
self._exercise_primitive(rsaObj)
|
|
||||||
pub = rsaObj.publickey()
|
|
||||||
self._check_public_key(pub)
|
|
||||||
self._exercise_public_primitive(rsaObj)
|
|
||||||
|
|
||||||
plaintext = a2b_hex(self.plaintext)
|
|
||||||
ciphertext1 = rsaObj_orig.encrypt(plaintext, b(""))
|
|
||||||
ciphertext2 = rsaObj.encrypt(plaintext, b(""))
|
|
||||||
self.assertEqual(ciphertext1, ciphertext2)
|
|
||||||
|
|
||||||
if not (3, 0) <= sys.version_info < (3, 1, 2, 'final', 0):
|
|
||||||
# Unpickling is broken in Python 3 before 3.1.2 due to http://bugs.python.org/issue6137
|
|
||||||
def test_serialization_compat(self):
|
|
||||||
"""RSA (default implementation) backward compatibility serialization"""
|
|
||||||
rsaObj = pickle.loads(b(self.pickled_key_2_3))
|
|
||||||
plaintext = a2b_hex(self.plaintext)
|
|
||||||
ciphertext = a2b_hex(self.ciphertext)
|
|
||||||
ciphertext_result = rsaObj.encrypt(plaintext, b(""))[0]
|
|
||||||
self.assertEqual(ciphertext_result, ciphertext)
|
|
||||||
|
|
||||||
def _check_private_key(self, rsaObj):
|
def _check_private_key(self, rsaObj):
|
||||||
# Check capabilities
|
# Check capabilities
|
||||||
self.assertEqual(1, rsaObj.has_private())
|
self.assertEqual(1, rsaObj.has_private())
|
||||||
@@ -393,20 +352,6 @@ class RSAFastMathTest(RSATest):
|
|||||||
def test_factoring(self):
|
def test_factoring(self):
|
||||||
RSATest.test_factoring(self)
|
RSATest.test_factoring(self)
|
||||||
|
|
||||||
|
|
||||||
def test_serialization(self):
|
|
||||||
"""RSA (_fastmath implementation) serialize/unserialize key
|
|
||||||
"""
|
|
||||||
RSATest.test_serialization(self)
|
|
||||||
|
|
||||||
if not (3, 0) <= sys.version_info < (3, 1, 2, 'final', 0):
|
|
||||||
# Unpickling is broken in Python 3 before 3.1.2 due to http://bugs.python.org/issue6137
|
|
||||||
def test_serialization_compat(self):
|
|
||||||
"""RSA (_fastmath implementation) backward compatibility serialization
|
|
||||||
"""
|
|
||||||
RSATest.test_serialization_compat(self)
|
|
||||||
|
|
||||||
|
|
||||||
class RSASlowMathTest(RSATest):
|
class RSASlowMathTest(RSATest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
RSATest.setUp(self)
|
RSATest.setUp(self)
|
||||||
@@ -443,17 +388,6 @@ class RSASlowMathTest(RSATest):
|
|||||||
def test_factoring(self):
|
def test_factoring(self):
|
||||||
RSATest.test_factoring(self)
|
RSATest.test_factoring(self)
|
||||||
|
|
||||||
def test_serialization(self):
|
|
||||||
"""RSA (_slowmath implementation) serialize/unserialize key"""
|
|
||||||
RSATest.test_serialization(self)
|
|
||||||
|
|
||||||
if not (3, 0) <= sys.version_info < (3, 1, 2, 'final', 0):
|
|
||||||
# Unpickling is broken in Python 3 before 3.1.2 due to http://bugs.python.org/issue6137
|
|
||||||
def test_serialization_compat(self):
|
|
||||||
"""RSA (_slowmath implementation) backward compatibility serialization
|
|
||||||
"""
|
|
||||||
RSATest.test_serialization_compat(self)
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
tests = []
|
tests = []
|
||||||
tests += list_test_cases(RSATest)
|
tests += list_test_cases(RSATest)
|
||||||
|
|||||||
@@ -0,0 +1,345 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys
|
||||||
|
#
|
||||||
|
# ===================================================================
|
||||||
|
# The contents of this file are dedicated to the public domain. To
|
||||||
|
# the extent that dedication to the public domain is not available,
|
||||||
|
# everyone is granted a worldwide, perpetual, royalty-free,
|
||||||
|
# non-exclusive license to exercise all rights associated with the
|
||||||
|
# contents of this file for any purpose whatsoever.
|
||||||
|
# No rights are reserved.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
from __future__ import nested_scopes
|
||||||
|
|
||||||
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.SelfTest.st_common import *
|
||||||
|
from Crypto.Util.py3compat import *
|
||||||
|
from Crypto.Util.number import inverse
|
||||||
|
from Crypto.Util import asn1
|
||||||
|
|
||||||
|
def der2pem(der, text='PUBLIC'):
|
||||||
|
import binascii
|
||||||
|
chunks = [ binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48) ]
|
||||||
|
pem = b('-----BEGIN %s KEY-----\n' % text)
|
||||||
|
pem += b('').join(chunks)
|
||||||
|
pem += b('-----END %s KEY-----' % text)
|
||||||
|
return pem
|
||||||
|
|
||||||
|
class ImportKeyTests(unittest.TestCase):
|
||||||
|
# 512-bit RSA key generated with openssl
|
||||||
|
rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII
|
||||||
|
q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8
|
||||||
|
Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI
|
||||||
|
OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr
|
||||||
|
+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK
|
||||||
|
JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9
|
||||||
|
n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ==
|
||||||
|
-----END RSA PRIVATE KEY-----'''
|
||||||
|
|
||||||
|
# As above, but this is actually an unencrypted PKCS#8 key
|
||||||
|
rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS
|
||||||
|
ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj
|
||||||
|
wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK
|
||||||
|
5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk
|
||||||
|
B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC
|
||||||
|
NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx
|
||||||
|
yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7
|
||||||
|
BX85JB8zqwHB
|
||||||
|
-----END PRIVATE KEY-----'''
|
||||||
|
|
||||||
|
# The same RSA private key as in rsaKeyPEM, but now encrypted
|
||||||
|
rsaKeyEncryptedPEM=(
|
||||||
|
|
||||||
|
# With DES and passphrase 'test'
|
||||||
|
('test', u'''-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: DES-CBC,AF8F9A40BD2FA2FC
|
||||||
|
|
||||||
|
Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA
|
||||||
|
u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs
|
||||||
|
C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP
|
||||||
|
BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy
|
||||||
|
9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY
|
||||||
|
IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp
|
||||||
|
dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s=
|
||||||
|
-----END RSA PRIVATE KEY-----''',
|
||||||
|
"\xAF\x8F\x9A\x40\xBD\x2F\xA2\xFC"),
|
||||||
|
|
||||||
|
# With Triple-DES and passphrase 'rocking'
|
||||||
|
('rocking', u'''-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: DES-EDE3-CBC,C05D6C07F7FC02F6
|
||||||
|
|
||||||
|
w4lwQrXaVoTTJ0GgwY566htTA2/t1YlimhxkxYt9AEeCcidS5M0Wq9ClPiPz9O7F
|
||||||
|
m6K5QpM1rxo1RUE/ZyI85gglRNPdNwkeTOqit+kum7nN73AToX17+irVmOA4Z9E+
|
||||||
|
4O07t91GxGMcjUSIFk0ucwEU4jgxRvYscbvOMvNbuZszGdVNzBTVddnShKCsy9i7
|
||||||
|
nJbPlXeEKYi/OkRgO4PtfqqWQu5GIEFVUf9ev1QV7AvC+kyWTR1wWYnHX265jU5c
|
||||||
|
sopxQQtP8XEHIJEdd5/p1oieRcWTCNyY8EkslxDSsrf0OtZp6mZH9N+KU47cgQtt
|
||||||
|
9qGORmlWnsIoFFKcDohbtOaWBTKhkj5h6OkLjFjfU/sBeV1c+7wDT3dAy5tawXjG
|
||||||
|
YSxC7qDQIT/RECvV3+oQKEcmpEujn45wAnkTi12BH30=
|
||||||
|
-----END RSA PRIVATE KEY-----''',
|
||||||
|
"\xC0\x5D\x6C\x07\xF7\xFC\x02\xF6"),
|
||||||
|
)
|
||||||
|
|
||||||
|
rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY-----
|
||||||
|
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T
|
||||||
|
Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----'''
|
||||||
|
|
||||||
|
# Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM'
|
||||||
|
rsaPublicKeyOpenSSH = '''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n'''
|
||||||
|
|
||||||
|
# The private key, in PKCS#1 format encoded with DER
|
||||||
|
rsaKeyDER = a2b_hex(
|
||||||
|
'''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe
|
||||||
|
913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312
|
||||||
|
2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6
|
||||||
|
7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c
|
||||||
|
54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f
|
||||||
|
2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23
|
||||||
|
022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2
|
||||||
|
a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca
|
||||||
|
240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b
|
||||||
|
c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07
|
||||||
|
e4defe43ed91a3ae27bb057f39241f33ab01c1
|
||||||
|
'''.replace(" ",""))
|
||||||
|
|
||||||
|
# The private key, in unencrypted PKCS#8 format encoded with DER
|
||||||
|
rsaKeyDER8 = a2b_hex(
|
||||||
|
'''30820155020100300d06092a864886f70d01010105000482013f3082013
|
||||||
|
b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932
|
||||||
|
ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78
|
||||||
|
492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2
|
||||||
|
301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb
|
||||||
|
f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da
|
||||||
|
61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c
|
||||||
|
a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0
|
||||||
|
23702210087be1c3029504bcf34ec713d877947447813288975ca240080a
|
||||||
|
f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf
|
||||||
|
433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4
|
||||||
|
3ed91a3ae27bb057f39241f33ab01c1
|
||||||
|
'''.replace(" ",""))
|
||||||
|
|
||||||
|
rsaPublicKeyDER = a2b_hex(
|
||||||
|
'''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a
|
||||||
|
a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c
|
||||||
|
b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502
|
||||||
|
03010001
|
||||||
|
'''.replace(" ",""))
|
||||||
|
|
||||||
|
n = long('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F 93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3 12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16)
|
||||||
|
e = 65537L
|
||||||
|
d = long('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7 01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18 F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16)
|
||||||
|
p = long('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26 24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16)
|
||||||
|
q = long('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38 06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16)
|
||||||
|
|
||||||
|
# This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1}
|
||||||
|
# mod q) instead!
|
||||||
|
qInv = long('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3 AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16)
|
||||||
|
pInv = inverse(p,q)
|
||||||
|
|
||||||
|
def testImportKey1(self):
|
||||||
|
"""Verify import of RSAPrivateKey DER SEQUENCE"""
|
||||||
|
key = self.rsa.importKey(self.rsaKeyDER)
|
||||||
|
self.failUnless(key.has_private())
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey2(self):
|
||||||
|
"""Verify import of SubjectPublicKeyInfo DER SEQUENCE"""
|
||||||
|
key = self.rsa.importKey(self.rsaPublicKeyDER)
|
||||||
|
self.failIf(key.has_private())
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
|
||||||
|
def testImportKey3unicode(self):
|
||||||
|
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode"""
|
||||||
|
key = RSA.importKey(self.rsaKeyPEM)
|
||||||
|
self.assertEqual(key.has_private(),True) # assert_
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey3bytes(self):
|
||||||
|
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte string"""
|
||||||
|
key = RSA.importKey(b(self.rsaKeyPEM))
|
||||||
|
self.assertEqual(key.has_private(),True) # assert_
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey4unicode(self):
|
||||||
|
"""Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode"""
|
||||||
|
key = RSA.importKey(self.rsaPublicKeyPEM)
|
||||||
|
self.assertEqual(key.has_private(),False) # failIf
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
|
||||||
|
def testImportKey4bytes(self):
|
||||||
|
"""Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM as byte string"""
|
||||||
|
key = RSA.importKey(b(self.rsaPublicKeyPEM))
|
||||||
|
self.assertEqual(key.has_private(),False) # failIf
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
|
||||||
|
def testImportKey5(self):
|
||||||
|
"""Verifies that the imported key is still a valid RSA pair"""
|
||||||
|
key = RSA.importKey(self.rsaKeyPEM)
|
||||||
|
idem = key.encrypt(key.decrypt(b("Test")),0)
|
||||||
|
self.assertEqual(idem[0],b("Test"))
|
||||||
|
|
||||||
|
def testImportKey6(self):
|
||||||
|
"""Verifies that the imported key is still a valid RSA pair"""
|
||||||
|
key = RSA.importKey(self.rsaKeyDER)
|
||||||
|
idem = key.encrypt(key.decrypt(b("Test")),0)
|
||||||
|
self.assertEqual(idem[0],b("Test"))
|
||||||
|
|
||||||
|
def testImportKey7(self):
|
||||||
|
"""Verify import of OpenSSH public key"""
|
||||||
|
key = self.rsa.importKey(self.rsaPublicKeyOpenSSH)
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
|
||||||
|
def testImportKey8(self):
|
||||||
|
"""Verify import of encrypted PrivateKeyInfo DER SEQUENCE"""
|
||||||
|
for t in self.rsaKeyEncryptedPEM:
|
||||||
|
key = self.rsa.importKey(t[1], t[0])
|
||||||
|
self.failUnless(key.has_private())
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey9(self):
|
||||||
|
"""Verify import of unencrypted PrivateKeyInfo DER SEQUENCE"""
|
||||||
|
key = self.rsa.importKey(self.rsaKeyDER8)
|
||||||
|
self.failUnless(key.has_private())
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey10(self):
|
||||||
|
"""Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded with PEM"""
|
||||||
|
key = self.rsa.importKey(self.rsaKeyPEM8)
|
||||||
|
self.failUnless(key.has_private())
|
||||||
|
self.assertEqual(key.n, self.n)
|
||||||
|
self.assertEqual(key.e, self.e)
|
||||||
|
self.assertEqual(key.d, self.d)
|
||||||
|
self.assertEqual(key.p, self.p)
|
||||||
|
self.assertEqual(key.q, self.q)
|
||||||
|
|
||||||
|
def testImportKey11(self):
|
||||||
|
"""Verify import of RSAPublicKey DER SEQUENCE"""
|
||||||
|
der = asn1.DerSequence([17, 3]).encode()
|
||||||
|
key = self.rsa.importKey(der)
|
||||||
|
self.assertEqual(key.n, 17)
|
||||||
|
self.assertEqual(key.e, 3)
|
||||||
|
|
||||||
|
def testImportKey12(self):
|
||||||
|
"""Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM"""
|
||||||
|
der = asn1.DerSequence([17, 3]).encode()
|
||||||
|
pem = der2pem(der)
|
||||||
|
key = self.rsa.importKey(pem)
|
||||||
|
self.assertEqual(key.n, 17)
|
||||||
|
self.assertEqual(key.e, 3)
|
||||||
|
|
||||||
|
###
|
||||||
|
def testExportKey1(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
|
||||||
|
derKey = key.exportKey("DER")
|
||||||
|
self.assertEqual(derKey, self.rsaKeyDER)
|
||||||
|
|
||||||
|
def testExportKey2(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e])
|
||||||
|
derKey = key.exportKey("DER")
|
||||||
|
self.assertEqual(derKey, self.rsaPublicKeyDER)
|
||||||
|
|
||||||
|
def testExportKey3(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
|
||||||
|
pemKey = key.exportKey("PEM")
|
||||||
|
self.assertEqual(pemKey, b(self.rsaKeyPEM))
|
||||||
|
|
||||||
|
def testExportKey4(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e])
|
||||||
|
pemKey = key.exportKey("PEM")
|
||||||
|
self.assertEqual(pemKey, b(self.rsaPublicKeyPEM))
|
||||||
|
|
||||||
|
def testExportKey5(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e])
|
||||||
|
openssh_1 = key.exportKey("OpenSSH").split()
|
||||||
|
openssh_2 = self.rsaPublicKeyOpenSSH.split()
|
||||||
|
self.assertEqual(openssh_1[0], openssh_2[0])
|
||||||
|
self.assertEqual(openssh_1[1], openssh_2[1])
|
||||||
|
|
||||||
|
def testExportKey4(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
|
||||||
|
# Tuple with index #1 is encrypted with 3DES
|
||||||
|
t = map(b,self.rsaKeyEncryptedPEM[1])
|
||||||
|
# Force the salt being used when exporting
|
||||||
|
key._randfunc = lambda N: (t[2]*divmod(N+len(t[2]),len(t[2]))[0])[:N]
|
||||||
|
pemKey = key.exportKey("PEM", t[0])
|
||||||
|
self.assertEqual(pemKey, t[1])
|
||||||
|
|
||||||
|
def testExportKey5(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
|
||||||
|
derKey = key.exportKey("DER", pkcs=8)
|
||||||
|
self.assertEqual(derKey, self.rsaKeyDER8)
|
||||||
|
|
||||||
|
def testExportKey6(self):
|
||||||
|
key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
|
||||||
|
pemKey = key.exportKey("PEM", pkcs=8)
|
||||||
|
self.assertEqual(pemKey, b(self.rsaKeyPEM8))
|
||||||
|
|
||||||
|
class ImportKeyTestsSlow(ImportKeyTests):
|
||||||
|
def setUp(self):
|
||||||
|
self.rsa = RSA.RSAImplementation(use_fast_math=0)
|
||||||
|
|
||||||
|
class ImportKeyTestsFast(ImportKeyTests):
|
||||||
|
def setUp(self):
|
||||||
|
self.rsa = RSA.RSAImplementation(use_fast_math=1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
|
def get_tests(config={}):
|
||||||
|
tests = []
|
||||||
|
try:
|
||||||
|
from Crypto.PublicKey import _fastmath
|
||||||
|
tests += list_test_cases(ImportKeyTestsFast)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
tests += list_test_cases(ImportKeyTestsSlow)
|
||||||
|
return tests
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
suite = lambda: unittest.TestSuite(get_tests())
|
||||||
|
unittest.main(defaultTest='suite')
|
||||||
|
|
||||||
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
@@ -32,7 +32,6 @@ def get_tests(config={}):
|
|||||||
from Crypto.SelfTest.Random import OSRNG; tests += OSRNG.get_tests(config=config)
|
from Crypto.SelfTest.Random import OSRNG; tests += OSRNG.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config)
|
from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Random import test_rpoolcompat; tests += test_rpoolcompat.get_tests(config=config)
|
from Crypto.SelfTest.Random import test_rpoolcompat; tests += test_rpoolcompat.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Random import test__UserFriendlyRNG; tests += test__UserFriendlyRNG.get_tests(config=config)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class SimpleTest(unittest.TestCase):
|
|||||||
self.assertEqual(b('1') in z, True)
|
self.assertEqual(b('1') in z, True)
|
||||||
self.assertRaises(TypeError, random.shuffle, b('12'))
|
self.assertRaises(TypeError, random.shuffle, b('12'))
|
||||||
self.assertRaises(TypeError, random.shuffle, 1)
|
self.assertRaises(TypeError, random.shuffle, 1)
|
||||||
self.assertRaises(TypeError, random.shuffle, "11")
|
self.assertRaises(TypeError, random.shuffle, "1")
|
||||||
self.assertRaises(TypeError, random.shuffle, (1,2))
|
self.assertRaises(TypeError, random.shuffle, (1,2))
|
||||||
# 2to3 wraps a list() around it, alas - but I want to shoot
|
# 2to3 wraps a list() around it, alas - but I want to shoot
|
||||||
# myself in the foot here! :D
|
# myself in the foot here! :D
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ import unittest
|
|||||||
|
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
||||||
from Crypto.Hash import MD2, SHA1, MD5, SHA224, SHA256, SHA384, SHA512,\
|
from Crypto.Hash import *
|
||||||
RIPEMD160
|
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
from Crypto.Signature import PKCS1_v1_5 as PKCS
|
from Crypto.Signature import PKCS1_v1_5 as PKCS
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
@@ -124,7 +123,7 @@ class PKCS1_15_Tests(unittest.TestCase):
|
|||||||
'''4a700a16432a291a3194646952687d5316458b8b86fb0a25aa30e0dcecdb
|
'''4a700a16432a291a3194646952687d5316458b8b86fb0a25aa30e0dcecdb
|
||||||
442676759ac63d56ec1499c3ae4c0013c2053cabd5b5804848994541ac16
|
442676759ac63d56ec1499c3ae4c0013c2053cabd5b5804848994541ac16
|
||||||
fa243a4d''',
|
fa243a4d''',
|
||||||
SHA1
|
SHA
|
||||||
),
|
),
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -147,7 +146,7 @@ class PKCS1_15_Tests(unittest.TestCase):
|
|||||||
A9D20970C54E6651070B0144D43844C899320DD8FA7819F7EBC6A7715287332E
|
A9D20970C54E6651070B0144D43844C899320DD8FA7819F7EBC6A7715287332E
|
||||||
C8675C136183B3F8A1F81EF969418267130A756FDBB2C71D9A667446E34E0EAD
|
C8675C136183B3F8A1F81EF969418267130A756FDBB2C71D9A667446E34E0EAD
|
||||||
9CF31BFB66F816F319D0B7E430A5F2891553986E003720261C7E9022C0D9F11F''',
|
9CF31BFB66F816F319D0B7E430A5F2891553986E003720261C7E9022C0D9F11F''',
|
||||||
SHA1
|
SHA
|
||||||
)
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
@@ -198,7 +197,7 @@ class PKCS1_15_Tests(unittest.TestCase):
|
|||||||
rng = Random.new().read
|
rng = Random.new().read
|
||||||
key = RSA.generate(1024, rng)
|
key = RSA.generate(1024, rng)
|
||||||
|
|
||||||
for hashmod in (MD2,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160):
|
for hashmod in (MD2,MD5,SHA,SHA224,SHA256,SHA384,SHA512,RIPEMD):
|
||||||
h = hashmod.new()
|
h = hashmod.new()
|
||||||
h.update(b('blah blah blah'))
|
h.update(b('blah blah blah'))
|
||||||
|
|
||||||
@@ -207,37 +206,10 @@ class PKCS1_15_Tests(unittest.TestCase):
|
|||||||
result = signer.verify(h, s)
|
result = signer.verify(h, s)
|
||||||
self.failUnless(result)
|
self.failUnless(result)
|
||||||
|
|
||||||
class PKCS1_15_NoParams(unittest.TestCase):
|
|
||||||
"""Verify that PKCS#1 v1.5 signatures pass even without NULL parameters in
|
|
||||||
the algorithm identifier (bug #1119552)."""
|
|
||||||
|
|
||||||
rsakey = """-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII
|
|
||||||
q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8
|
|
||||||
Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI
|
|
||||||
OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr
|
|
||||||
+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK
|
|
||||||
JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9
|
|
||||||
n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ==
|
|
||||||
-----END RSA PRIVATE KEY-----"""
|
|
||||||
|
|
||||||
msg = b("This is a test\x0a")
|
|
||||||
|
|
||||||
# PKCS1 v1.5 signature of the message computed using SHA-1.
|
|
||||||
# The digestAlgorithm SEQUENCE does NOT contain the NULL parameter.
|
|
||||||
signature = '''a287a13517f716e72fb14eea8e33a8db4a4643314607e7ca3e3e281893db7401
|
|
||||||
3dda8b855fd99f6fecedcb25fcb7a434f35cd0a101f8b19348e0bd7b6f152dfc'''
|
|
||||||
|
|
||||||
def testVerify(self):
|
|
||||||
verifier = PKCS.new(RSA.importKey(self.rsakey))
|
|
||||||
h = SHA1.new(self.msg)
|
|
||||||
result = verifier.verify(h, t2b(self.signature))
|
|
||||||
self.failUnless(result)
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
tests = []
|
tests = []
|
||||||
tests += list_test_cases(PKCS1_15_Tests)
|
tests += list_test_cases(PKCS1_15_Tests)
|
||||||
tests += list_test_cases(PKCS1_15_NoParams)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ import unittest
|
|||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
|
||||||
from Crypto.Hash import SHA1, MD2, RIPEMD160, SHA224, SHA384, SHA512,\
|
from Crypto.Hash import *
|
||||||
SHA256, MD5
|
|
||||||
from Crypto.Signature import PKCS1_PSS as PKCS
|
from Crypto.Signature import PKCS1_PSS as PKCS
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
@@ -137,7 +136,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
'''e3 b5 d5 d0 02 c1 bc e5 0c 2b 65 ef 88 a1 88 d8
|
'''e3 b5 d5 d0 02 c1 bc e5 0c 2b 65 ef 88 a1 88 d8
|
||||||
3b ce 7e 61''',
|
3b ce 7e 61''',
|
||||||
# Hash algorithm
|
# Hash algorithm
|
||||||
SHA1
|
SHA
|
||||||
),
|
),
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -193,7 +192,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
'''de e9 59 c7 e0 64 11 36 14 20 ff 80 18 5e d5 7f
|
'''de e9 59 c7 e0 64 11 36 14 20 ff 80 18 5e d5 7f
|
||||||
3e 67 76 af''',
|
3e 67 76 af''',
|
||||||
# Hash
|
# Hash
|
||||||
SHA1
|
SHA
|
||||||
),
|
),
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -239,7 +238,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
'''ef 28 69 fa 40 c3 46 cb 18 3d ab 3d 7b ff c9 8f
|
'''ef 28 69 fa 40 c3 46 cb 18 3d ab 3d 7b ff c9 8f
|
||||||
d5 6d f4 2d''',
|
d5 6d f4 2d''',
|
||||||
# Hash
|
# Hash
|
||||||
SHA1
|
SHA
|
||||||
),
|
),
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -286,7 +285,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
# Salt
|
# Salt
|
||||||
'''57 bf 16 0b cb 02 bb 1d c7 28 0c f0 45 85 30 b7
|
'''57 bf 16 0b cb 02 bb 1d c7 28 0c f0 45 85 30 b7
|
||||||
d2 83 2f f7''',
|
d2 83 2f f7''',
|
||||||
SHA1
|
SHA
|
||||||
),
|
),
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -340,7 +339,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
# Salt
|
# Salt
|
||||||
'''1d 65 49 1d 79 c8 64 b3 73 00 9b e6 f6 f2 46 7b
|
'''1d 65 49 1d 79 c8 64 b3 73 00 9b e6 f6 f2 46 7b
|
||||||
ac 4c 78 fa''',
|
ac 4c 78 fa''',
|
||||||
SHA1
|
SHA
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -381,7 +380,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
self.failUnless(result)
|
self.failUnless(result)
|
||||||
|
|
||||||
def testSignVerify(self):
|
def testSignVerify(self):
|
||||||
h = SHA1.new()
|
h = SHA.new()
|
||||||
h.update(b('blah blah blah'))
|
h.update(b('blah blah blah'))
|
||||||
|
|
||||||
rng = Random.new().read
|
rng = Random.new().read
|
||||||
@@ -395,7 +394,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
return bchr(0x00)*maskLen
|
return bchr(0x00)*maskLen
|
||||||
|
|
||||||
# Verify that PSS is friendly to all ciphers
|
# Verify that PSS is friendly to all ciphers
|
||||||
for hashmod in (MD2,MD5,SHA1,SHA224,SHA256,SHA384,RIPEMD160):
|
for hashmod in (MD2,MD5,SHA,SHA224,SHA256,SHA384,RIPEMD):
|
||||||
h = hashmod.new()
|
h = hashmod.new()
|
||||||
h.update(b('blah blah blah'))
|
h.update(b('blah blah blah'))
|
||||||
|
|
||||||
@@ -407,7 +406,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
|
|||||||
self.failUnless(signer.verify(h, s))
|
self.failUnless(signer.verify(h, s))
|
||||||
self.assertEqual(key.asked, h.digest_size)
|
self.assertEqual(key.asked, h.digest_size)
|
||||||
|
|
||||||
h = SHA1.new()
|
h = SHA.new()
|
||||||
h.update(b('blah blah blah'))
|
h.update(b('blah blah blah'))
|
||||||
|
|
||||||
# Verify that sign() uses a different salt length
|
# Verify that sign() uses a different salt length
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ def get_tests(config={}):
|
|||||||
from Crypto.SelfTest.Util import test_winrandom; tests += test_winrandom.get_tests(config=config)
|
from Crypto.SelfTest.Util import test_winrandom; tests += test_winrandom.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config)
|
from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config)
|
from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config)
|
||||||
from Crypto.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -39,24 +39,34 @@ class CounterTests(unittest.TestCase):
|
|||||||
from Crypto.Util import Counter
|
from Crypto.Util import Counter
|
||||||
|
|
||||||
def test_BE_shortcut(self):
|
def test_BE_shortcut(self):
|
||||||
"""Big endian"""
|
"""Big endian, shortcut enabled"""
|
||||||
c = Counter.new(128)
|
c = Counter.new(128)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
c = Counter.new(128, little_endian=False)
|
c = Counter.new(128, little_endian=False)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
|
c = Counter.new(128, disable_shortcut=False)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
|
c = Counter.new(128, little_endian=False, disable_shortcut=False)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
|
|
||||||
def test_LE_shortcut(self):
|
def test_LE_shortcut(self):
|
||||||
"""Little endian"""
|
"""Little endian, shortcut enabled"""
|
||||||
c = Counter.new(128, little_endian=True)
|
c = Counter.new(128, little_endian=True)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
|
c = Counter.new(128, little_endian=True, disable_shortcut=False)
|
||||||
|
self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
|
||||||
|
|
||||||
def test_BE_no_shortcut(self):
|
def test_BE_no_shortcut(self):
|
||||||
"""Big endian, with disable_shortcut"""
|
"""Big endian, shortcut disabled"""
|
||||||
# Just testing API backward-compatibility. disable_shortcut is now a no-op.
|
|
||||||
c = Counter.new(128, disable_shortcut=True)
|
c = Counter.new(128, disable_shortcut=True)
|
||||||
|
self.assertRaises(AttributeError, getattr, c, '__PCT_CTR_SHORTCUT__')
|
||||||
c = Counter.new(128, little_endian=False, disable_shortcut=True)
|
c = Counter.new(128, little_endian=False, disable_shortcut=True)
|
||||||
|
self.assertRaises(AttributeError, getattr, c, '__PCT_CTR_SHORTCUT__')
|
||||||
|
|
||||||
def test_LE_no_shortcut(self):
|
def test_LE_no_shortcut(self):
|
||||||
"""Little endian, shortcut disabled"""
|
"""Little endian, shortcut disabled"""
|
||||||
# Just testing API backward-compatibility. disable_shortcut is now a no-op.
|
|
||||||
c = Counter.new(128, little_endian=True, disable_shortcut=True)
|
c = Counter.new(128, little_endian=True, disable_shortcut=True)
|
||||||
|
self.assertRaises(AttributeError, getattr, c, '__PCT_CTR_SHORTCUT__')
|
||||||
|
|
||||||
def test_BE_defaults(self):
|
def test_BE_defaults(self):
|
||||||
"""128-bit, Big endian, defaults"""
|
"""128-bit, Big endian, defaults"""
|
||||||
|
|||||||
@@ -28,249 +28,53 @@ import unittest
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
from Crypto.Util.asn1 import DerObject, DerSetOf, newDerSetOf, DerInteger,\
|
from Crypto.Util.asn1 import DerSequence, DerObject
|
||||||
DerBitString, newDerBitString, newDerObjectId,\
|
|
||||||
DerObjectId, DerNull, DerOctetString,\
|
|
||||||
newDerOctetString, DerSequence, newDerSequence,\
|
|
||||||
newDerInteger
|
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
|
|
||||||
class DerObjectTests(unittest.TestCase):
|
class DerObjectTests(unittest.TestCase):
|
||||||
|
|
||||||
def testObjInit1(self):
|
|
||||||
# Fail with invalid tag format (must be 1 byte)
|
|
||||||
self.assertRaises(ValueError, DerObject, b('\x00\x99'))
|
|
||||||
# Fail with invalid implicit tag (must be <0x1F)
|
|
||||||
self.assertRaises(ValueError, DerObject, 0x1F)
|
|
||||||
|
|
||||||
# ------
|
|
||||||
|
|
||||||
def testObjEncode1(self):
|
def testObjEncode1(self):
|
||||||
# No payload
|
# No payload
|
||||||
der = DerObject(b('\x02'))
|
der = DerObject(b('\x33'))
|
||||||
self.assertEquals(der.encode(), b('\x02\x00'))
|
self.assertEquals(der.encode(), b('\x33\x00'))
|
||||||
# Small payload (primitive)
|
# Small payload
|
||||||
der.payload = b('\x45')
|
der.payload = b('\x45')
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x45'))
|
self.assertEquals(der.encode(), b('\x33\x01\x45'))
|
||||||
# Invariant
|
# Invariant
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x45'))
|
self.assertEquals(der.encode(), b('\x33\x01\x45'))
|
||||||
# Initialize with numerical tag
|
# Initialize with numerical tag
|
||||||
der = DerObject(0x04)
|
der = DerObject(b(0x33))
|
||||||
der.payload = b('\x45')
|
der.payload = b('\x45')
|
||||||
self.assertEquals(der.encode(), b('\x04\x01\x45'))
|
self.assertEquals(der.encode(), b('\x33\x01\x45'))
|
||||||
# Initialize with constructed type
|
|
||||||
der = DerObject(b('\x10'), constructed=True)
|
|
||||||
self.assertEquals(der.encode(), b('\x30\x00'))
|
|
||||||
|
|
||||||
def testObjEncode2(self):
|
def testObjEncode2(self):
|
||||||
# Initialize with payload
|
# Known types
|
||||||
der = DerObject(0x03, b('\x12\x12'))
|
der = DerObject('SEQUENCE')
|
||||||
self.assertEquals(der.encode(), b('\x03\x02\x12\x12'))
|
self.assertEquals(der.encode(), b('\x30\x00'))
|
||||||
|
der = DerObject('BIT STRING')
|
||||||
|
self.assertEquals(der.encode(), b('\x03\x00'))
|
||||||
|
|
||||||
def testObjEncode3(self):
|
def testObjEncode3(self):
|
||||||
# Long payload
|
# Long payload
|
||||||
der = DerObject(b('\x10'))
|
der = DerObject(b('\x34'))
|
||||||
der.payload = b("0")*128
|
der.payload = b("0")*128
|
||||||
self.assertEquals(der.encode(), b('\x10\x81\x80' + "0"*128))
|
self.assertEquals(der.encode(), b('\x34\x81\x80' + "0"*128))
|
||||||
|
|
||||||
def testObjEncode4(self):
|
|
||||||
# Implicit tags (constructed)
|
|
||||||
der = DerObject(0x10, implicit=1, constructed=True)
|
|
||||||
der.payload = b('ppll')
|
|
||||||
self.assertEquals(der.encode(), b('\xa1\x04ppll'))
|
|
||||||
# Implicit tags (primitive)
|
|
||||||
der = DerObject(0x02, implicit=0x1E, constructed=False)
|
|
||||||
der.payload = b('ppll')
|
|
||||||
self.assertEquals(der.encode(), b('\x9E\x04ppll'))
|
|
||||||
|
|
||||||
# -----
|
|
||||||
|
|
||||||
def testObjDecode1(self):
|
def testObjDecode1(self):
|
||||||
# Decode short payload
|
# Decode short payload
|
||||||
der = DerObject(0x02)
|
der = DerObject()
|
||||||
der.decode(b('\x02\x02\x01\x02'))
|
der.decode(b('\x20\x02\x01\x02'))
|
||||||
self.assertEquals(der.payload, b("\x01\x02"))
|
self.assertEquals(der.payload, b("\x01\x02"))
|
||||||
self.assertEquals(der._idOctet, 0x02)
|
self.assertEquals(der.typeTag, 0x20)
|
||||||
|
|
||||||
def testObjDecode2(self):
|
def testObjDecode2(self):
|
||||||
# Decode long payload
|
# Decode short payload
|
||||||
der = DerObject(0x02)
|
|
||||||
der.decode(b('\x02\x81\x80' + "1"*128))
|
|
||||||
self.assertEquals(der.payload, b("1")*128)
|
|
||||||
self.assertEquals(der._idOctet, 0x02)
|
|
||||||
|
|
||||||
def testObjDecode3(self):
|
|
||||||
# Decode payload with too much data gives error
|
|
||||||
der = DerObject(0x02)
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02\xFF'))
|
|
||||||
# Decode payload with too little data gives error
|
|
||||||
der = DerObject(0x02)
|
|
||||||
self.assertRaises(EOFError, der.decode, b('\x02\x02\x01'))
|
|
||||||
|
|
||||||
def testObjDecode4(self):
|
|
||||||
# Decode implicit tag (primitive)
|
|
||||||
der = DerObject(0x02, constructed=False, implicit=0xF)
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02'))
|
|
||||||
der.decode(b('\x8F\x01\x00'))
|
|
||||||
self.assertEquals(der.payload, b('\x00'))
|
|
||||||
# Decode implicit tag (constructed)
|
|
||||||
der = DerObject(0x02, constructed=True, implicit=0xF)
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02'))
|
|
||||||
der.decode(b('\xAF\x01\x00'))
|
|
||||||
self.assertEquals(der.payload, b('\x00'))
|
|
||||||
|
|
||||||
def testObjDecode5(self):
|
|
||||||
# Decode payload with unexpected tag gives error
|
|
||||||
der = DerObject(0x02)
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02'))
|
|
||||||
|
|
||||||
def testObjDecode6(self):
|
|
||||||
# Arbitrary DER object
|
|
||||||
der = DerObject()
|
der = DerObject()
|
||||||
der.decode(b('\x65\x01\x88'))
|
der.decode(b('\x22\x81\x80' + "1"*128))
|
||||||
self.assertEquals(der._idOctet, 0x65)
|
self.assertEquals(der.payload, b("1")*128)
|
||||||
self.assertEquals(der.payload, b('\x88'))
|
self.assertEquals(der.typeTag, 0x22)
|
||||||
|
|
||||||
class DerIntegerTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def testInit1(self):
|
|
||||||
der = newDerInteger(1)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x01'))
|
|
||||||
|
|
||||||
def testEncode1(self):
|
|
||||||
# Single-byte integers
|
|
||||||
# Value 0
|
|
||||||
der = DerInteger(0)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x00'))
|
|
||||||
# Value 1
|
|
||||||
der = DerInteger(1)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x01'))
|
|
||||||
# Value 127
|
|
||||||
der = DerInteger(127)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x7F'))
|
|
||||||
|
|
||||||
def testEncode2(self):
|
|
||||||
# Multi-byte integers
|
|
||||||
# Value 128
|
|
||||||
der = DerInteger(128)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x02\x00\x80'))
|
|
||||||
# Value 0x180
|
|
||||||
der = DerInteger(0x180L)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x02\x01\x80'))
|
|
||||||
# One very long integer
|
|
||||||
der = DerInteger(2L**2048)
|
|
||||||
self.assertEquals(der.encode(),
|
|
||||||
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
|
||||||
|
|
||||||
def testEncode3(self):
|
|
||||||
# Negative integers
|
|
||||||
# Value -1
|
|
||||||
der = DerInteger(-1)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\xFF'))
|
|
||||||
# Value -128
|
|
||||||
der = DerInteger(-128)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x01\x80'))
|
|
||||||
# Value
|
|
||||||
der = DerInteger(-87873)
|
|
||||||
self.assertEquals(der.encode(), b('\x02\x03\xFE\xA8\xBF'))
|
|
||||||
|
|
||||||
# -----
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Single-byte integer
|
|
||||||
der = DerInteger()
|
|
||||||
# Value 0
|
|
||||||
der.decode(b('\x02\x01\x00'))
|
|
||||||
self.assertEquals(der.value, 0)
|
|
||||||
# Value 1
|
|
||||||
der.decode(b('\x02\x01\x01'))
|
|
||||||
self.assertEquals(der.value, 1)
|
|
||||||
# Value 127
|
|
||||||
der.decode(b('\x02\x01\x7F'))
|
|
||||||
self.assertEquals(der.value, 127)
|
|
||||||
|
|
||||||
def testDecode2(self):
|
|
||||||
# Multi-byte integer
|
|
||||||
der = DerInteger()
|
|
||||||
# Value 0x180L
|
|
||||||
der.decode(b('\x02\x02\x01\x80'))
|
|
||||||
self.assertEquals(der.value,0x180L)
|
|
||||||
# One very long integer
|
|
||||||
der.decode(
|
|
||||||
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
|
||||||
self.assertEquals(der.value,2L**2048)
|
|
||||||
|
|
||||||
def testDecode3(self):
|
|
||||||
# Negative integer
|
|
||||||
der = DerInteger()
|
|
||||||
# Value -1
|
|
||||||
der.decode(b('\x02\x01\xFF'))
|
|
||||||
self.assertEquals(der.value, -1)
|
|
||||||
# Value -32768
|
|
||||||
der.decode(b('\x02\x02\x80\x00'))
|
|
||||||
self.assertEquals(der.value, -32768)
|
|
||||||
|
|
||||||
def testDecode5(self):
|
|
||||||
# We still accept BER integer format
|
|
||||||
der = DerInteger()
|
|
||||||
# Redundant leading zeroes
|
|
||||||
der.decode(b('\x02\x02\x00\x01'))
|
|
||||||
self.assertEquals(der.value, 1)
|
|
||||||
# Redundant leading 0xFF
|
|
||||||
der.decode(b('\x02\x02\xFF\xFF'))
|
|
||||||
self.assertEquals(der.value, -1)
|
|
||||||
# Empty payload
|
|
||||||
der.decode(b('\x02\x00'))
|
|
||||||
self.assertEquals(der.value, 0)
|
|
||||||
|
|
||||||
def testErrDecode1(self):
|
|
||||||
# Wide length field
|
|
||||||
der = DerInteger()
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x02\x81\x01\x01'))
|
|
||||||
|
|
||||||
class DerSequenceTests(unittest.TestCase):
|
class DerSequenceTests(unittest.TestCase):
|
||||||
|
|
||||||
def testInit1(self):
|
|
||||||
der = newDerSequence(1, DerInteger(2), '0\x00')
|
|
||||||
self.assertEquals(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00'))
|
|
||||||
|
|
||||||
def testEncode1(self):
|
def testEncode1(self):
|
||||||
# Empty sequence
|
# Empty sequence
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
@@ -279,17 +83,16 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
# One single-byte integer (zero)
|
# One single-byte integer (zero)
|
||||||
der.append(0)
|
der.append(0)
|
||||||
self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
|
self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
|
||||||
self.assertEquals(der.hasInts(),1)
|
|
||||||
self.assertEquals(der.hasInts(False),1)
|
|
||||||
self.failUnless(der.hasOnlyInts())
|
self.failUnless(der.hasOnlyInts())
|
||||||
self.failUnless(der.hasOnlyInts(False))
|
|
||||||
# Invariant
|
# Invariant
|
||||||
self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
|
self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
|
||||||
|
|
||||||
def testEncode2(self):
|
def testEncode2(self):
|
||||||
# Indexing
|
# One single-byte integer (non-zero)
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
der.append(0)
|
der.append(127)
|
||||||
|
self.assertEquals(der.encode(), b('0\x03\x02\x01\x7f'))
|
||||||
|
# Indexing
|
||||||
der[0] = 1
|
der[0] = 1
|
||||||
self.assertEquals(len(der),1)
|
self.assertEquals(len(der),1)
|
||||||
self.assertEquals(der[0],1)
|
self.assertEquals(der[0],1)
|
||||||
@@ -310,7 +113,7 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
def testEncode4(self):
|
def testEncode4(self):
|
||||||
# One very long integer
|
# One very long integer
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
der.append(2L**2048)
|
der.append(2**2048)
|
||||||
self.assertEquals(der.encode(), b('0\x82\x01\x05')+
|
self.assertEquals(der.encode(), b('0\x82\x01\x05')+
|
||||||
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
||||||
@@ -333,37 +136,27 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
||||||
|
|
||||||
def testEncode5(self):
|
def testEncode5(self):
|
||||||
|
# One single-byte integer (looks negative)
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
der += 1
|
der.append(0xFFL)
|
||||||
der += b('\x30\x00')
|
self.assertEquals(der.encode(), b('0\x04\x02\x02\x00\xff'))
|
||||||
self.assertEquals(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
|
|
||||||
|
|
||||||
def testEncode6(self):
|
def testEncode6(self):
|
||||||
# Two positive integers
|
# Two integers
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
der.append(0x180L)
|
der.append(0x180L)
|
||||||
der.append(0xFFL)
|
der.append(0xFFL)
|
||||||
self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
|
self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
|
||||||
self.failUnless(der.hasOnlyInts())
|
self.failUnless(der.hasOnlyInts())
|
||||||
self.failUnless(der.hasOnlyInts(False))
|
|
||||||
# Two mixed integers
|
|
||||||
der = DerSequence()
|
|
||||||
der.append(2)
|
|
||||||
der.append(-2)
|
|
||||||
self.assertEquals(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE'))
|
|
||||||
self.assertEquals(der.hasInts(), 1)
|
|
||||||
self.assertEquals(der.hasInts(False), 2)
|
|
||||||
self.failIf(der.hasOnlyInts())
|
|
||||||
self.failUnless(der.hasOnlyInts(False))
|
|
||||||
#
|
#
|
||||||
der.append(0x01)
|
der.append(0x01)
|
||||||
der[1:] = [9,8]
|
der[1:] = [9,8]
|
||||||
self.assertEquals(len(der),3)
|
self.assertEquals(len(der),3)
|
||||||
self.assertEqual(der[1:],[9,8])
|
self.assertEqual(der[1:],[9,8])
|
||||||
self.assertEqual(der[1:-1],[9])
|
self.assertEqual(der[1:-1],[9])
|
||||||
self.assertEquals(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
|
self.assertEquals(der.encode(), b('0\x0A\x02\x02\x01\x80\x02\x01\x09\x02\x01\x08'))
|
||||||
|
|
||||||
def testEncode7(self):
|
def testEncode6(self):
|
||||||
# One integer and another type (no matter what it is)
|
# One integer and another type (no matter what it is)
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
der.append(0x180L)
|
der.append(0x180L)
|
||||||
@@ -394,6 +187,13 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
self.assertEquals(len(der),1)
|
self.assertEquals(len(der),1)
|
||||||
self.assertEquals(der[0],127)
|
self.assertEquals(der[0],127)
|
||||||
|
|
||||||
|
def testDecode3(self):
|
||||||
|
# One multi-byte integer (non-zero)
|
||||||
|
der = DerSequence()
|
||||||
|
der.decode(b('0\x04\x02\x02\x01\x80'))
|
||||||
|
self.assertEquals(len(der),1)
|
||||||
|
self.assertEquals(der[0],0x180L)
|
||||||
|
|
||||||
def testDecode4(self):
|
def testDecode4(self):
|
||||||
# One very long integer
|
# One very long integer
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
@@ -418,7 +218,14 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+
|
||||||
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
b('\x00\x00\x00\x00\x00\x00\x00\x00\x00'))
|
||||||
self.assertEquals(len(der),1)
|
self.assertEquals(len(der),1)
|
||||||
self.assertEquals(der[0],2L**2048)
|
self.assertEquals(der[0],2**2048)
|
||||||
|
|
||||||
|
def testDecode5(self):
|
||||||
|
# One single-byte integer (looks negative)
|
||||||
|
der = DerSequence()
|
||||||
|
der.decode(b('0\x04\x02\x02\x00\xff'))
|
||||||
|
self.assertEquals(len(der),1)
|
||||||
|
self.assertEquals(der[0],0xFFL)
|
||||||
|
|
||||||
def testDecode6(self):
|
def testDecode6(self):
|
||||||
# Two integers
|
# Two integers
|
||||||
@@ -444,210 +251,39 @@ class DerSequenceTests(unittest.TestCase):
|
|||||||
self.assertEquals(len(der),2)
|
self.assertEquals(len(der),2)
|
||||||
self.assertEquals(der[0],b('\x24\x02\xb6\x63'))
|
self.assertEquals(der[0],b('\x24\x02\xb6\x63'))
|
||||||
self.assertEquals(der[1],b('\x12\x00'))
|
self.assertEquals(der[1],b('\x12\x00'))
|
||||||
self.assertEquals(der.hasInts(), 0)
|
|
||||||
self.assertEquals(der.hasInts(False), 0)
|
|
||||||
self.failIf(der.hasOnlyInts())
|
|
||||||
self.failIf(der.hasOnlyInts(False))
|
|
||||||
|
|
||||||
def testErrDecode1(self):
|
def testErrDecode1(self):
|
||||||
# Not a sequence
|
# Not a sequence
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
self.assertRaises(EOFError, der.decode, b(''))
|
self.assertRaises(ValueError, der.decode, b(''))
|
||||||
self.assertRaises(ValueError, der.decode, b('\x00'))
|
self.assertRaises(ValueError, der.decode, b('\x00'))
|
||||||
self.assertRaises(EOFError, der.decode, b('\x30'))
|
self.assertRaises(ValueError, der.decode, b('\x30'))
|
||||||
|
|
||||||
def testErrDecode2(self):
|
def testErrDecode2(self):
|
||||||
|
# Wrong payload type
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
# Too much data
|
self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'), True)
|
||||||
self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'))
|
|
||||||
|
|
||||||
def testErrDecode3(self):
|
def testErrDecode3(self):
|
||||||
# Wrong length format
|
# Wrong length format
|
||||||
der = DerSequence()
|
der = DerSequence()
|
||||||
# Missing length in sub-item
|
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00'))
|
||||||
self.assertRaises(EOFError, der.decode, b('\x30\x04\x02\x01\x01\x00'))
|
|
||||||
# Valid BER, but invalid DER length
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01'))
|
self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01'))
|
||||||
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01'))
|
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01'))
|
||||||
|
|
||||||
class DerOctetStringTests(unittest.TestCase):
|
def testErrDecode4(self):
|
||||||
|
# Wrong integer format
|
||||||
def testInit1(self):
|
der = DerSequence()
|
||||||
der = newDerOctetString(b('\xFF'))
|
# Multi-byte encoding for zero
|
||||||
self.assertEquals(der.encode(), b('\x04\x01\xFF'))
|
#self.assertRaises(ValueError, der.decode, '\x30\x04\x02\x02\x00\x00')
|
||||||
|
# Negative integer
|
||||||
def testEncode1(self):
|
self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\xFF'))
|
||||||
# Empty sequence
|
|
||||||
der = DerOctetString()
|
|
||||||
self.assertEquals(der.encode(), b('\x04\x00'))
|
|
||||||
# Small payload
|
|
||||||
der.payload = b('\x01\x02')
|
|
||||||
self.assertEquals(der.encode(), b('\x04\x02\x01\x02'))
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerOctetString()
|
|
||||||
der.decode(b('\x04\x00'))
|
|
||||||
self.assertEquals(der.payload, b(''))
|
|
||||||
# Small payload
|
|
||||||
der.decode(b('\x04\x02\x01\x02'))
|
|
||||||
self.assertEquals(der.payload, b('\x01\x02'))
|
|
||||||
|
|
||||||
def testErrDecode1(self):
|
|
||||||
# No leftovers allowed
|
|
||||||
der = DerOctetString()
|
|
||||||
self.assertRaises(ValueError, der.decode, b('\x04\x01\x01\xff'))
|
|
||||||
|
|
||||||
class DerNullTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def testEncode1(self):
|
|
||||||
der = DerNull()
|
|
||||||
self.assertEquals(der.encode(), b('\x05\x00'))
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerNull()
|
|
||||||
der.decode(b('\x05\x00'))
|
|
||||||
|
|
||||||
class DerObjectIdTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def testInit1(self):
|
|
||||||
der = newDerObjectId("1.1")
|
|
||||||
self.assertEquals(der.encode(), b('\x06\x01)'))
|
|
||||||
|
|
||||||
def testEncode1(self):
|
|
||||||
der = DerObjectId('1.2.840.113549.1.1.1')
|
|
||||||
self.assertEquals(der.encode(), b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))
|
|
||||||
#
|
|
||||||
der = DerObjectId()
|
|
||||||
der.value = '1.2.840.113549.1.1.1'
|
|
||||||
self.assertEquals(der.encode(), b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerObjectId()
|
|
||||||
der.decode(b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))
|
|
||||||
self.assertEquals(der.value, '1.2.840.113549.1.1.1')
|
|
||||||
|
|
||||||
class DerBitStringTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def testInit1(self):
|
|
||||||
der = newDerBitString(b("\xFF"))
|
|
||||||
self.assertEquals(der.encode(), b('\x03\x02\x00\xFF'))
|
|
||||||
|
|
||||||
def testEncode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerBitString()
|
|
||||||
self.assertEquals(der.encode(), b('\x03\x01\x00'))
|
|
||||||
# Small payload
|
|
||||||
der = DerBitString(b('\x01\x02'))
|
|
||||||
self.assertEquals(der.encode(), b('\x03\x03\x00\x01\x02'))
|
|
||||||
# Small payload
|
|
||||||
der = DerBitString()
|
|
||||||
der.value = b('\x01\x02')
|
|
||||||
self.assertEquals(der.encode(), b('\x03\x03\x00\x01\x02'))
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerBitString()
|
|
||||||
der.decode(b('\x03\x00'))
|
|
||||||
self.assertEquals(der.value, b(''))
|
|
||||||
# Small payload
|
|
||||||
der.decode(b('\x03\x03\x00\x01\x02'))
|
|
||||||
self.assertEquals(der.value, b('\x01\x02'))
|
|
||||||
|
|
||||||
class DerSetOfTests(unittest.TestCase):
|
|
||||||
|
|
||||||
def testInit1(self):
|
|
||||||
der = newDerSetOf(DerInteger(1), DerInteger(2))
|
|
||||||
self.assertEquals(der.encode(), b('1\x06\x02\x01\x01\x02\x01\x02'))
|
|
||||||
|
|
||||||
def testEncode1(self):
|
|
||||||
# Empty set
|
|
||||||
der = DerSetOf()
|
|
||||||
self.assertEquals(der.encode(), b('1\x00'))
|
|
||||||
# One single-byte integer (zero)
|
|
||||||
der.add(0)
|
|
||||||
self.assertEquals(der.encode(), b('1\x03\x02\x01\x00'))
|
|
||||||
# Invariant
|
|
||||||
self.assertEquals(der.encode(), b('1\x03\x02\x01\x00'))
|
|
||||||
|
|
||||||
def testEncode2(self):
|
|
||||||
# Two integers
|
|
||||||
der = DerSetOf()
|
|
||||||
der.add(0x180L)
|
|
||||||
der.add(0xFFL)
|
|
||||||
self.assertEquals(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80'))
|
|
||||||
# Initialize with integers
|
|
||||||
der = DerSetOf([0x180L, 0xFFL])
|
|
||||||
self.assertEquals(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80'))
|
|
||||||
|
|
||||||
def testEncode3(self):
|
|
||||||
# One integer and another type (no matter what it is)
|
|
||||||
der = DerSetOf()
|
|
||||||
der.add(0x180L)
|
|
||||||
self.assertRaises(ValueError, der.add, b('\x00\x02\x00\x00'))
|
|
||||||
|
|
||||||
def testEncode4(self):
|
|
||||||
# Only non integers
|
|
||||||
der = DerSetOf()
|
|
||||||
der.add(b('\x01\x00'))
|
|
||||||
der.add(b('\x01\x01\x01'))
|
|
||||||
self.assertEquals(der.encode(), b('1\x05\x01\x00\x01\x01\x01'))
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
def testDecode1(self):
|
|
||||||
# Empty sequence
|
|
||||||
der = DerSetOf()
|
|
||||||
der.decode(b('1\x00'))
|
|
||||||
self.assertEquals(len(der),0)
|
|
||||||
# One single-byte integer (zero)
|
|
||||||
der.decode(b('1\x03\x02\x01\x00'))
|
|
||||||
self.assertEquals(len(der),1)
|
|
||||||
self.assertEquals(list(der),[0])
|
|
||||||
|
|
||||||
def testDecode2(self):
|
|
||||||
# Two integers
|
|
||||||
der = DerSetOf()
|
|
||||||
der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
|
|
||||||
self.assertEquals(len(der),2)
|
|
||||||
l = list(der)
|
|
||||||
self.failUnless(0x180 in l)
|
|
||||||
self.failUnless(0xFF in l)
|
|
||||||
|
|
||||||
def testDecode3(self):
|
|
||||||
# One integer and 2 other types
|
|
||||||
der = DerSetOf()
|
|
||||||
#import pdb; pdb.set_trace()
|
|
||||||
self.assertRaises(ValueError, der.decode,
|
|
||||||
b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00'))
|
|
||||||
|
|
||||||
def testErrDecode1(self):
|
|
||||||
# No leftovers allowed
|
|
||||||
der = DerSetOf()
|
|
||||||
self.assertRaises(ValueError, der.decode,
|
|
||||||
b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff\xAA'))
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
from Crypto.SelfTest.st_common import list_test_cases
|
from Crypto.SelfTest.st_common import list_test_cases
|
||||||
listTests = []
|
listTests = []
|
||||||
listTests += list_test_cases(DerObjectTests)
|
listTests += list_test_cases(DerObjectTests)
|
||||||
listTests += list_test_cases(DerIntegerTests)
|
|
||||||
listTests += list_test_cases(DerSequenceTests)
|
listTests += list_test_cases(DerSequenceTests)
|
||||||
listTests += list_test_cases(DerOctetStringTests)
|
|
||||||
listTests += list_test_cases(DerNullTests)
|
|
||||||
listTests += list_test_cases(DerObjectIdTests)
|
|
||||||
listTests += list_test_cases(DerBitStringTests)
|
|
||||||
listTests += list_test_cases(DerSetOfTests)
|
|
||||||
return listTests
|
return listTests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class MyError(Exception):
|
|
||||||
"""Dummy exception used for tests"""
|
|
||||||
|
|
||||||
# NB: In some places, we compare tuples instead of just output values so that
|
# NB: In some places, we compare tuples instead of just output values so that
|
||||||
# if any inputs cause a test failure, we'll be able to tell which ones.
|
# if any inputs cause a test failure, we'll be able to tell which ones.
|
||||||
|
|
||||||
@@ -279,11 +276,6 @@ class MiscTests(unittest.TestCase):
|
|||||||
self.assertEqual(number.size(0xa2ba40),8*3)
|
self.assertEqual(number.size(0xa2ba40),8*3)
|
||||||
self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5L), 1024)
|
self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5L), 1024)
|
||||||
|
|
||||||
class FastmathTests(unittest.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
global number
|
|
||||||
from Crypto.Util import number
|
|
||||||
|
|
||||||
def test_negative_number_roundtrip_mpzToLongObj_longObjToMPZ(self):
|
def test_negative_number_roundtrip_mpzToLongObj_longObjToMPZ(self):
|
||||||
"""Test that mpzToLongObj and longObjToMPZ (internal functions) roundtrip negative numbers correctly."""
|
"""Test that mpzToLongObj and longObjToMPZ (internal functions) roundtrip negative numbers correctly."""
|
||||||
n = -100000000000000000000000000000000000L
|
n = -100000000000000000000000000000000000L
|
||||||
@@ -292,49 +284,9 @@ class FastmathTests(unittest.TestCase):
|
|||||||
self.assertEqual(n, k.n)
|
self.assertEqual(n, k.n)
|
||||||
self.assertEqual(e, k.e)
|
self.assertEqual(e, k.e)
|
||||||
|
|
||||||
def test_isPrime_randfunc_exception(self):
|
|
||||||
"""Test that when isPrime is called, an exception raised in randfunc is propagated."""
|
|
||||||
def randfunc(n):
|
|
||||||
raise MyError
|
|
||||||
prime = 3536384141L # Needs to be large enough so that rabinMillerTest will be invoked
|
|
||||||
self.assertRaises(MyError, number._fastmath.isPrime, prime, randfunc=randfunc)
|
|
||||||
|
|
||||||
def test_getStrongPrime_randfunc_exception(self):
|
|
||||||
"""Test that when getStrongPrime is called, an exception raised in randfunc is propagated."""
|
|
||||||
def randfunc(n):
|
|
||||||
raise MyError
|
|
||||||
self.assertRaises(MyError, number._fastmath.getStrongPrime, 512, randfunc=randfunc)
|
|
||||||
|
|
||||||
def test_isPrime_randfunc_bogus(self):
|
|
||||||
"""Test that when isPrime is called, an exception is raised if randfunc returns something bogus."""
|
|
||||||
def randfunc(n):
|
|
||||||
return None
|
|
||||||
prime = 3536384141L # Needs to be large enough so that rabinMillerTest will be invoked
|
|
||||||
self.assertRaises(TypeError, number._fastmath.isPrime, prime, randfunc=randfunc)
|
|
||||||
|
|
||||||
def test_getStrongPrime_randfunc_bogus(self):
|
|
||||||
"""Test that when getStrongPrime is called, an exception is raised if randfunc returns something bogus."""
|
|
||||||
def randfunc(n):
|
|
||||||
return None
|
|
||||||
self.assertRaises(TypeError, number._fastmath.getStrongPrime, 512, randfunc=randfunc)
|
|
||||||
|
|
||||||
def get_tests(config={}):
|
def get_tests(config={}):
|
||||||
from Crypto.SelfTest.st_common import list_test_cases
|
from Crypto.SelfTest.st_common import list_test_cases
|
||||||
tests = list_test_cases(MiscTests)
|
return list_test_cases(MiscTests)
|
||||||
try:
|
|
||||||
from Crypto.PublicKey import _fastmath
|
|
||||||
tests += list_test_cases(FastmathTests)
|
|
||||||
except ImportError:
|
|
||||||
from distutils.sysconfig import get_config_var
|
|
||||||
import inspect, os.path
|
|
||||||
_fm_path = os.path.normpath(os.path.dirname(os.path.abspath(
|
|
||||||
inspect.getfile(inspect.currentframe())))
|
|
||||||
+"/../../PublicKey/_fastmath"+get_config_var("SO"))
|
|
||||||
if os.path.exists(_fm_path):
|
|
||||||
raise ImportError("While the _fastmath module exists, importing "+
|
|
||||||
"it failed. This may point to the gmp or mpir shared library "+
|
|
||||||
"not being in the path. _fastmath was found at "+_fm_path)
|
|
||||||
return tests
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
suite = lambda: unittest.TestSuite(get_tests())
|
suite = lambda: unittest.TestSuite(get_tests())
|
||||||
|
|||||||
@@ -66,13 +66,11 @@ def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs
|
|||||||
raise ValueError("'module' and 'tests' arguments are mutually exclusive")
|
raise ValueError("'module' and 'tests' arguments are mutually exclusive")
|
||||||
if stream is None:
|
if stream is None:
|
||||||
kwargs['stream'] = StringIO()
|
kwargs['stream'] = StringIO()
|
||||||
else:
|
|
||||||
kwargs['stream'] = stream
|
|
||||||
runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs)
|
runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs)
|
||||||
result = runner.run(suite)
|
result = runner.run(suite)
|
||||||
if not result.wasSuccessful():
|
if not result.wasSuccessful():
|
||||||
if stream is None:
|
if stream is None:
|
||||||
sys.stderr.write(kwargs['stream'].getvalue())
|
sys.stderr.write(stream.getvalue())
|
||||||
raise SelfTestError("Self-test failed", result)
|
raise SelfTestError("Self-test failed", result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -85,7 +83,6 @@ def get_tests(config={}):
|
|||||||
from Crypto.SelfTest import Random; tests += Random.get_tests(config=config)
|
from Crypto.SelfTest import Random; tests += Random.get_tests(config=config)
|
||||||
from Crypto.SelfTest import Util; tests += Util.get_tests(config=config)
|
from Crypto.SelfTest import Util; tests += Util.get_tests(config=config)
|
||||||
from Crypto.SelfTest import Signature; tests += Signature.get_tests(config=config)
|
from Crypto.SelfTest import Signature; tests += Signature.get_tests(config=config)
|
||||||
from Crypto.SelfTest import IO; tests += IO.get_tests(config=config)
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -30,22 +30,22 @@ For example, a sender may authenticate a message using SHA-1 and PSS like
|
|||||||
this:
|
this:
|
||||||
|
|
||||||
>>> from Crypto.Signature import PKCS1_PSS
|
>>> from Crypto.Signature import PKCS1_PSS
|
||||||
>>> from Crypto.Hash import SHA1
|
>>> from Crypto.Hash import SHA
|
||||||
>>> from Crypto.PublicKey import RSA1
|
>>> from Crypto.PublicKey import RSA
|
||||||
>>> from Crypto import Random
|
>>> from Crypto import Random
|
||||||
>>>
|
>>>
|
||||||
>>> message = 'To be signed'
|
>>> message = 'To be signed'
|
||||||
>>> key = RSA.importKey(open('privkey.der').read())
|
>>> key = RSA.importKey(open('privkey.der').read())
|
||||||
>>> h = SHA1.new()
|
>>> h = SHA.new()
|
||||||
>>> h.update(message)
|
>>> h.update(message)
|
||||||
>>> signer = PKCS1_PSS.new(key)
|
>>> signer = PKCS1_PSS.new(key)
|
||||||
>>> signature = signer.sign(key)
|
>>> signature = PKCS1_PSS.sign(key)
|
||||||
|
|
||||||
At the receiver side, verification can be done like using the public part of
|
At the receiver side, verification can be done like using the public part of
|
||||||
the RSA key:
|
the RSA key:
|
||||||
|
|
||||||
>>> key = RSA.importKey(open('pubkey.der').read())
|
>>> key = RSA.importKey(open('pubkey.der').read())
|
||||||
>>> h = SHA1.new()
|
>>> h = SHA.new()
|
||||||
>>> h.update(message)
|
>>> h.update(message)
|
||||||
>>> verifier = PKCS1_PSS.new(key)
|
>>> verifier = PKCS1_PSS.new(key)
|
||||||
>>> if verifier.verify(h, signature):
|
>>> if verifier.verify(h, signature):
|
||||||
@@ -72,7 +72,6 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|||||||
import Crypto.Util.number
|
import Crypto.Util.number
|
||||||
from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes
|
from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes
|
||||||
from Crypto.Util.strxor import strxor
|
from Crypto.Util.strxor import strxor
|
||||||
from Crypto.Hash import new as Hash_new
|
|
||||||
|
|
||||||
class PSS_SigScheme:
|
class PSS_SigScheme:
|
||||||
"""This signature scheme can perform PKCS#1 PSS RSA signature or verification."""
|
"""This signature scheme can perform PKCS#1 PSS RSA signature or verification."""
|
||||||
@@ -204,11 +203,7 @@ def MGF1(mgfSeed, maskLen, hash):
|
|||||||
T = b("")
|
T = b("")
|
||||||
for counter in xrange(ceil_div(maskLen, hash.digest_size)):
|
for counter in xrange(ceil_div(maskLen, hash.digest_size)):
|
||||||
c = long_to_bytes(counter, 4)
|
c = long_to_bytes(counter, 4)
|
||||||
try:
|
|
||||||
T = T + hash.new(mgfSeed + c).digest()
|
T = T + hash.new(mgfSeed + c).digest()
|
||||||
except AttributeError:
|
|
||||||
# hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it
|
|
||||||
T = T + Hash_new(hash, mgfSeed + c).digest()
|
|
||||||
assert(len(T)>=maskLen)
|
assert(len(T)>=maskLen)
|
||||||
return T[:maskLen]
|
return T[:maskLen]
|
||||||
|
|
||||||
@@ -258,11 +253,7 @@ def EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen):
|
|||||||
if randFunc and sLen>0:
|
if randFunc and sLen>0:
|
||||||
salt = randFunc(sLen)
|
salt = randFunc(sLen)
|
||||||
# Step 5 and 6
|
# Step 5 and 6
|
||||||
try:
|
|
||||||
h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt)
|
h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt)
|
||||||
except AttributeError:
|
|
||||||
# hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it
|
|
||||||
h = Hash_new(mhash, bchr(0x00)*8 + mhash.digest() + salt)
|
|
||||||
# Step 7 and 8
|
# Step 7 and 8
|
||||||
db = bchr(0x00)*(emLen-sLen-mhash.digest_size-2) + bchr(0x01) + salt
|
db = bchr(0x00)*(emLen-sLen-mhash.digest_size-2) + bchr(0x01) + salt
|
||||||
# Step 9
|
# Step 9
|
||||||
@@ -337,11 +328,7 @@ def EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen):
|
|||||||
salt = b("")
|
salt = b("")
|
||||||
if sLen: salt = db[-sLen:]
|
if sLen: salt = db[-sLen:]
|
||||||
# Step 12 and 13
|
# Step 12 and 13
|
||||||
try:
|
|
||||||
hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest()
|
hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest()
|
||||||
except AttributeError:
|
|
||||||
# hash object doesn't have a "new" method. Use Crypto.Hash.new() to instantiate it
|
|
||||||
hp = Hash_new(mhash, bchr(0x00)*8 + mhash.digest() + salt).digest()
|
|
||||||
# Step 14
|
# Step 14
|
||||||
if h!=hp:
|
if h!=hp:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -60,13 +60,9 @@ the RSA key:
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
__all__ = [ 'new', 'PKCS115_SigScheme' ]
|
__all__ = [ 'new', 'PKCS115_SigScheme' ]
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import Crypto.Util.number
|
import Crypto.Util.number
|
||||||
from Crypto.Util.number import ceil_div
|
from Crypto.Util.number import ceil_div
|
||||||
from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId
|
from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
|
||||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|
||||||
from Crypto.Util.py21compat import *
|
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
class PKCS115_SigScheme:
|
class PKCS115_SigScheme:
|
||||||
@@ -154,13 +150,7 @@ class PKCS115_SigScheme:
|
|||||||
em1 = bchr(0x00)*(k-len(m)) + m
|
em1 = bchr(0x00)*(k-len(m)) + m
|
||||||
# Step 3
|
# Step 3
|
||||||
try:
|
try:
|
||||||
em2_with_params = EMSA_PKCS1_V1_5_ENCODE(mhash, k, True)
|
em2 = EMSA_PKCS1_V1_5_ENCODE(mhash, k)
|
||||||
# MD hashes always require NULL params in AlgorithmIdentifier.
|
|
||||||
# For all others, it is optional.
|
|
||||||
if _HASH_OIDS[mhash.name].startswith('1.2.840.113549.2.'): # MD2/MD4/MD5
|
|
||||||
em2_without_params = em2_with_params
|
|
||||||
else:
|
|
||||||
em2_without_params = EMSA_PKCS1_V1_5_ENCODE(mhash, k, False)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 0
|
return 0
|
||||||
# Step 4
|
# Step 4
|
||||||
@@ -168,9 +158,9 @@ class PKCS115_SigScheme:
|
|||||||
# of its components one at a time) we avoid attacks to the padding
|
# of its components one at a time) we avoid attacks to the padding
|
||||||
# scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537).
|
# scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537).
|
||||||
#
|
#
|
||||||
return em1==em2_with_params or em1==em2_without_params
|
return em1==em2
|
||||||
|
|
||||||
def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
|
def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
|
||||||
"""
|
"""
|
||||||
Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
|
Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
|
||||||
in PKCS#1 v2.1 (RFC3447, 9.2).
|
in PKCS#1 v2.1 (RFC3447, 9.2).
|
||||||
@@ -184,9 +174,6 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
|
|||||||
The hash object that holds the digest of the message being signed.
|
The hash object that holds the digest of the message being signed.
|
||||||
emLen : int
|
emLen : int
|
||||||
The length the final encoding must have, in bytes.
|
The length the final encoding must have, in bytes.
|
||||||
with_hash_parameters:
|
|
||||||
If True (default), include NULL parameters for the hash
|
|
||||||
algorithm in the ``digestAlgorithm`` SEQUENCE.
|
|
||||||
|
|
||||||
:attention: the early standard (RFC2313) stated that ``DigestInfo``
|
:attention: the early standard (RFC2313) stated that ``DigestInfo``
|
||||||
had to be BER-encoded. This means that old signatures
|
had to be BER-encoded. This means that old signatures
|
||||||
@@ -194,6 +181,11 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
|
|||||||
is not supported in DER. Such encoding cannot be
|
is not supported in DER. Such encoding cannot be
|
||||||
reproduced by this function.
|
reproduced by this function.
|
||||||
|
|
||||||
|
:attention: the same standard defined ``DigestAlgorithm`` to be
|
||||||
|
of ``AlgorithmIdentifier`` type, where the PARAMETERS
|
||||||
|
item is optional. Encodings for ``MD2/4/5`` without
|
||||||
|
``PARAMETERS`` cannot be reproduced by this function.
|
||||||
|
|
||||||
:Return: An ``emLen`` byte long string that encodes the hash.
|
:Return: An ``emLen`` byte long string that encodes the hash.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -216,19 +208,7 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
|
|||||||
# { OID id-sha512 PARAMETERS NULL }
|
# { OID id-sha512 PARAMETERS NULL }
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters
|
digestAlgo = DerSequence([hash.oid, DerNull().encode()])
|
||||||
# should be omitted. They may be present, but when they are, they shall
|
|
||||||
# have NULL value.
|
|
||||||
|
|
||||||
if with_hash_parameters:
|
|
||||||
digestAlgo = DerSequence([
|
|
||||||
DerObjectId(_HASH_OIDS[hash.name]).encode(),
|
|
||||||
DerNull().encode()
|
|
||||||
])
|
|
||||||
else:
|
|
||||||
digestAlgo = DerSequence([
|
|
||||||
DerObjectId(_HASH_OIDS[hash.name]).encode(),
|
|
||||||
])
|
|
||||||
digest = DerOctetString(hash.digest())
|
digest = DerOctetString(hash.digest())
|
||||||
digestInfo = DerSequence([
|
digestInfo = DerSequence([
|
||||||
digestAlgo.encode(),
|
digestAlgo.encode(),
|
||||||
@@ -238,7 +218,7 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
|
|||||||
# We need at least 11 bytes for the remaining data: 3 fixed bytes and
|
# We need at least 11 bytes for the remaining data: 3 fixed bytes and
|
||||||
# at least 8 bytes of padding).
|
# at least 8 bytes of padding).
|
||||||
if emLen<len(digestInfo)+11:
|
if emLen<len(digestInfo)+11:
|
||||||
raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest))
|
raise ValueError("Selected hash algorith has a too long digest (%d bytes)." % len(digest))
|
||||||
PS = bchr(0xFF) * (emLen - len(digestInfo) - 3)
|
PS = bchr(0xFF) * (emLen - len(digestInfo) - 3)
|
||||||
return b("\x00\x01") + PS + bchr(0x00) + digestInfo
|
return b("\x00\x01") + PS + bchr(0x00) + digestInfo
|
||||||
|
|
||||||
@@ -254,75 +234,3 @@ def new(key):
|
|||||||
"""
|
"""
|
||||||
return PKCS115_SigScheme(key)
|
return PKCS115_SigScheme(key)
|
||||||
|
|
||||||
# AlgorithmIdentifier OIDs for use with PKCS#1 v1.5.
|
|
||||||
#
|
|
||||||
# These map names to the associated OIDs. We should try to be compatible
|
|
||||||
# with the standard library's hashlib modules, where possible.
|
|
||||||
#
|
|
||||||
# XXX - These will probably be moved somewhere else soon.
|
|
||||||
_HASH_OIDS = {
|
|
||||||
#: id-md2 OBJECT IDENTIFIER ::= {
|
|
||||||
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
|
||||||
#: digestAlgorithm(2) 2
|
|
||||||
#: }
|
|
||||||
"MD2": "1.2.840.113549.2.2",
|
|
||||||
"md2": "1.2.840.113549.2.2",
|
|
||||||
|
|
||||||
#: id-md4 OBJECT IDENTIFIER ::= {
|
|
||||||
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
|
||||||
#: digestAlgorithm(2) 4
|
|
||||||
#: }
|
|
||||||
"MD4": "1.2.840.113549.2.4",
|
|
||||||
"md4": "1.2.840.113549.2.4",
|
|
||||||
|
|
||||||
#: id-md5 OBJECT IDENTIFIER ::= {
|
|
||||||
#: iso(1) member-body(2) us(840) rsadsi(113549)
|
|
||||||
#: digestAlgorithm(2) 5
|
|
||||||
#: }
|
|
||||||
"MD5": "1.2.840.113549.2.5",
|
|
||||||
"md5": "1.2.840.113549.2.5",
|
|
||||||
|
|
||||||
#: id-ripemd160 OBJECT IDENTIFIER ::= {
|
|
||||||
#: iso(1) identified-organization(3) teletrust(36)
|
|
||||||
#: algorithm(3) hashAlgorithm(2) ripemd160(1)
|
|
||||||
#: }
|
|
||||||
"RIPEMD160": "1.3.36.3.2.1",
|
|
||||||
"ripemd160": "1.3.36.3.2.1",
|
|
||||||
|
|
||||||
#: id-sha1 OBJECT IDENTIFIER ::= {
|
|
||||||
#: iso(1) identified-organization(3) oiw(14) secsig(3)
|
|
||||||
#: algorithms(2) 26
|
|
||||||
#: }
|
|
||||||
"SHA1": "1.3.14.3.2.26",
|
|
||||||
"sha1": "1.3.14.3.2.26",
|
|
||||||
|
|
||||||
#: id-sha224 OBJECT IDENTIFIER ::= {
|
|
||||||
#: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3)
|
|
||||||
#: nistalgorithm(4) hashalgs(2) 4
|
|
||||||
#: }
|
|
||||||
"SHA224": '2.16.840.1.101.3.4.2.4',
|
|
||||||
"sha224": '2.16.840.1.101.3.4.2.4',
|
|
||||||
|
|
||||||
#: id-sha256 OBJECT IDENTIFIER ::= {
|
|
||||||
#: joint-iso-itu-t(2) country(16) us(840) organization(1)
|
|
||||||
#: gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1
|
|
||||||
#: }
|
|
||||||
"SHA256": "2.16.840.1.101.3.4.2.1",
|
|
||||||
"sha256": "2.16.840.1.101.3.4.2.1",
|
|
||||||
|
|
||||||
#: id-sha384 OBJECT IDENTIFIER ::= {
|
|
||||||
#: joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3)
|
|
||||||
#: nistalgorithm(4) hashalgs(2) 2
|
|
||||||
#: }
|
|
||||||
"SHA384": '2.16.840.1.101.3.4.2.2',
|
|
||||||
"sha384": '2.16.840.1.101.3.4.2.2',
|
|
||||||
|
|
||||||
#: id-sha512 OBJECT IDENTIFIER ::= {
|
|
||||||
#: joint-iso-itu-t(2)
|
|
||||||
#: country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3
|
|
||||||
#: }
|
|
||||||
"SHA512": "2.16.840.1.101.3.4.2.3",
|
|
||||||
"sha512": "2.16.840.1.101.3.4.2.3",
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,9 @@ An example of usage is the following:
|
|||||||
>>> from Crypto.Cipher import AES
|
>>> from Crypto.Cipher import AES
|
||||||
>>> from Crypto.Util import Counter
|
>>> from Crypto.Util import Counter
|
||||||
>>>
|
>>>
|
||||||
>>> pt = b'X'*1000000
|
>>> pt = b'\x00'*1000000
|
||||||
>>> ctr = Counter.new(128)
|
>>> ctr = Counter.new(128)
|
||||||
>>> key = b'AES-128 symm key'
|
>>> cipher = AES.new(b'\x00'*16, AES.MODE_CTR, counter=ctr)
|
||||||
>>> cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
|
|
||||||
>>> ct = cipher.encrypt(pt)
|
>>> ct = cipher.encrypt(pt)
|
||||||
|
|
||||||
:undocumented: __package__
|
:undocumented: __package__
|
||||||
@@ -57,15 +56,11 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
|||||||
from Crypto.Util.py21compat import *
|
from Crypto.Util.py21compat import *
|
||||||
from Crypto.Util.py3compat import *
|
from Crypto.Util.py3compat import *
|
||||||
|
|
||||||
from Crypto.pct_warnings import DisableShortcut_DeprecationWarning
|
|
||||||
from Crypto.Util import _counter
|
from Crypto.Util import _counter
|
||||||
import struct
|
import struct
|
||||||
import warnings
|
|
||||||
|
|
||||||
|
|
||||||
# Factory function
|
# Factory function
|
||||||
_deprecated = "deprecated"
|
def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=False):
|
||||||
def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=_deprecated):
|
|
||||||
"""Create a stateful counter block function suitable for CTR encryption modes.
|
"""Create a stateful counter block function suitable for CTR encryption modes.
|
||||||
|
|
||||||
Each call to the function returns the next counter block.
|
Each call to the function returns the next counter block.
|
||||||
@@ -73,7 +68,7 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
|
|||||||
|
|
||||||
prefix || counter value || postfix
|
prefix || counter value || postfix
|
||||||
|
|
||||||
The counter value is incremented by 1 at each call.
|
The counter value is incremented by one at each call.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
nbits : integer
|
nbits : integer
|
||||||
@@ -86,18 +81,17 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
|
|||||||
used.
|
used.
|
||||||
initial_value : integer
|
initial_value : integer
|
||||||
The initial value of the counter. Default value is 1.
|
The initial value of the counter. Default value is 1.
|
||||||
overflow : integer
|
|
||||||
This value is currently ignored.
|
|
||||||
little_endian : boolean
|
little_endian : boolean
|
||||||
If *True*, the counter number will be encoded in little endian format.
|
If True, the counter number will be encoded in little endian format.
|
||||||
If *False* (default), in big endian format.
|
If False (default), in big endian format.
|
||||||
allow_wraparound : boolean
|
allow_wraparound : boolean
|
||||||
If *True*, the counter will automatically restart from zero after
|
If True, the function will raise an *OverflowError* exception as soon
|
||||||
reaching the maximum value (``2**nbits-1``).
|
as the counter wraps around. If False (default), the counter will
|
||||||
If *False* (default), the object will raise an *OverflowError*.
|
simply restart from zero.
|
||||||
disable_shortcut : deprecated
|
disable_shortcut : boolean
|
||||||
This option is a no-op for backward compatibility. It will be removed
|
If True, do not make ciphers from `Crypto.Cipher` bypass the Python
|
||||||
in a future version. Don't use it.
|
layer when invoking the counter block function.
|
||||||
|
If False (default), bypass the Python layer.
|
||||||
:Returns:
|
:Returns:
|
||||||
The counter block function.
|
The counter block function.
|
||||||
"""
|
"""
|
||||||
@@ -114,13 +108,10 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
|
|||||||
|
|
||||||
initval = _encode(initial_value, nbytes, little_endian)
|
initval = _encode(initial_value, nbytes, little_endian)
|
||||||
|
|
||||||
if disable_shortcut is not _deprecated: # exact object comparison
|
|
||||||
warnings.warn("disable_shortcut has no effect and is deprecated", DisableShortcut_DeprecationWarning)
|
|
||||||
|
|
||||||
if little_endian:
|
if little_endian:
|
||||||
return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
|
return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
|
||||||
else:
|
else:
|
||||||
return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
|
return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
|
||||||
|
|
||||||
def _encode(n, nbytes, little_endian=False):
|
def _encode(n, nbytes, little_endian=False):
|
||||||
retval = []
|
retval = []
|
||||||
|
|||||||
@@ -23,22 +23,15 @@
|
|||||||
Contains useful modules that don't belong into any of the
|
Contains useful modules that don't belong into any of the
|
||||||
other Crypto.* subpackages.
|
other Crypto.* subpackages.
|
||||||
|
|
||||||
======================== =============================================
|
Crypto.Util.number Number-theoretic functions (primality testing, etc.)
|
||||||
Module Description
|
Crypto.Util.randpool Random number generation
|
||||||
======================== =============================================
|
Crypto.Util.RFC1751 Converts between 128-bit keys and human-readable
|
||||||
`Crypto.Util.number` Number-theoretic functions (primality testing, etc.)
|
|
||||||
`Crypto.Util.Counter` Fast counter functions for CTR cipher modes.
|
|
||||||
`Crypto.Util.randpool` Random number generation
|
|
||||||
`Crypto.Util.RFC1751` Converts between 128-bit keys and human-readable
|
|
||||||
strings of words.
|
strings of words.
|
||||||
`Crypto.Util.asn1` Minimal support for ASN.1 DER encoding
|
Crypto.Util.asn1 Minimal support for ASN.1 DER encoding
|
||||||
`Crypto.Util.Padding` Set of functions for adding and removing padding.
|
|
||||||
======================== =============================================
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['randpool', 'RFC1751', 'number', 'strxor', 'asn1', 'Counter',
|
__all__ = ['randpool', 'RFC1751', 'number', 'strxor', 'asn1' ]
|
||||||
'Padding' ]
|
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
+155
-768
File diff suppressed because it is too large
Load Diff
@@ -81,21 +81,4 @@ except TypeError:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
#
|
|
||||||
# Python 2.2 introduces the built-in staticmethod(). Python 2.4 turns
|
|
||||||
# it into a function decorator (@staticmethod).
|
|
||||||
#
|
|
||||||
# The following recipe for achieving the same thing in Python 2.1 comes
|
|
||||||
# from the Python Cookbok ("Implementanting Static Methods").
|
|
||||||
#
|
|
||||||
try:
|
|
||||||
class A:
|
|
||||||
def a(): pass
|
|
||||||
a = staticmethod(a)
|
|
||||||
except NameError:
|
|
||||||
class staticmethod:
|
|
||||||
def __init__(self, anycallable):
|
|
||||||
self.__call__ = anycallable
|
|
||||||
__all__ += ['staticmethod']
|
|
||||||
|
|
||||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
|
|||||||
@@ -77,18 +77,12 @@ if sys.version_info[0] == 2:
|
|||||||
return s.encode('latin-1')
|
return s.encode('latin-1')
|
||||||
except:
|
except:
|
||||||
return ''.join(s)
|
return ''.join(s)
|
||||||
def tostr(bs):
|
|
||||||
return unicode(bs, 'latin-1')
|
|
||||||
else:
|
else:
|
||||||
def tobytes(s):
|
def tobytes(s):
|
||||||
if isinstance(s, unicode):
|
if isinstance(s, unicode):
|
||||||
return s.encode("latin-1")
|
return s.encode("latin-1")
|
||||||
else:
|
else:
|
||||||
return ''.join(s)
|
return ''.join(s)
|
||||||
def tostr(bs):
|
|
||||||
return bs.decode('latin-1')
|
|
||||||
# In Pyton 2.x, StringIO is a stand-alone module
|
|
||||||
from StringIO import StringIO as BytesIO
|
|
||||||
else:
|
else:
|
||||||
def b(s):
|
def b(s):
|
||||||
return s.encode("latin-1") # utf-8 would cause some side-effects we don't want
|
return s.encode("latin-1") # utf-8 would cause some side-effects we don't want
|
||||||
@@ -109,9 +103,5 @@ else:
|
|||||||
return s.encode("latin-1")
|
return s.encode("latin-1")
|
||||||
else:
|
else:
|
||||||
return bytes(s)
|
return bytes(s)
|
||||||
def tostr(bs):
|
|
||||||
return bs.decode("latin-1")
|
|
||||||
# In Pyton 3.x, StringIO is a sub-module of io
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
# vim:set ts=4 sw=4 sts=4 expandtab:
|
# vim:set ts=4 sw=4 sts=4 expandtab:
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
@@ -41,11 +41,11 @@ Crypto.Util
|
|||||||
generation, number theoretic functions)
|
generation, number theoretic functions)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', 'IO']
|
__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature']
|
||||||
|
|
||||||
__version__ = '2.7a1' # See also below and setup.py
|
__version__ = '2.6' # See also below and setup.py
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
# New software should look at this instead of at __version__ above.
|
# New software should look at this instead of at __version__ above.
|
||||||
version_info = (2, 7, 0, 'alpha', 1) # See also above and setup.py
|
version_info = (2, 6, 0, 'final', 0) # See also above and setup.py
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,6 @@ class ClockRewindWarning(CryptoRuntimeWarning):
|
|||||||
class GetRandomNumber_DeprecationWarning(CryptoDeprecationWarning):
|
class GetRandomNumber_DeprecationWarning(CryptoDeprecationWarning):
|
||||||
"""Issued when Crypto.Util.number.getRandomNumber is invoked."""
|
"""Issued when Crypto.Util.number.getRandomNumber is invoked."""
|
||||||
|
|
||||||
class DisableShortcut_DeprecationWarning(CryptoDeprecationWarning):
|
|
||||||
"""Issued when Counter.new(disable_shortcut=...) is invoked."""
|
|
||||||
|
|
||||||
class PowmInsecureWarning(CryptoRuntimeWarning):
|
class PowmInsecureWarning(CryptoRuntimeWarning):
|
||||||
"""Warning for when _fastmath is built without mpz_powm_sec"""
|
"""Warning for when _fastmath is built without mpz_powm_sec"""
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
import bson, scrypt
|
||||||
|
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
from Crypto.Util import Counter
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
from Crypto.PublicKey import DSA
|
||||||
|
from salsa20 import Salsa20_keystream
|
||||||
|
import os, struct, time, hashlib, hashlib, random
|
||||||
|
|
||||||
|
|
||||||
|
class EncryptedScreenshot:
|
||||||
|
def __init__(self, metadata,id=None,signer=None,password_encryptor=None):
|
||||||
|
def rand(len):
|
||||||
|
return ''.join(
|
||||||
|
random.choice("1234567890ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz") for _ in range(len))
|
||||||
|
|
||||||
|
self.password = rand(16)
|
||||||
|
print "Passphrase %s" % str(bytearray(self.passphrase())).encode("hex")
|
||||||
|
self.id = id
|
||||||
|
if id is None:
|
||||||
|
self.id = rand(8)
|
||||||
|
self.metadata_encryption = True
|
||||||
|
self.metadata = metadata
|
||||||
|
self.signer = signer
|
||||||
|
self.password_encryptor = password_encryptor
|
||||||
|
|
||||||
|
def caesar_encrypted_password(self):
|
||||||
|
caesar_key = reduce(lambda sum,charcode: sum+charcode, map(ord,list(self.id)))
|
||||||
|
caesar_plaintext = map(ord, self.password)
|
||||||
|
caesar_ciphertext = Caesar().encrypt(caesar_plaintext,caesar_key)
|
||||||
|
return ''.join(map(chr,caesar_ciphertext))
|
||||||
|
|
||||||
|
def passphrase(self):
|
||||||
|
# new ScryptParameters(64, 8, 1,32, new Uint8List.fromList(new List<int>()))
|
||||||
|
print "Password units: %s" % (map(ord, self.password.encode("utf-8")),)
|
||||||
|
sha = hashlib.sha256()
|
||||||
|
sha.update(self.password)
|
||||||
|
return sha.digest() # scrypt.hash(self.password.encode("utf-8"), '', 64, 8, 1, 32)
|
||||||
|
|
||||||
|
def assemble(self, file):
|
||||||
|
(image_digest, encrypted_image) = self.encrypt(file)
|
||||||
|
self.metadata["hash"] = image_digest
|
||||||
|
unencrypted_metadata = bson.dumps(self.metadata)
|
||||||
|
if len(unencrypted_metadata) % 16 != 0:
|
||||||
|
unencrypted_metadata += ' ' * (16 - len(unencrypted_metadata) % 16)
|
||||||
|
(encryptor, iv) = self.encryptor(len(unencrypted_metadata))
|
||||||
|
encrypted_metadata = []
|
||||||
|
|
||||||
|
encrypted_metadata += encryptor(unencrypted_metadata)
|
||||||
|
|
||||||
|
encrypted_metadata = iv + str(bytearray(encrypted_metadata))
|
||||||
|
|
||||||
|
print "Metadata: %s" % str(encrypted_metadata).encode("base64").replace("\n", "")
|
||||||
|
print "%s %s" % (str(encrypted_metadata[:16]).encode("hex"), str(encrypted_metadata[16:]).encode("hex"))
|
||||||
|
print "Unencrypted: %s" % (unencrypted_metadata.encode("hex"))
|
||||||
|
print "Password %s" % self.password
|
||||||
|
|
||||||
|
print bson.loads(unencrypted_metadata)
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
"image": encrypted_image,
|
||||||
|
"metadata_encryption": self.metadata_encryption,
|
||||||
|
"metadata": encrypted_metadata if self.metadata_encryption else self.metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.signer is not None:
|
||||||
|
fields["signature"] = self.signer.signature(encrypted_metadata if self.metadata_encryption else bson.dumps(self.metadata))
|
||||||
|
|
||||||
|
if self.password_encryptor is not None:
|
||||||
|
fields["password"] = self.password_encryptor.encrypt_password(self.password)
|
||||||
|
|
||||||
|
return bson.dumps(fields)
|
||||||
|
|
||||||
|
def encryptor(self,length=0):
|
||||||
|
iv = os.urandom(16)
|
||||||
|
ctr = Counter.new(128, initial_value=long(iv.encode("hex"), 16))
|
||||||
|
print "IV: %s" % iv.encode("hex")
|
||||||
|
cipher = AES.new(self.passphrase(), AES.MODE_CTR, counter=ctr)
|
||||||
|
|
||||||
|
#salsa
|
||||||
|
# keysstream = bytearray(Salsa20_keystream(length,iv[:8],self.passphrase()))
|
||||||
|
# offset={"offset": 0}
|
||||||
|
def encrypt(data):
|
||||||
|
#Salsa20
|
||||||
|
# array = bytearray(data)
|
||||||
|
# for i in range(len(array)):
|
||||||
|
# array[i] ^= keysstream[i+offset["offset"]]
|
||||||
|
# offset["offset"] += len(array)
|
||||||
|
# return str(array)
|
||||||
|
return cipher.encrypt(data)
|
||||||
|
|
||||||
|
return (encrypt, iv)
|
||||||
|
|
||||||
|
def encrypt(self, file):
|
||||||
|
filesize = os.path.getsize(file)
|
||||||
|
(encryptor, iv) = self.encryptor(filesize)
|
||||||
|
binary = []
|
||||||
|
digest = hashlib.sha256()
|
||||||
|
with open(file, 'rb') as infile:
|
||||||
|
# binary += struct.pack('<Q', filesize)
|
||||||
|
while True:
|
||||||
|
chunk = infile.read(64 * 1024)
|
||||||
|
if len(chunk) == 0:
|
||||||
|
break
|
||||||
|
elif len(chunk) % 16 != 0:
|
||||||
|
pass # chunk += ' ' * (16 - len(chunk) % 16)
|
||||||
|
digest.update(chunk)
|
||||||
|
binary += encryptor(chunk)
|
||||||
|
return (digest.digest(), iv + str(bytearray(binary)))
|
||||||
|
|
||||||
|
from Crypto.Signature import PKCS1_v1_5
|
||||||
|
from Crypto.Hash import SHA256
|
||||||
|
|
||||||
|
class Signer:
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default():
|
||||||
|
return Signer(RSA.importKey("-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEAuTEHVWjtwFydG/VmHKr15qymIkwZIaNnQeKmBzzn+n87Zjdg\nkEDtCEYSq3W1VxlgUw1Dh8KTTr3K1LQwcDfx8vdArk99OX4mxqpYWRbdfEQk1wUD\n7ctr2E5eKQcCcbAl/OKYFa/PkY3KsBuns06Rlf85sHSZ7CfirqH6FoefrXDZVAJO\nmrQhTh/0qGlBy1f13c2a12sFNOmncLs8Vp4ftJxLr9GoE4vsQvX/6oQvi7PqWYmv\nlwmUUvhCPS/JSF8kCuvmvfgcF8OXOj1Q6itOLZDt8/ZuZeok7nS8JxhR73HzHR4a\nHWnqC8UkIx1CR/VvlZhp/7gbS/y1EORRaVlO3YTkF2UMTtF2BoCsY5glpealDV6F\nh9YZwq68APb5/cleuXu8tebYpo5yuwH9G8m0bp7mIrVUnaBPCE/Wsj6HFULniUi8\n0N8149cM2kLmm7c+JNC4QUupc3iy3qylqh1KFlU0SWPAinDbODSHqnPiWV0IHjC9\nmVeAmMDjg/6R7uaAubLz0rJso/odk0kfWYO98D43Hv7C+TG/If9oE7JdsgSCCfeT\nuaKE5XH3C3GegciDOyr6Sd/08KprQwvy7nZpJJxzpyr2MoJ/n8O6O4IqDt76EAZz\n76nUvJzPXSoUGy7942QOwywpRYB6NbrVpPUemUCsUttUJzhgHU70ElqE2hsCAwEA\nAQKCAgBVyMZS5BYt4zjLuLMiWHcr8ZHLlWCW2nB8bpbmB2qV+NX1FXXfnJOwH3WK\ngy4LOLAMCLrdal5+PSB1wzok4WVsXOhTVnL1bOBdao8eRZ83bwF5sNMPFgnQ2wx3\nCM4zB5uxNu2oLhaCoCHhzg2y25RI3T9F491hLWCt8E4+nXh0CTBC4Aa1VveOjvLw\nCEH4BbjYk+NEIkj5J7ruV20t2nVpXnUY7o9i7o/0vKtdYPn9RswpycPSvRc+D83v\nNfGRWrEBdiEeoo2w3GNzEPAoaQL/zIDNX7vn7bxJ0T1PBs79kdVCCa2jLmrCJQIG\nWglX9/NGYqHHWOscGeVt+7VSjZIf8+q32khXcheBUP++wsDC1YoxiT2aDwV7zX8d\nBhB6MMi7QUqkkwnuvXdyUIUy4J7lJHDsC5l4EYDmbhViTax8Qp42MobJ32tHoS1c\nhfN5w4Usqx7yGRL0vUQmbGrh7JbyayD6CFYiZOinhN0ma7dMqglQ4ch3HPeMct9T\nLskF+gSlol2gTCMYjl9Zwb2rG8uSthjXFd2CDCHbiqzzRhskHG2vWuhxvASP4yeD\nNbm85H8ZKqhejcWL4XlJIZK2ZbWUjdMDPCDDd3ipwQ/GUmSo6IaNxEFMCFLsk/xl\n2BGg99xDuacldKNUtf+aMv4HglW6at+TasVsmWXsF/cWR1JusQKCAQEA88JECQTE\nm8AIOaHY5rOWxkYCsVzVw9zRHOfIXbvMMr9k3OTE/9gNy35QTee5UYVEnjRuWP/r\n2hRJhbTfwP5LmcvsxN3cE3SkrlNCulo0TWD4O78W+PnEkSzN+1h39QOfA/TTN9pV\nnqh7Bf5u9kBioooPeUe6yU/eMlVa+mzwNfDC9ogS7o1/1Zy4ui4beo0XpIv5KNtV\nU5K2uEcx0jnAzhcd+IKzDNm7HuU82KCsYNUCdHIJOpoq0WqPTqa350LPWHqbZA9n\nOa+5Yo1ADMn/rMFohErWq2zjUlO3qFjyGBaVAQCYCeprmk56vk4gP44X2YkW524G\nHg/CWYITF42W7QKCAQEAwn3UDzS1LeCZq82TSlFPWO3dojh4fMwssQWzJkrkJg4N\nNlAGGteh7K2eIFjACk7bLe037F2RhPxk+RZEIy4Adr5oAcNLKXMIcaAx9Xca+JrX\nRjLAGsBuoOJFYBVm+/ZlwoVkhOnX1VOJ4Zt4TNOYcImrhZyeVjVfJI7ijTU61v5M\n2+6Ekc2pq6WI7/2hmM+UOw6xvroNvCx0neWVgAVdCWfWWmCkUqjsS8FJ2z9q/8or\nnFPKeAT/kcDg2N+8LiPeVfAqdl6GZ3SY3lZ+Q+JEJMAZEsFsbh0x5OT4750Y/MBz\nqQF1oU2HkV5xah5tAqECp37/FSIxPG2e/qklGqbMJwKCAQA/qkSUym8DcvNzAgeh\nsdQ2cwCvDF00q87eKteVS8B4nK6eVw3w+KAZvyMARf6MAS+71lvf2O/j5JqTVnt+\nb6yVPcLYZE3fsv50HYD3JSo175bGHBHG841YkYg3FpM2Jjz5Do/ALcFhEAYZuauH\nm6dnZoHGHmr1u2uAX/TEJYHTxM9XDpFLRx/VTfqdff9lUcaUDo8EEc1GZ7JbjRTB\nIJ5v9W+5gYF8YL3TwvHSbpy3KctbWJF6gdufGKLXWwn7V+LJ7DP7vV4rne7gg53v\n+S5TE6zVqKpK2cTBsuXsDVcl3XgLa/lJ1bVG9ypt2//mOZmXEowt4/mrDlingia0\nZyG9AoIBAAvBQSTeIakxLviER0exnGMalU+trBKW4IieeJJy6lEmfkPvGD9dEwtT\n/v+jfY/h7jtbYAroKNhpzMyFPP8HU73Zij25CPzrV/JOJVbZqQanjSVQAe5b/RO6\nOUkyYfQOk13rZATogUQCdY3uMJosG8WJfJVpvuQk+6gg/q5cLj86RXjxdI+/Z2bZ\nbWpb4P10ZlgfbjzBz/y0jyPP8XY4XMQpw3nY53WbghSeDRG0RopJNNOQ+ObCHpQ3\nnR9efmgngNOe3WIkGml8UZT2k1EVBttVxO4uRJhvKUnVUPpie1UjaJopXWuvXOc7\nVw1740jKZHetJEupsmIdmgN4Q6bVt/cCggEBAILm8bfc2OGbZgN4RT4315EkWekb\nMngMFETDDgn6p2jmkVjXDGku1oX502X7BKteZ+gD4Oqy8BtrvshyzvzoBerthrDj\nJ4M3t7uFC14mvRfdelRcKyed13SGzZNJxxxL7vNq2Me81yzBaMPiAZpDIN4awEzV\nPQwWMmogo6sEp2ND2NhvbP4Hxl8WXoI+3hH5hetE31kvBzDlWek4Wj059BeeIhjF\nBNUxIwbqlSwt+2VuY17LBzCe4Tnp3Ns+ptD9Fn2vm+Azl9qBY2VvqOcdp0R8tmeo\nwpjrWKwP9LkwCt9ZxVzCQBiIFYtpZ8a2EahqTbOlFEsvcDbTfQlf/lykhjA=\n-----END RSA PRIVATE KEY-----\n"),"PUBLIC")
|
||||||
|
|
||||||
|
def __init__(self,privateKey,privateKeyId, mode=RSA):
|
||||||
|
self.mode = mode
|
||||||
|
self.privateKeyId = privateKeyId
|
||||||
|
self._signer = PKCS1_v1_5.new(privateKey)
|
||||||
|
|
||||||
|
def sign(self, data):
|
||||||
|
digest = SHA256.new()
|
||||||
|
digest.update(data)
|
||||||
|
return self._signer.sign(digest)
|
||||||
|
|
||||||
|
def signature(self,data):
|
||||||
|
signed = self.sign(data)
|
||||||
|
return {"signed-hash": signed,
|
||||||
|
"signature-algorithm": "SHA-256/%s" % unicode("RSA" if self.mode == RSA else "DSA"),
|
||||||
|
"key-id": unicode(self.privateKeyId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class EncryptedPassword:
|
||||||
|
|
||||||
|
def __init__(self,publicKey,publicKeyId,mode=RSA):
|
||||||
|
assert mode == RSA
|
||||||
|
self.mode = mode
|
||||||
|
self.publicKey = publicKey
|
||||||
|
self.publicKeyId = publicKeyId
|
||||||
|
|
||||||
|
def encrypt(self,password):
|
||||||
|
return self.publicKey.encrypt(password.encode("utf-8"), os.urandom(32))[0]
|
||||||
|
|
||||||
|
def encrypt_password(self,password):
|
||||||
|
return {"algorithm": unicode( "RSA" if self.mode == RSA else "DSA"),
|
||||||
|
"key-id": unicode(self.publicKeyId),
|
||||||
|
"password": self.encrypt(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Caesar:
|
||||||
|
|
||||||
|
def __init__(self,charset = map(ord,list("1234567890ABCDEFGHIJKLMNOPQRSTUWVXYZabcdefghijklmnopqrstuwvxyz"))):
|
||||||
|
self.charset = charset
|
||||||
|
|
||||||
|
def encrypt(self,plaintext,key):
|
||||||
|
if key >= len(self.charset) or key < 0:
|
||||||
|
key = key % len(self.charset)
|
||||||
|
|
||||||
|
def addKey(charcode):
|
||||||
|
pos = self.charset.index(charcode)
|
||||||
|
if pos + key >= len(self.charset):
|
||||||
|
return self.charset[pos+key - len(self.charset)]
|
||||||
|
else:
|
||||||
|
return self.charset[pos+key]
|
||||||
|
return map(addKey,plaintext)
|
||||||
|
|
||||||
|
def decrypt(self,ciphertext,key):
|
||||||
|
return self.encrypt(ciphertext,key*-1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
privateKey = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS0FJQkFBS0NBZ0VBdVRFSFZXanR3RnlkRy9WbUhLcjE1cXltSWt3WklhTm5RZUttQnp6bituODdaamRnCmtFRHRDRVlTcTNXMVZ4bGdVdzFEaDhLVFRyM0sxTFF3Y0RmeDh2ZEFyazk5T1g0bXhxcFlXUmJkZkVRazF3VUQKN2N0cjJFNWVLUWNDY2JBbC9PS1lGYS9Qa1kzS3NCdW5zMDZSbGY4NXNIU1o3Q2ZpcnFINkZvZWZyWERaVkFKTwptclFoVGgvMHFHbEJ5MWYxM2MyYTEyc0ZOT21uY0xzOFZwNGZ0SnhMcjlHb0U0dnNRdlgvNm9Rdmk3UHFXWW12Cmx3bVVVdmhDUFMvSlNGOGtDdXZtdmZnY0Y4T1hPajFRNml0T0xaRHQ4L1p1WmVvazduUzhKeGhSNzNIekhSNGEKSFducUM4VWtJeDFDUi9WdmxaaHAvN2diUy95MUVPUlJhVmxPM1lUa0YyVU1UdEYyQm9Dc1k1Z2xwZWFsRFY2RgpoOVlad3E2OEFQYjUvY2xldVh1OHRlYllwbzV5dXdIOUc4bTBicDdtSXJWVW5hQlBDRS9Xc2o2SEZVTG5pVWk4CjBOODE0OWNNMmtMbW03YytKTkM0UVV1cGMzaXkzcXlscWgxS0ZsVTBTV1BBaW5EYk9EU0hxblBpV1YwSUhqQzkKbVZlQW1NRGpnLzZSN3VhQXViTHowckpzby9vZGswa2ZXWU85OEQ0M0h2N0MrVEcvSWY5b0U3SmRzZ1NDQ2ZlVAp1YUtFNVhIM0MzR2VnY2lET3lyNlNkLzA4S3ByUXd2eTduWnBKSnh6cHlyMk1vSi9uOE82TzRJcUR0NzZFQVp6Cjc2blV2SnpQWFNvVUd5Nzk0MlFPd3l3cFJZQjZOYnJWcFBVZW1VQ3NVdHRVSnpoZ0hVNzBFbHFFMmhzQ0F3RUEKQVFLQ0FnQlZ5TVpTNUJZdDR6akx1TE1pV0hjcjhaSExsV0NXMm5COGJwYm1CMnFWK05YMUZYWGZuSk93SDNXSwpneTRMT0xBTUNMcmRhbDUrUFNCMXd6b2s0V1ZzWE9oVFZuTDFiT0JkYW84ZVJaODNid0Y1c05NUEZnblEyd3gzCkNNNHpCNXV4TnUyb0xoYUNvQ0hoemcyeTI1UkkzVDlGNDkxaExXQ3Q4RTQrblhoMENUQkM0QWExVnZlT2p2THcKQ0VINEJiallrK05FSWtqNUo3cnVWMjB0Mm5WcFhuVVk3bzlpN28vMHZLdGRZUG45UnN3cHljUFN2UmMrRDgzdgpOZkdSV3JFQmRpRWVvbzJ3M0dOekVQQW9hUUwveklETlg3dm43YnhKMFQxUEJzNzlrZFZDQ2EyakxtckNKUUlHCldnbFg5L05HWXFISFdPc2NHZVZ0KzdWU2paSWY4K3EzMmtoWGNoZUJVUCsrd3NEQzFZb3hpVDJhRHdWN3pYOGQKQmhCNk1NaTdRVXFra3dudXZYZHlVSVV5NEo3bEpIRHNDNWw0RVlEbWJoVmlUYXg4UXA0Mk1vYkozMnRIb1MxYwpoZk41dzRVc3F4N3lHUkwwdlVRbWJHcmg3SmJ5YXlENkNGWWlaT2luaE4wbWE3ZE1xZ2xRNGNoM0hQZU1jdDlUCkxza0YrZ1Nsb2wyZ1RDTVlqbDlad2Iyckc4dVN0aGpYRmQyQ0RDSGJpcXp6Umhza0hHMnZXdWh4dkFTUDR5ZUQKTmJtODVIOFpLcWhlamNXTDRYbEpJWksyWmJXVWpkTURQQ0REZDNpcHdRL0dVbVNvNklhTnhFRk1DRkxzay94bAoyQkdnOTl4RHVhY2xkS05VdGYrYU12NEhnbFc2YXQrVGFzVnNtV1hzRi9jV1IxSnVzUUtDQVFFQTg4SkVDUVRFCm04QUlPYUhZNXJPV3hrWUNzVnpWdzl6UkhPZklYYnZNTXI5azNPVEUvOWdOeTM1UVRlZTVVWVZFbmpSdVdQL3IKMmhSSmhiVGZ3UDVMbWN2c3hOM2NFM1NrcmxOQ3VsbzBUV0Q0Tzc4VytQbkVrU3pOKzFoMzlRT2ZBL1RUTjlwVgpucWg3QmY1dTlrQmlvb29QZVVlNnlVL2VNbFZhK216d05mREM5b2dTN28xLzFaeTR1aTRiZW8wWHBJdjVLTnRWClU1SzJ1RWN4MGpuQXpoY2QrSUt6RE5tN0h1VTgyS0NzWU5VQ2RISUpPcG9xMFdxUFRxYTM1MExQV0hxYlpBOW4KT2ErNVlvMUFETW4vck1Gb2hFcldxMnpqVWxPM3FGanlHQmFWQVFDWUNlcHJtazU2dms0Z1A0NFgyWWtXNTI0RwpIZy9DV1lJVEY0Mlc3UUtDQVFFQXduM1VEelMxTGVDWnE4MlRTbEZQV08zZG9qaDRmTXdzc1FXekprcmtKZzROCk5sQUdHdGVoN0syZUlGakFDazdiTGUwMzdGMlJoUHhrK1JaRUl5NEFkcjVvQWNOTEtYTUljYUF4OVhjYStKclgKUmpMQUdzQnVvT0pGWUJWbSsvWmx3b1ZraE9uWDFWT0o0WnQ0VE5PWWNJbXJoWnllVmpWZkpJN2lqVFU2MXY1TQoyKzZFa2MycHE2V0k3LzJobU0rVU93Nnh2cm9OdkN4MG5lV1ZnQVZkQ1dmV1dtQ2tVcWpzUzhGSjJ6OXEvOG9yCm5GUEtlQVQva2NEZzJOKzhMaVBlVmZBcWRsNkdaM1NZM2xaK1ErSkVKTUFaRXNGc2JoMHg1T1Q0NzUwWS9NQnoKcVFGMW9VMkhrVjV4YWg1dEFxRUNwMzcvRlNJeFBHMmUvcWtsR3FiTUp3S0NBUUEvcWtTVXltOERjdk56QWdlaApzZFEyY3dDdkRGMDBxODdlS3RlVlM4QjRuSzZlVnczdytLQVp2eU1BUmY2TUFTKzcxbHZmMk8vajVKcVRWbnQrCmI2eVZQY0xZWkUzZnN2NTBIWUQzSlNvMTc1YkdIQkhHODQxWWtZZzNGcE0ySmp6NURvL0FMY0ZoRUFZWnVhdUgKbTZkblpvSEdIbXIxdTJ1QVgvVEVKWUhUeE05WERwRkxSeC9WVGZxZGZmOWxVY2FVRG84RUVjMUdaN0pialJUQgpJSjV2OVcrNWdZRjhZTDNUd3ZIU2JweTNLY3RiV0pGNmdkdWZHS0xYV3duN1YrTEo3RFA3dlY0cm5lN2dnNTN2CitTNVRFNnpWcUtwSzJjVEJzdVhzRFZjbDNYZ0xhL2xKMWJWRzl5cHQyLy9tT1ptWEVvd3Q0L21yRGxpbmdpYTAKWnlHOUFvSUJBQXZCUVNUZUlha3hMdmlFUjBleG5HTWFsVSt0ckJLVzRJaWVlSkp5NmxFbWZrUHZHRDlkRXd0VAovditqZlkvaDdqdGJZQXJvS05ocHpNeUZQUDhIVTczWmlqMjVDUHpyVi9KT0pWYlpxUWFualNWUUFlNWIvUk82Ck9Va3lZZlFPazEzclpBVG9nVVFDZFkzdU1Kb3NHOFdKZkpWcHZ1UWsrNmdnL3E1Y0xqODZSWGp4ZEkrL1oyYloKYldwYjRQMTBabGdmYmp6QnoveTBqeVBQOFhZNFhNUXB3M25ZNTNXYmdoU2VEUkcwUm9wSk5OT1ErT2JDSHBRMwpuUjllZm1nbmdOT2UzV0lrR21sOFVaVDJrMUVWQnR0VnhPNHVSSmh2S1VuVlVQcGllMVVqYUpvcFhXdXZYT2M3ClZ3MTc0MGpLWkhldEpFdXBzbUlkbWdONFE2YlZ0L2NDZ2dFQkFJTG04YmZjMk9HYlpnTjRSVDQzMTVFa1dla2IKTW5nTUZFVEREZ242cDJqbWtWalhER2t1MW9YNTAyWDdCS3RlWitnRDRPcXk4QnRydnNoeXp2em9CZXJ0aHJEagpKNE0zdDd1RkMxNG12UmZkZWxSY0t5ZWQxM1NHelpOSnh4eEw3dk5xMk1lODF5ekJhTVBpQVpwRElONGF3RXpWClBRd1dNbW9nbzZzRXAyTkQyTmh2YlA0SHhsOFdYb0krM2hINWhldEUzMWt2QnpEbFdlazRXajA1OUJlZUloakYKQk5VeEl3YnFsU3d0KzJWdVkxN0xCekNlNFRucDNOcytwdEQ5Rm4ydm0rQXpsOXFCWTJWdnFPY2RwMFI4dG1lbwp3cGpyV0t3UDlMa3dDdDlaeFZ6Q1FCaUlGWXRwWjhhMkVhaHFUYk9sRkVzdmNEYlRmUWxmL2x5a2hqQT0KLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K="
|
||||||
|
publicKey = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUF1VEVIVldqdHdGeWRHL1ZtSEtyMQo1cXltSWt3WklhTm5RZUttQnp6bituODdaamRna0VEdENFWVNxM1cxVnhsZ1V3MURoOEtUVHIzSzFMUXdjRGZ4Cjh2ZEFyazk5T1g0bXhxcFlXUmJkZkVRazF3VUQ3Y3RyMkU1ZUtRY0NjYkFsL09LWUZhL1BrWTNLc0J1bnMwNlIKbGY4NXNIU1o3Q2ZpcnFINkZvZWZyWERaVkFKT21yUWhUaC8wcUdsQnkxZjEzYzJhMTJzRk5PbW5jTHM4VnA0Zgp0SnhMcjlHb0U0dnNRdlgvNm9Rdmk3UHFXWW12bHdtVVV2aENQUy9KU0Y4a0N1dm12ZmdjRjhPWE9qMVE2aXRPCkxaRHQ4L1p1WmVvazduUzhKeGhSNzNIekhSNGFIV25xQzhVa0l4MUNSL1Z2bFpocC83Z2JTL3kxRU9SUmFWbE8KM1lUa0YyVU1UdEYyQm9Dc1k1Z2xwZWFsRFY2Rmg5WVp3cTY4QVBiNS9jbGV1WHU4dGViWXBvNXl1d0g5RzhtMApicDdtSXJWVW5hQlBDRS9Xc2o2SEZVTG5pVWk4ME44MTQ5Y00ya0xtbTdjK0pOQzRRVXVwYzNpeTNxeWxxaDFLCkZsVTBTV1BBaW5EYk9EU0hxblBpV1YwSUhqQzltVmVBbU1EamcvNlI3dWFBdWJMejBySnNvL29kazBrZldZTzkKOEQ0M0h2N0MrVEcvSWY5b0U3SmRzZ1NDQ2ZlVHVhS0U1WEgzQzNHZWdjaURPeXI2U2QvMDhLcHJRd3Z5N25acApKSnh6cHlyMk1vSi9uOE82TzRJcUR0NzZFQVp6NzZuVXZKelBYU29VR3k3OTQyUU93eXdwUllCNk5iclZwUFVlCm1VQ3NVdHRVSnpoZ0hVNzBFbHFFMmhzQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="
|
||||||
|
encrypted = EncryptedScreenshot({"owner": u"test", "format": u"jpg", "title": u"5x5 Red", "timestamp": int(time.time()*1000)},
|
||||||
|
signer=Signer.default(),
|
||||||
|
password_encryptor=EncryptedPassword(RSA.importKey(publicKey.decode("base64")),"PUBLIC"))
|
||||||
|
fixed_id = encrypted.id #"W9u9Zm0u"
|
||||||
|
print len(encrypted.passphrase())
|
||||||
|
out = open("/home/marvin/Dokumente/IdeaProjects/EncryptedScreencloud/Frontend/WebApp/web/data/" + fixed_id, 'wb')
|
||||||
|
assembled = encrypted.assemble("5x5red.png")
|
||||||
|
out.write(assembled)
|
||||||
|
b = bson.loads(assembled)
|
||||||
|
del b["image"]
|
||||||
|
print b
|
||||||
|
#print assembled.encode("base64").replace("\n","")
|
||||||
|
print "http://localhost:8080/#%s%s" % (fixed_id, encrypted.password)
|
||||||
|
caesar_key = reduce(lambda sum,charcode: sum+charcode, map(ord,list(fixed_id)))
|
||||||
|
caesar_plaintext = map(ord,encrypted.password)
|
||||||
|
caesar_ciphertext = Caesar().encrypt(caesar_plaintext,caesar_key)
|
||||||
|
assert caesar_plaintext == Caesar().decrypt(caesar_ciphertext,caesar_key)
|
||||||
|
print "caesar_key=%s %s -> %s" % (caesar_key,encrypted.password,''.join(map(chr,caesar_ciphertext)))
|
||||||
|
print "http://localhost:8080/#%s%sC" % (fixed_id, encrypted.caesar_encrypted_password())
|
||||||
|
print "http://localhost:8080/#%s" % (fixed_id, )
|
||||||
|
out.close()
|
||||||
+26
-6
@@ -52,31 +52,43 @@ class SeafileLibrary:
|
|||||||
self.name = name
|
self.name = name
|
||||||
self.owner = owner
|
self.owner = owner
|
||||||
|
|
||||||
def upload(self,file,file_name,directory):
|
def api_endpoint(self):
|
||||||
|
return "%s/repos/%s" % (self.client.api_endpoint(),self.id)
|
||||||
|
|
||||||
|
def upload(self,file,file_name,directory,link=None):
|
||||||
def obtain_link():
|
def obtain_link():
|
||||||
#curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/
|
#curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/
|
||||||
quoted = requests.get("%s/repos/%s/upload-link" % (self.client.api_endpoint(),self.id), headers = {'Authorization': "Token %s" % self.client.token.token,}).text
|
print "%s/upload-link" % self.api_endpoint()
|
||||||
|
quoted = requests.get("%s/upload-link" % self.api_endpoint(), headers = {'Authorization': "Token %s" % self.client.token.token,}).text
|
||||||
return quoted[1:-1]
|
return quoted[1:-1]
|
||||||
|
|
||||||
#curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" -F file=@test.txt -F filename=test.txt -F parent_dir=/ http://cloud.seafile.com:8082/upload-api/73c5d117-3bcf-48a0-aa2a-3f48d5274ae3
|
#curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" -F file=@test.txt -F filename=test.txt -F parent_dir=/ http://cloud.seafile.com:8082/upload-api/73c5d117-3bcf-48a0-aa2a-3f48d5274ae3
|
||||||
resp = requests.post(obtain_link(),
|
resp = requests.post(link or obtain_link() ,
|
||||||
files={'file': (file_name,open(file, 'rb')), 'parent_dir': directory},
|
files={'file': (file_name,open(file, 'rb')), 'parent_dir': directory, 'target_file': "%s/%s" % (directory,file_name)},
|
||||||
headers = {'Authorization': "Token %s" % self.client.token.token,}
|
headers = {'Authorization': "Token %s" % self.client.token.token,}
|
||||||
)
|
)
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
return SeafileFile(self,("%s/%s" % (directory,file_name)).replace('//','/').replace('//','/'),resp.text)
|
return SeafileFile(self,("%s/%s" % (directory,file_name)).replace('//','/').replace('//','/'),resp.text)
|
||||||
|
return False
|
||||||
|
|
||||||
|
#curl -H 'Authorization: Token f2210dacd3606d94ff8e61d99b477fd' -H 'Accept: application/json; charset=utf-8; indent=4' https://cloud.seafile.com/api2/repos/dae8cecc-2359-4d33-aa42-01b7846c4b32/file/detail/?p=/foo.c
|
||||||
|
def file_info(self,path):
|
||||||
|
resp=requests.get("%s/file/detail/?p=%s" % (self.api_endpoint(),path), headers = {'Authorization': "Token %s" % self.token.token, 'Accept': 'application/json; indent=4' })
|
||||||
|
if resp.status_code == 200:
|
||||||
|
json = resp.json()
|
||||||
|
return SeafileFile(self,path,json['id'],json['size'])
|
||||||
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s on %s by %s" % (self.name,self.client.server,self.owner)
|
return "%s on %s by %s" % (self.name,self.client.server,self.owner)
|
||||||
|
|
||||||
class SeafileFile:
|
class SeafileFile:
|
||||||
|
|
||||||
def __init__(self,library,path,id):
|
def __init__(self,library,path,id,size=0):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.path = path
|
self.path = path
|
||||||
self.library = library
|
self.library = library
|
||||||
|
self.size = size
|
||||||
|
|
||||||
#curl -v -X PUT -d "p=/foo.md" -H 'Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/afc3b694-7d4c-4b8a-86a4-89c9f3261b12/file/shared-link/
|
#curl -v -X PUT -d "p=/foo.md" -H 'Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd' -H 'Accept: application/json; indent=4' https://cloud.seafile.com/api2/repos/afc3b694-7d4c-4b8a-86a4-89c9f3261b12/file/shared-link/
|
||||||
def share(self):
|
def share(self):
|
||||||
@@ -86,6 +98,14 @@ class SeafileFile:
|
|||||||
)
|
)
|
||||||
return resp.headers.get("location")
|
return resp.headers.get("location")
|
||||||
|
|
||||||
|
def update(self,file):
|
||||||
|
def obtain_link():
|
||||||
|
#curl -H "Authorization: Token f2210dacd9c6ccb8133606d94ff8e61d99b477fd" https://cloud.seafile.com/api2/repos/99b758e6-91ab-4265-b705-925367374cf0/upload-link/
|
||||||
|
quoted = requests.get("%s/update-link" % self.library.api_endpoint(), headers = {'Authorization': "Token %s" % self.library.client.token.token,}).text
|
||||||
|
return quoted[1:-1]
|
||||||
|
directory, name = os.path.split(self.path)
|
||||||
|
return self.library.upload(file,name,directory,obtain_link())
|
||||||
|
|
||||||
class SeafileToken:
|
class SeafileToken:
|
||||||
|
|
||||||
def __init__(self,username,token):
|
def __init__(self,username,token):
|
||||||
|
|||||||
Reference in New Issue
Block a user