updated pycrypto
This commit is contained in:
parent
fb89f1946b
commit
26579a25f1
@ -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())
|
||||||
|
BIN
modules/Crypto/Cipher/_AES.so
Executable file
BIN
modules/Crypto/Cipher/_AES.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_ARC2.so
Executable file
BIN
modules/Crypto/Cipher/_ARC2.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_ARC4.so
Executable file
BIN
modules/Crypto/Cipher/_ARC4.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_Blowfish.so
Executable file
BIN
modules/Crypto/Cipher/_Blowfish.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_CAST.so
Executable file
BIN
modules/Crypto/Cipher/_CAST.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_DES.so
Executable file
BIN
modules/Crypto/Cipher/_DES.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_DES3.so
Executable file
BIN
modules/Crypto/Cipher/_DES3.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Cipher/_XOR.so
Executable file
BIN
modules/Crypto/Cipher/_XOR.so
Executable file
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,21 +150,12 @@ 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,
|
|
||||||
MODE_CFB,
|
|
||||||
b('\x00')*self.block_size, # IV for CFB
|
b('\x00')*self.block_size, # IV for CFB
|
||||||
segment_size=self.block_size*8)
|
segment_size=self.block_size*8)
|
||||||
|
|
||||||
@ -554,8 +169,7 @@ class BlockAlgo:
|
|||||||
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]:
|
||||||
@ -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.
|
||||||
@ -709,8 +226,7 @@ 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",
|
||||||
@ -725,99 +241,46 @@ 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",
|
||||||
@ -829,208 +292,5 @@ class BlockAlgo:
|
|||||||
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.
|
||||||
|
|
||||||
|
91
modules/Crypto/Hash/MD2.py
Normal file
91
modules/Crypto/Hash/MD2.py
Normal file
@ -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
|
||||||
|
|
91
modules/Crypto/Hash/MD4.py
Normal file
91
modules/Crypto/Hash/MD4.py
Normal file
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
95
modules/Crypto/Hash/SHA224.py
Normal file
95
modules/Crypto/Hash/SHA224.py
Normal file
@ -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
|
||||||
|
|
95
modules/Crypto/Hash/SHA256.py
Normal file
95
modules/Crypto/Hash/SHA256.py
Normal file
@ -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
|
||||||
|
|
96
modules/Crypto/Hash/SHA384.py
Normal file
96
modules/Crypto/Hash/SHA384.py
Normal file
@ -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
|
||||||
|
|
||||||
|
|
95
modules/Crypto/Hash/SHA512.py
Normal file
95
modules/Crypto/Hash/SHA512.py
Normal file
@ -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
|
||||||
|
|
BIN
modules/Crypto/Hash/_MD2.so
Executable file
BIN
modules/Crypto/Hash/_MD2.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_MD4.so
Executable file
BIN
modules/Crypto/Hash/_MD4.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_RIPEMD160.so
Executable file
BIN
modules/Crypto/Hash/_RIPEMD160.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_SHA224.so
Executable file
BIN
modules/Crypto/Hash/_SHA224.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_SHA256.so
Executable file
BIN
modules/Crypto/Hash/_SHA256.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_SHA384.so
Executable file
BIN
modules/Crypto/Hash/_SHA384.so
Executable file
Binary file not shown.
BIN
modules/Crypto/Hash/_SHA512.so
Executable file
BIN
modules/Crypto/Hash/_SHA512.so
Executable file
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
|
|
||||||
|
116
modules/Crypto/Hash/hashalgo.py
Normal file
116
modules/Crypto/Hash/hashalgo.py
Normal file
@ -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):
|
||||||
|
@ -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,112 +539,134 @@ 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
|
|
||||||
# q^{-1} mod p
|
|
||||||
der.append(inverse(der[4],der[5])) # Add p^{-1} mod q
|
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.
|
|
||||||
# 'subjectPublicKey' encapsulates the actual ASN.1
|
|
||||||
# RSAPublicKey element.
|
|
||||||
if der[0]==algorithmIdentifier:
|
if der[0]==algorithmIdentifier:
|
||||||
bitmap = decode_der(DerBitString, der[1])
|
bitmap = DerObject()
|
||||||
rsaPub = decode_der(DerSequence, bitmap.value)
|
bitmap.decode(der[1], True)
|
||||||
if len(rsaPub) == 2 and rsaPub.hasOnlyInts():
|
if bitmap.isType('BIT STRING') and bord(bitmap.payload[0])==0x00:
|
||||||
return self.construct(rsaPub[:])
|
der.decode(bitmap.payload[1:], True)
|
||||||
except (ValueError, EOFError):
|
if len(der)==2 and der.hasOnlyInts():
|
||||||
pass
|
return self.construct(der[:])
|
||||||
|
|
||||||
# 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]
|
||||||
@ -686,25 +675,23 @@ class RSAImplementation(object):
|
|||||||
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
|
||||||
|
73
modules/Crypto/SelfTest/Hash/test_RIPEMD.py
Normal file
73
modules/Crypto/SelfTest/Hash/test_RIPEMD.py
Normal file
@ -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:
|
64
modules/Crypto/SelfTest/Hash/test_SHA.py
Normal file
64
modules/Crypto/SelfTest/Hash/test_SHA.py
Normal file
@ -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)
|
||||||
|
345
modules/Crypto/SelfTest/PublicKey/test_importKey.py
Normal file
345
modules/Crypto/SelfTest/PublicKey/test_importKey.py
Normal file
@ -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$"
|
||||||
|
|
||||||
|
BIN
modules/Crypto/Util/_counter.so
Executable file
BIN
modules/Crypto/Util/_counter.so
Executable file
Binary file not shown.
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:
|
||||||
|
BIN
modules/Crypto/Util/strxor.so
Executable file
BIN
modules/Crypto/Util/strxor.so
Executable file
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"""
|
||||||
|
|
||||||
|
199
modules/encryptedscreenshot.py
Normal file
199
modules/encryptedscreenshot.py
Normal file
@ -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()
|
@ -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):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user