updated pycrypto

This commit is contained in:
shim_ 2018-05-10 16:56:32 +02:00
parent fb89f1946b
commit 26579a25f1
92 changed files with 2518 additions and 5288 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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.

View File

@ -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

Binary file not shown.

BIN
modules/Crypto/Cipher/_ARC2.so Executable file

Binary file not shown.

BIN
modules/Crypto/Cipher/_ARC4.so Executable file

Binary file not shown.

Binary file not shown.

BIN
modules/Crypto/Cipher/_CAST.so Executable file

Binary file not shown.

BIN
modules/Crypto/Cipher/_DES.so Executable file

Binary file not shown.

BIN
modules/Crypto/Cipher/_DES3.so Executable file

Binary file not shown.

BIN
modules/Crypto/Cipher/_XOR.so Executable file

Binary file not shown.

View File

@ -24,21 +24,8 @@
import sys import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1: if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import * from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import * from Crypto.Util.py3compat import *
from binascii import unhexlify
from Crypto.Util import Counter
from Crypto.Util.strxor import strxor
from Crypto.Util.number import long_to_bytes, bytes_to_long
import Crypto.Util.Counter
from Crypto.Hash import CMAC
from Crypto.Hash.CMAC import _SmoothMAC
from Crypto.Protocol.KDF import _S2V
from Crypto.Util import galois
#: *Electronic Code Book (ECB)*. #: *Electronic Code Book (ECB)*.
#: This is the simplest encryption mode. Each of the plaintext blocks #: This is the simplest encryption mode. Each of the plaintext blocks
#: is directly encrypted into a ciphertext block, independently of #: is directly encrypted into a ciphertext block, independently of
@ -55,8 +42,8 @@ MODE_ECB = 1
#: (*IV*) is required. #: (*IV*) is required.
#: #:
#: The *IV* is a data block to be transmitted to the receiver. #: The *IV* is a data block to be transmitted to the receiver.
#: The *IV* can be made public, but it must be authenticated by the receiver #: The *IV* can be made public, but it must be authenticated by the receiver and
#: and it should be picked randomly. #: it should be picked randomly.
#: #:
#: See `NIST SP800-38A`_ , Section 6.2 . #: See `NIST SP800-38A`_ , Section 6.2 .
#: #:
@ -86,8 +73,7 @@ MODE_PGP = 4
#: *Output FeedBack (OFB)*. This mode is very similar to CBC, but it #: *Output FeedBack (OFB)*. This mode is very similar to CBC, but it
#: transforms the underlying block cipher into a stream cipher. #: transforms the underlying block cipher into a stream cipher.
#: The keystream is the iterated block encryption of an #: The keystream is the iterated block encryption of an Initialization Vector (*IV*).
#: Initialization Vector (*IV*).
#: #:
#: The *IV* is a data block to be transmitted to the receiver. #: The *IV* is a data block to be transmitted to the receiver.
#: The *IV* can be made public, but it should be picked randomly. #: The *IV* can be made public, but it should be picked randomly.
@ -124,399 +110,37 @@ MODE_OFB = 5
#: .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf #: .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
MODE_CTR = 6 MODE_CTR = 6
#: *OpenPGP CFB*. This mode is a variant of CFB, and it is only used in PGP and #: OpenPGP. This mode is a variant of CFB, and it is only used in PGP and OpenPGP_ applications.
#: OpenPGP_ applications. An Initialization Vector (*IV*) is required. #: An Initialization Vector (*IV*) is required.
#: #:
#: Unlike CFB, the IV is not transmitted to the receiver. #: Unlike CFB, the IV is not transmitted to the receiver. Instead, the *encrypted* IV is.
#: Instead, the *encrypted* IV is. #: The IV is a random data block. Two of its bytes are duplicated to act as a checksum
#: The IV is a random data block. Two of its bytes are duplicated to act #: for the correctness of the key. The encrypted IV is therefore 2 bytes longer than
#: as a checksum for the correctness of the key. The encrypted IV is #: the clean IV.
#: therefore 2 bytes longer than the clean IV.
#: #:
#: .. _OpenPGP: http://tools.ietf.org/html/rfc4880 #: .. _OpenPGP: http://tools.ietf.org/html/rfc4880
MODE_OPENPGP = 7 MODE_OPENPGP = 7
#: *Counter with CBC-MAC (CCM)*. This is an Authenticated Encryption with
#: Associated Data (`AEAD`_) mode. It provides both confidentiality and
#: authenticity.
#: The header of the message may be left in the clear, if needed, and it will
#: still be subject to authentication. The decryption step tells the receiver
#: if the message comes from a source that really knowns the secret key.
#: Additionally, decryption detects if any part of the message - including the
#: header - has been modified or corrupted.
#:
#: This mode requires a nonce. The nonce shall never repeat for two
#: different messages encrypted with the same key, but it does not need
#: to be random.
#: Note that there is a trade-off between the size of the nonce and the
#: maximum size of a single message you can encrypt.
#:
#: It is important to use a large nonce if the key is reused across several
#: messages and the nonce is chosen randomly.
#:
#: It is acceptable to us a short nonce if the key is only used a few times or
#: if the nonce is taken from a counter.
#:
#: The following table shows the trade-off when the nonce is chosen at
#: random. The column on the left shows how many messages it takes
#: for the keystream to repeat **on average**. In practice, you will want to
#: stop using the key way before that.
#:
#: +--------------------+---------------+-------------------+
#: | Avg. # of messages | nonce | Max. message |
#: | before keystream | size | size |
#: | repeats | (bytes) | (bytes) |
#: +====================+===============+===================+
#: | 2**52 | 13 | 64K |
#: +--------------------+---------------+-------------------+
#: | 2**48 | 12 | 16M |
#: +--------------------+---------------+-------------------+
#: | 2**44 | 11 | 4G |
#: +--------------------+---------------+-------------------+
#: | 2**40 | 10 | 1T |
#: +--------------------+---------------+-------------------+
#: | 2**36 | 9 | 64P |
#: +--------------------+---------------+-------------------+
#: | 2**32 | 8 | 16E |
#: +--------------------+---------------+-------------------+
#:
#: This mode is only available for ciphers that operate on 128 bits blocks
#: (e.g. AES but not TDES).
#:
#: See `NIST SP800-38C`_ or RFC3610_ .
#:
#: .. _`NIST SP800-38C`: http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C.pdf
#: .. _RFC3610: https://tools.ietf.org/html/rfc3610
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
MODE_CCM = 8
#: *EAX*. This is an Authenticated Encryption with Associated Data
#: (`AEAD`_) mode. It provides both confidentiality and authenticity.
#:
#: The header of the message may be left in the clear, if needed, and it will
#: still be subject to authentication.
#:
#: The decryption step tells the receiver if the message comes from a source
#: that really knowns the secret key.
#: Additionally, decryption detects if any part of the message - including the
#: header - has been modified or corrupted.
#:
#: This mode requires a nonce. The nonce shall never repeat for two
#: different messages encrypted with the same key, but it does not need to
#: be random.
#
#: This mode is only available for ciphers that operate on 64 or
#: 128 bits blocks.
#:
#: There are no official standards defining EAX. The implementation is based on
#: `a proposal`__ that was presented to NIST.
#:
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
#: .. __: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf
MODE_EAX = 9
#: *Synthetic Initialization Vector*. This is an Authenticated Encryption with
#: Associated Data (`AEAD`_) mode. It provides both confidentiality and
#: authenticity.
#: The header of the message may be left in the clear, if needed, and it will
#: still be subject to authentication. The decryption step tells the receiver
#: if the message comes from a source that really knowns the secret key.
#: Additionally, decryption detects if any part of the message - including the
#: header - has been modified or corrupted.
#:
#: If the data being encrypted is completely unpredictable to an adversary
#: (e.g. a secret key, for key wrapping purposes) a nonce is not strictly
#: required.
#:
#: Otherwise, a nonce has to be provided; the nonce shall never repeat
#: for two different messages encrypted with the same key, but it does not
#: need to be random.
#:
#: Unlike other AEAD modes such as CCM, EAX or GCM, accidental reuse of a
#: nonce is not catastrophic for the confidentiality of the message. The only
#: effect is that an attacker can tell when the same plaintext (and same
#: associated data) is protected with the same key.
#:
#: The length of the MAC is fixed to the block size of the underlying cipher.
#: The key size is twice the length of the key of the underlying cipher.
#:
#: This mode is only available for AES ciphers.
#:
#: +--------------------+---------------+-------------------+
#: | Cipher | SIV MAC size | SIV key length |
#: | | (bytes) | (bytes) |
#: +====================+===============+===================+
#: | AES-128 | 16 | 32 |
#: +--------------------+---------------+-------------------+
#: | AES-192 | 16 | 48 |
#: +--------------------+---------------+-------------------+
#: | AES-256 | 16 | 64 |
#: +--------------------+---------------+-------------------+
#:
#: See `RFC5297`_ and the `original paper`__.
#:
#: .. _RFC5297: https://tools.ietf.org/html/rfc5297
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
#: .. __: http://www.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf
MODE_SIV = 10
#: *Galois/Counter Mode (GCM)*. This is an Authenticated Encryption with
#: Associated Data (`AEAD`_) mode. It provides both confidentiality and
#: authenticity.
#: The header of the message may be left in the clear, if needed, and it will
#: still be subject to authentication. The decryption step tells the receiver
#: if the message comes from a source that really knowns the secret key.
#: Additionally, decryption detects if any part of the message - including the
#: header - has been modified or corrupted.
#:
#: This mode requires a nonce. The nonce shall never repeat for two
#: different messages encrypted with the same key, but it does not need to
#: be random.
#:
#: This mode is only available for ciphers that operate on 128 bits blocks
#: (e.g. AES but not TDES).
#:
#: See `NIST SP800-38D`_ .
#:
#: .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
#: .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html
MODE_GCM = 11
def _getParameter(name, index, args, kwargs, default=None): def _getParameter(name, index, args, kwargs, default=None):
"""Find a parameter in tuple and dictionary arguments a function receives""" """Find a parameter in tuple and dictionary arguments a function receives"""
param = kwargs.get(name) param = kwargs.get(name)
if len(args) > index: if len(args)>index:
if param: if param:
raise TypeError("Parameter '%s' is specified twice" % name) raise ValueError("Parameter '%s' is specified twice" % name)
param = args[index] param = args[index]
return param or default return param or default
class _CBCMAC(_SmoothMAC):
def __init__(self, key, ciphermod):
_SmoothMAC.__init__(self, ciphermod.block_size, None, 0)
self._key = key
self._factory = ciphermod
def _ignite(self, data):
if self._mac:
raise TypeError("_ignite() cannot be called twice")
self._buffer.insert(0, data)
self._buffer_len += len(data)
self._mac = self._factory.new(self._key, MODE_CBC, bchr(0) * 16)
self.update(b(""))
def _update(self, block_data):
self._t = self._mac.encrypt(block_data)[-16:]
def _digest(self, left_data):
return self._t
class _GHASH(_SmoothMAC):
"""GHASH function defined in NIST SP 800-38D, Algorithm 2.
If X_1, X_2, .. X_m are the blocks of input data, the function
computes:
X_1*H^{m} + X_2*H^{m-1} + ... + X_m*H
in the Galois field GF(2^256) using the reducing polynomial
(x^128 + x^7 + x^2 + x + 1).
"""
def __init__(self, hash_subkey, block_size, table_size='64K'):
_SmoothMAC.__init__(self, block_size, None, 0)
if table_size == '64K':
self._hash_subkey = galois._ghash_expand(hash_subkey)
else:
self._hash_subkey = hash_subkey
self._last_y = bchr(0) * 16
self._mac = galois._ghash
def copy(self):
clone = _GHASH(self._hash_subkey, self._bs, table_size='0K')
_SmoothMAC._deep_copy(self, clone)
clone._last_y = self._last_y
return clone
def _update(self, block_data):
self._last_y = galois._ghash(block_data, self._last_y,
self._hash_subkey)
def _digest(self, left_data):
return self._last_y
class BlockAlgo: class BlockAlgo:
"""Class modelling an abstract block cipher.""" """Class modelling an abstract block cipher."""
def __init__(self, factory, key, *args, **kwargs): def __init__(self, factory, key, *args, **kwargs):
self.mode = _getParameter('mode', 0, args, kwargs, default=MODE_ECB) self.mode = _getParameter('mode', 0, args, kwargs, default=MODE_ECB)
self.block_size = factory.block_size self.block_size = factory.block_size
self._factory = factory
self._tag = None
if self.mode == MODE_CCM: if self.mode != MODE_OPENPGP:
if self.block_size != 16:
raise TypeError("CCM mode is only available for ciphers that operate on 128 bits blocks")
self._mac_len = kwargs.get('mac_len', 16) # t
if self._mac_len not in (4, 6, 8, 10, 12, 14, 16):
raise ValueError("Parameter 'mac_len' must be even and in the range 4..16")
self.nonce = _getParameter('nonce', 1, args, kwargs) # N
if not (self.nonce and 7 <= len(self.nonce) <= 13):
raise ValueError("Length of parameter 'nonce' must be"
" in the range 7..13 bytes")
self._key = key
self._msg_len = kwargs.get('msg_len', None) # p
self._assoc_len = kwargs.get('assoc_len', None) # a
self._cipherMAC = _CBCMAC(key, factory)
self._done_assoc_data = False # True when all associated data
# has been processed
# Allowed transitions after initialization
self._next = [self.update, self.encrypt, self.decrypt,
self.digest, self.verify]
# Try to start CCM
self._start_ccm()
elif self.mode == MODE_OPENPGP:
self._start_PGP(factory, key, *args, **kwargs)
elif self.mode == MODE_EAX:
self._start_eax(factory, key, *args, **kwargs)
elif self.mode == MODE_SIV:
self._start_siv(factory, key, *args, **kwargs)
elif self.mode == MODE_GCM:
self._start_gcm(factory, key, *args, **kwargs)
else:
self._cipher = factory.new(key, *args, **kwargs) self._cipher = factory.new(key, *args, **kwargs)
self.IV = self._cipher.IV self.IV = self._cipher.IV
def _start_gcm(self, factory, key, *args, **kwargs):
if self.block_size != 16:
raise TypeError("GCM mode is only available for ciphers that operate on 128 bits blocks")
self.nonce = _getParameter('nonce', 1, args, kwargs)
if not self.nonce:
raise TypeError("MODE_GCM requires a nonce")
self._mac_len = kwargs.get('mac_len', 16)
if not (self._mac_len and 4 <= self._mac_len <= 16):
raise ValueError("Parameter 'mac_len' must not be larger than 16 bytes")
# Allowed transitions after initialization
self._next = [self.update, self.encrypt, self.decrypt,
self.digest, self.verify]
self._done_assoc_data = False
# Length of the ciphertext or plaintext
self._msg_len = 0
# Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H
# See also Algorithm 5 (decryption)
hash_subkey = factory.new(key).encrypt(bchr(0) * 16)
# Step 2 - Compute J0 (integer, not byte string!)
if len(self.nonce) == 12:
self._j0 = bytes_to_long(self.nonce + b("\x00\x00\x00\x01"))
else: else:
fill = (16 - (len(self.nonce) % 16)) % 16 + 8
ghash_in = (self.nonce +
bchr(0) * fill +
long_to_bytes(8 * len(self.nonce), 8))
mac = _GHASH(hash_subkey, factory.block_size, '0K')
mac.update(ghash_in)
self._j0 = bytes_to_long(mac.digest())
# Step 3 - Prepare GCTR cipher for encryption/decryption
ctr = Counter.new(128, initial_value=self._j0 + 1,
allow_wraparound=True)
self._cipher = self._factory.new(key, MODE_CTR, counter=ctr)
# Step 5 - Bootstrat GHASH
self._cipherMAC = _GHASH(hash_subkey, factory.block_size, '64K')
# Step 6 - Prepare GCTR cipher for GMAC
ctr = Counter.new(128, initial_value=self._j0, allow_wraparound=True)
self._tag_cipher = self._factory.new(key, MODE_CTR, counter=ctr)
def _start_siv(self, factory, key, *args, **kwargs):
subkey_size, rem = divmod(len(key), 2)
if rem:
raise ValueError("MODE_SIV requires a key twice as long as for the underlying cipher")
# IV is optional
self.nonce = _getParameter('nonce', 1, args, kwargs)
self._cipherMAC = _S2V(key[:subkey_size], ciphermod=factory)
self._subkey_ctr = key[subkey_size:]
self._mac_len = factory.block_size
self._cipherMAC = self._cipherMAC
# Allowed transitions after initialization
self._next = [self.update, self.encrypt, self.decrypt,
self.digest, self.verify]
def _siv_ctr_cipher(self, tag):
"""Create a new CTR cipher from the MAC in SIV mode"""
tag_int = bytes_to_long(tag)
init_counter = tag_int ^ (tag_int & 0x8000000080000000L)
ctr = Counter.new(self._factory.block_size * 8,
initial_value=init_counter,
allow_wraparound=True)
return self._factory.new(self._subkey_ctr, MODE_CTR, counter=ctr)
def _start_eax(self, factory, key, *args, **kwargs):
self.nonce = _getParameter('nonce', 1, args, kwargs)
if not self.nonce:
raise TypeError("MODE_EAX requires a nonce")
# Allowed transitions after initialization
self._next = [self.update, self.encrypt, self.decrypt,
self.digest, self.verify]
self._mac_len = kwargs.get('mac_len', self.block_size)
if not (self._mac_len and 4 <= self._mac_len <= self.block_size):
raise ValueError("Parameter 'mac_len' must not be larger than %d"
% self.block_size)
self._omac = [
CMAC.new(key, bchr(0) * (self.block_size - 1) + bchr(i),
ciphermod=factory)
for i in xrange(0, 3)
]
# Compute MAC of nonce
self._omac[0].update(self.nonce)
self._cipherMAC = self._omac[1]
# MAC of the nonce is also the initial counter for CTR encryption
counter_int = bytes_to_long(self._omac[0].digest())
counter_obj = Crypto.Util.Counter.new(
self.block_size * 8,
initial_value=counter_int,
allow_wraparound=True)
self._cipher = factory.new(key, MODE_CTR, counter=counter_obj)
def _start_PGP(self, factory, key, *args, **kwargs):
# OPENPGP mode. For details, see 13.9 in RCC4880. # OPENPGP mode. For details, see 13.9 in RCC4880.
# #
# A few members are specifically created for this mode: # A few members are specifically created for this mode:
@ -526,38 +150,28 @@ class BlockAlgo:
self._done_first_block = False self._done_first_block = False
self._done_last_block = False self._done_last_block = False
self.IV = _getParameter('IV', 1, args, kwargs)
if self.IV is None:
# TODO: Decide whether 'IV' or 'iv' should be used going forward,
# and deprecate the other. 'IV' is consistent with the rest of
# PyCrypto, but 'iv' is more common in Python generally. For now,
# we'll support both here. When in doubt, use a positional
# parameter for now.
self.IV = _getParameter('iv', 1, args, kwargs) self.IV = _getParameter('iv', 1, args, kwargs)
if not self.IV: if not self.IV:
raise ValueError("MODE_OPENPGP requires an IV") raise ValueError("MODE_OPENPGP requires an IV")
# Instantiate a temporary cipher to process the IV # Instantiate a temporary cipher to process the IV
IV_cipher = factory.new( IV_cipher = factory.new(key, MODE_CFB,
key, b('\x00')*self.block_size, # IV for CFB
MODE_CFB, segment_size=self.block_size*8)
b('\x00') * self.block_size, # IV for CFB
segment_size=self.block_size * 8)
# The cipher will be used for... # The cipher will be used for...
if len(self.IV) == self.block_size: if len(self.IV) == self.block_size:
# ... encryption # ... encryption
self._encrypted_IV = IV_cipher.encrypt( self._encrypted_IV = IV_cipher.encrypt(
self.IV + self.IV[-2:] + # Plaintext self.IV + self.IV[-2:] + # Plaintext
b('\x00') * (self.block_size - 2) # Padding b('\x00')*(self.block_size-2) # Padding
)[:self.block_size + 2] )[:self.block_size+2]
elif len(self.IV) == self.block_size + 2: elif len(self.IV) == self.block_size+2:
# ... decryption # ... decryption
self._encrypted_IV = self.IV self._encrypted_IV = self.IV
self.IV = IV_cipher.decrypt( self.IV = IV_cipher.decrypt(self.IV + # Ciphertext
self.IV + # Ciphertext b('\x00')*(self.block_size-2) # Padding
b('\x00') * (self.block_size - 2) # Padding )[:self.block_size+2]
)[:self.block_size + 2]
if self.IV[-2:] != self.IV[-4:-2]: if self.IV[-2:] != self.IV[-4:-2]:
raise ValueError("Failed integrity check for OPENPGP IV") raise ValueError("Failed integrity check for OPENPGP IV")
self.IV = self.IV[:-2] self.IV = self.IV[:-2]
@ -566,132 +180,35 @@ class BlockAlgo:
% (self.block_size, self.block_size+2)) % (self.block_size, self.block_size+2))
# Instantiate the cipher for the real PGP data # Instantiate the cipher for the real PGP data
self._cipher = factory.new( self._cipher = factory.new(key, MODE_CFB,
key,
MODE_CFB,
self._encrypted_IV[-self.block_size:], self._encrypted_IV[-self.block_size:],
segment_size=self.block_size * 8 segment_size=self.block_size*8)
)
def _start_ccm(self, assoc_len=None, msg_len=None):
# CCM mode. This method creates the 2 ciphers used for the MAC
# (self._cipherMAC) and for the encryption/decryption (self._cipher).
#
# Member _assoc_buffer may already contain user data that needs to be
# authenticated.
if self._cipherMAC.can_reduce():
# Already started
return
if assoc_len is not None:
self._assoc_len = assoc_len
if msg_len is not None:
self._msg_len = msg_len
if None in (self._assoc_len, self._msg_len):
return
# q is the length of Q, the encoding of the message length
q = 15 - len(self.nonce)
## Compute B_0
flags = (
64 * (self._assoc_len > 0) +
8 * divmod(self._mac_len - 2, 2)[0] +
(q - 1)
)
b_0 = bchr(flags) + self.nonce + long_to_bytes(self._msg_len, q)
# Start CBC MAC with zero IV
assoc_len_encoded = b('')
if self._assoc_len > 0:
if self._assoc_len < (2 ** 16 - 2 ** 8):
enc_size = 2
elif self._assoc_len < (2L ** 32):
assoc_len_encoded = b('\xFF\xFE')
enc_size = 4
else:
assoc_len_encoded = b('\xFF\xFF')
enc_size = 8
assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size)
self._cipherMAC._ignite(b_0 + assoc_len_encoded)
# Start CTR cipher
prefix = bchr(q - 1) + self.nonce
ctr = Counter.new(128 - len(prefix) * 8, prefix, initial_value=0)
self._cipher = self._factory.new(self._key, MODE_CTR, counter=ctr)
# Will XOR against CBC MAC
self._s_0 = self._cipher.encrypt(bchr(0) * 16)
def update(self, assoc_data):
"""Protect associated data
When using an AEAD mode like CCM, EAX, GCM or SIV, and
if there is any associated data, the caller has to invoke
this function one or more times, before using
``decrypt`` or ``encrypt``.
By *associated data* it is meant any data (e.g. packet headers) that
will not be encrypted and will be transmitted in the clear.
However, the receiver is still able to detect any modification to it.
In CCM and GCM, the *associated data* is also called
*additional authenticated data* (AAD).
In EAX, the *associated data* is called *header*.
If there is no associated data, this method must not be called.
The caller may split associated data in segments of any size, and
invoke this method multiple times, each time with the next segment.
:Parameters:
assoc_data : byte string
A piece of associated data. There are no restrictions on its size.
"""
if self.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
raise TypeError("update() not supported by this mode of operation")
if self.update not in self._next:
raise TypeError("update() can only be called immediately after initialization")
self._next = [self.update, self.encrypt, self.decrypt,
self.digest, self.verify]
return self._cipherMAC.update(assoc_data)
def encrypt(self, plaintext): def encrypt(self, plaintext):
"""Encrypt data with the key and the parameters set at initialization. """Encrypt data with the key and the parameters set at initialization.
A cipher object is stateful: once you have encrypted a message The cipher object is stateful; encryption of a long block
you cannot encrypt (or decrypt) another message using the same of data can be broken up in two or more calls to `encrypt()`.
object.
For `MODE_SIV` (always) and `MODE_CCM` (when ``msg_len`` was not
passed at initialization), this method can be called only **once**.
For all other modes, the data to encrypt can be broken up in two or
more pieces and `encrypt` can be called multiple times.
That is, the statement: That is, the statement:
>>> c.encrypt(a) + c.encrypt(b) >>> c.encrypt(a) + c.encrypt(b)
is equivalent to: is always equivalent to:
>>> c.encrypt(a+b) >>> c.encrypt(a+b)
That also means that you cannot reuse an object for encrypting That also means that you cannot reuse an object for encrypting
or decrypting other data with the same key. or decrypting other data with the same key.
This function does not add any padding to the plaintext. This function does not perform any padding.
- For `MODE_ECB` and `MODE_CBC`, *plaintext* length (in bytes) must be - For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *plaintext* length
a multiple of *block_size*. (in bytes) must be a multiple of *block_size*.
- For `MODE_CFB`, *plaintext* length (in bytes) must be a multiple - For `MODE_CFB`, *plaintext* length (in bytes) must be a multiple
of *segment_size*/8. of *segment_size*/8.
- For `MODE_OFB`, `MODE_CTR` and all AEAD modes - For `MODE_CTR`, *plaintext* can be of any length.
*plaintext* can be of any length.
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*, - For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
unless it is the last chunk of the message. unless it is the last chunk of the message.
@ -708,15 +225,14 @@ class BlockAlgo:
if self.mode == MODE_OPENPGP: if self.mode == MODE_OPENPGP:
padding_length = (self.block_size - len(plaintext) % self.block_size) % self.block_size padding_length = (self.block_size - len(plaintext) % self.block_size) % self.block_size
if padding_length > 0: if padding_length>0:
# CFB mode requires ciphertext to have length multiple # CFB mode requires ciphertext to have length multiple of block size,
# of block size,
# but PGP mode allows the last block to be shorter # but PGP mode allows the last block to be shorter
if self._done_last_block: if self._done_last_block:
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes", raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
self.block_size) self.block_size)
self._done_last_block = True self._done_last_block = True
padded = plaintext + b('\x00') * padding_length padded = plaintext + b('\x00')*padding_length
res = self._cipher.encrypt(padded)[:len(plaintext)] res = self._cipher.encrypt(padded)[:len(plaintext)]
else: else:
res = self._cipher.encrypt(plaintext) res = self._cipher.encrypt(plaintext)
@ -725,312 +241,56 @@ class BlockAlgo:
self._done_first_block = True self._done_first_block = True
return res return res
if self.mode in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM): return self._cipher.encrypt(plaintext)
if self.encrypt not in self._next:
raise TypeError("encrypt() can only be called after initialization or an update()")
self._next = [self.encrypt, self.digest]
if self.mode == MODE_CCM:
if self._assoc_len is None:
self._start_ccm(assoc_len=self._cipherMAC.get_len())
if self._msg_len is None:
self._start_ccm(msg_len=len(plaintext))
self._next = [self.digest]
if not self._done_assoc_data:
self._cipherMAC.zero_pad()
self._done_assoc_data = True
self._cipherMAC.update(plaintext)
if self.mode == MODE_SIV:
self._next = [self.digest]
if self.nonce:
self._cipherMAC.update(self.nonce)
self._cipherMAC.update(plaintext)
self._cipher = self._siv_ctr_cipher(self._cipherMAC.derive())
ct = self._cipher.encrypt(plaintext)
if self.mode == MODE_EAX:
self._omac[2].update(ct)
if self.mode == MODE_GCM:
if not self._done_assoc_data:
self._cipherMAC.zero_pad()
self._done_assoc_data = True
self._cipherMAC.update(ct)
self._msg_len += len(plaintext)
return ct
def decrypt(self, ciphertext): def decrypt(self, ciphertext):
"""Decrypt data with the key and the parameters set at initialization. """Decrypt data with the key and the parameters set at initialization.
A cipher object is stateful: once you have decrypted a message The cipher object is stateful; decryption of a long block
you cannot decrypt (or encrypt) another message with the same of data can be broken up in two or more calls to `decrypt()`.
object.
For `MODE_SIV` (always) and `MODE_CCM` (when ``msg_len`` was not
passed at initialization), this method can be called only **once**.
For all other modes, the data to decrypt can be broken up in two or
more pieces and `decrypt` can be called multiple times.
That is, the statement: That is, the statement:
>>> c.decrypt(a) + c.decrypt(b) >>> c.decrypt(a) + c.decrypt(b)
is equivalent to: is always equivalent to:
>>> c.decrypt(a+b) >>> c.decrypt(a+b)
That also means that you cannot reuse an object for encrypting That also means that you cannot reuse an object for encrypting
or decrypting other data with the same key. or decrypting other data with the same key.
This function does not remove any padding from the plaintext. This function does not perform any padding.
- For `MODE_ECB` and `MODE_CBC`, *ciphertext* length (in bytes) must - For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *ciphertext* length
be a multiple of *block_size*. (in bytes) must be a multiple of *block_size*.
- For `MODE_CFB`, *ciphertext* length (in bytes) must be a multiple - For `MODE_CFB`, *ciphertext* length (in bytes) must be a multiple
of *segment_size*/8. of *segment_size*/8.
- For `MODE_OFB`, `MODE_CTR` and all AEAD modes - For `MODE_CTR`, *ciphertext* can be of any length.
*ciphertext* can be of any length.
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*, - For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
unless it is the last chunk of the message. unless it is the last chunk of the message.
- For `MODE_SIV`, *ciphertext* can be of any length, but it must also
include the MAC (concatenated at the end).
:Parameters: :Parameters:
ciphertext : byte string ciphertext : byte string
The piece of data to decrypt (plus the MAC, for `MODE_SIV` only). The piece of data to decrypt.
:Return: the decrypted data (byte string, as long as *ciphertext*).
:Return: the decrypted data (byte string).
""" """
if self.mode == MODE_OPENPGP: if self.mode == MODE_OPENPGP:
padding_length = (self.block_size - len(ciphertext) % self.block_size) % self.block_size padding_length = (self.block_size - len(ciphertext) % self.block_size) % self.block_size
if padding_length > 0: if padding_length>0:
# CFB mode requires ciphertext to have length multiple # CFB mode requires ciphertext to have length multiple of block size,
# of block size,
# but PGP mode allows the last block to be shorter # but PGP mode allows the last block to be shorter
if self._done_last_block: if self._done_last_block:
raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes", raise ValueError("Only the last chunk is allowed to have length not multiple of %d bytes",
self.block_size) self.block_size)
self._done_last_block = True self._done_last_block = True
padded = ciphertext + b('\x00') * padding_length padded = ciphertext + b('\x00')*padding_length
res = self._cipher.decrypt(padded)[:len(ciphertext)] res = self._cipher.decrypt(padded)[:len(ciphertext)]
else: else:
res = self._cipher.decrypt(ciphertext) res = self._cipher.decrypt(ciphertext)
return res return res
if self.mode == MODE_SIV: return self._cipher.decrypt(ciphertext)
raise TypeError("decrypt() not allowed for SIV mode."
" Use decrypt_and_verify() instead.")
if self.mode in (MODE_CCM, MODE_EAX, MODE_GCM):
if self.decrypt not in self._next:
raise TypeError("decrypt() can only be called after initialization or an update()")
self._next = [self.decrypt, self.verify]
if self.mode == MODE_CCM:
if self._assoc_len is None:
self._start_ccm(assoc_len=self._cipherMAC.get_len())
if self._msg_len is None:
self._start_ccm(msg_len=len(ciphertext))
self._next = [self.verify]
if not self._done_assoc_data:
self._cipherMAC.zero_pad()
self._done_assoc_data = True
if self.mode == MODE_GCM:
if not self._done_assoc_data:
self._cipherMAC.zero_pad()
self._done_assoc_data = True
self._cipherMAC.update(ciphertext)
self._msg_len += len(ciphertext)
if self.mode == MODE_EAX:
self._omac[2].update(ciphertext)
pt = self._cipher.decrypt(ciphertext)
if self.mode == MODE_CCM:
self._cipherMAC.update(pt)
return pt
def digest(self):
"""Compute the *binary* MAC tag in an AEAD mode.
When using an AEAD mode like CCM or EAX, the caller invokes
this function at the very end.
This method returns the MAC that shall be sent to the receiver,
together with the ciphertext.
:Return: the MAC, as a byte string.
"""
if self.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
raise TypeError("digest() not supported by this mode of operation")
if self.digest not in self._next:
raise TypeError("digest() cannot be called when decrypting or validating a message")
self._next = [self.digest]
return self._compute_mac()
def _compute_mac(self):
"""Compute MAC without any FSM checks."""
if self._tag:
return self._tag
if self.mode == MODE_CCM:
if self._assoc_len is None:
self._start_ccm(assoc_len=self._cipherMAC.get_len())
if self._msg_len is None:
self._start_ccm(msg_len=0)
self._cipherMAC.zero_pad()
self._tag = strxor(self._cipherMAC.digest(),
self._s_0)[:self._mac_len]
if self.mode == MODE_GCM:
# Step 5 in NIST SP 800-38D, Algorithm 4 - Compute S
self._cipherMAC.zero_pad()
auth_len = self._cipherMAC.get_len() - self._msg_len
for tlen in (auth_len, self._msg_len):
self._cipherMAC.update(long_to_bytes(8 * tlen, 8))
s_tag = self._cipherMAC.digest()
# Step 6 - Compute T
self._tag = self._tag_cipher.encrypt(s_tag)[:self._mac_len]
if self.mode == MODE_EAX:
tag = bchr(0) * self.block_size
for i in xrange(3):
tag = strxor(tag, self._omac[i].digest())
self._tag = tag[:self._mac_len]
if self.mode == MODE_SIV:
self._tag = self._cipherMAC.derive()
return self._tag
def hexdigest(self):
"""Compute the *printable* MAC tag in an AEAD mode.
This method is like `digest`.
:Return: the MAC, as a hexadecimal string.
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def verify(self, mac_tag):
"""Validate the *binary* MAC tag in an AEAD mode.
When using an AEAD mode like CCM or EAX, the caller invokes
this function at the very end.
This method checks if the decrypted message is indeed valid
(that is, if the key is correct) and it has not been
tampered with while in transit.
:Parameters:
mac_tag : byte string
This is the *binary* MAC, as received from the sender.
:Raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
if self.mode not in (MODE_CCM, MODE_EAX, MODE_SIV, MODE_GCM):
raise TypeError("verify() not supported by this mode of operation")
if self.verify not in self._next:
raise TypeError("verify() cannot be called when encrypting a message")
self._next = [self.verify]
res = 0
# Constant-time comparison
for x, y in zip(self._compute_mac(), mac_tag):
res |= bord(x) ^ bord(y)
if res or len(mac_tag) != self._mac_len:
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Validate the *printable* MAC tag in an AEAD mode.
This method is like `verify`.
:Parameters:
hex_mac_tag : string
This is the *printable* MAC, as received from the sender.
:Raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
self.verify(unhexlify(hex_mac_tag))
def encrypt_and_digest(self, plaintext):
"""Perform encrypt() and digest() in one step.
:Parameters:
plaintext : byte string
The piece of data to encrypt.
:Return:
a tuple with two byte strings:
- the encrypted data
- the MAC
"""
return self.encrypt(plaintext), self.digest()
def decrypt_and_verify(self, ciphertext, mac_tag):
"""Perform decrypt() and verify() in one step.
:Parameters:
ciphertext : byte string
The piece of data to decrypt.
mac_tag : byte string
This is the *binary* MAC, as received from the sender.
:Return: the decrypted data (byte string).
:Raises ValueError:
if the MAC does not match. The message has been tampered with
or the key is incorrect.
"""
if self.mode == MODE_SIV:
if self.decrypt not in self._next:
raise TypeError("decrypt() can only be called"
" after initialization or an update()")
self._next = [self.verify]
# Take the MAC and start the cipher for decryption
self._mac = mac_tag
self._cipher = self._siv_ctr_cipher(self._mac)
pt = self._cipher.decrypt(ciphertext)
if self.nonce:
self._cipherMAC.update(self.nonce)
if pt:
self._cipherMAC.update(pt)
else:
pt = self.decrypt(ciphertext)
self.verify(mac_tag)
return pt

View File

@ -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.

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View 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

View 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

Binary file not shown.

BIN
modules/Crypto/Hash/_MD4.so Executable file

Binary file not shown.

BIN
modules/Crypto/Hash/_RIPEMD160.so Executable file

Binary file not shown.

BIN
modules/Crypto/Hash/_SHA224.so Executable file

Binary file not shown.

BIN
modules/Crypto/Hash/_SHA256.so Executable file

Binary file not shown.

BIN
modules/Crypto/Hash/_SHA384.so Executable file

Binary file not shown.

BIN
modules/Crypto/Hash/_SHA512.so Executable file

Binary file not shown.

View File

@ -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

View 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

View File

@ -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()

View File

@ -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:

View File

@ -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):

View File

@ -46,7 +46,7 @@ them from known components, exporting them, and importing them.
>>> >>>
>>> key = RSA.generate(2048) >>> key = RSA.generate(2048)
>>> f = open('mykey.pem','w') >>> f = open('mykey.pem','w')
>>> f.write(key.exportKey('PEM')) >>> f.write(RSA.exportKey('PEM'))
>>> f.close() >>> f.close()
... ...
>>> f = open('mykey.pem','r') >>> f = open('mykey.pem','r')
@ -65,39 +65,31 @@ it is recommended to use one of the standardized schemes instead (like
__revision__ = "$Id$" __revision__ = "$Id$"
__all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation', __all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation', '_RSAobj']
'_RSAobj', 'oid' , 'algorithmIdentifier' ]
import sys import sys
if sys.version_info[0] == 2 and sys.version_info[1] == 1: if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import * from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import * from Crypto.Util.py3compat import *
#from Crypto.Util.python_compat import *
from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes
from Crypto.PublicKey import _RSA, _slowmath, pubkey from Crypto.PublicKey import _RSA, _slowmath, pubkey
from Crypto.IO import PKCS8, PEM
from Crypto import Random from Crypto import Random
from Crypto.Util.asn1 import * from Crypto.Util.asn1 import DerObject, DerSequence, DerNull
import binascii import binascii
import struct import struct
from Crypto.Util.number import inverse from Crypto.Util.number import inverse
from Crypto.Util.number import inverse
try: try:
from Crypto.PublicKey import _fastmath from Crypto.PublicKey import _fastmath
except ImportError: except ImportError:
_fastmath = None _fastmath = None
def decode_der(obj_class, binstr):
"""Instantiate a DER object class, decode a DER binary string in it, and
return the object."""
der = obj_class()
der.decode(binstr)
return der
class _RSAobj(pubkey.pubkey): class _RSAobj(pubkey.pubkey):
"""Class defining an actual RSA key. """Class defining an actual RSA key.
@ -294,8 +286,6 @@ class _RSAobj(pubkey.pubkey):
def __setstate__(self, d): def __setstate__(self, d):
if not hasattr(self, 'implementation'): if not hasattr(self, 'implementation'):
self.implementation = RSAImplementation() self.implementation = RSAImplementation()
if not hasattr(self, '_randfunc'):
self._randfunc = Random.new().read
t = [] t = []
for k in self.keydata: for k in self.keydata:
if not d.has_key(k): if not d.has_key(k):
@ -315,66 +305,36 @@ class _RSAobj(pubkey.pubkey):
# PY3K: This is meant to be text, do not change to bytes (data) # PY3K: This is meant to be text, do not change to bytes (data)
return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs))
def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None): def exportKey(self, format='PEM', passphrase=None, pkcs=1):
"""Export this RSA key. """Export this RSA key.
:Parameters: :Parameter format: The format to use for wrapping the key.
format : string
The format to use for wrapping the key:
- *'DER'*. Binary encoding. - *'DER'*. Binary encoding, always unencrypted.
- *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_. - *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_.
Unencrypted (default) or encrypted.
- *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
Only suitable for public keys (not private keys). Only suitable for public keys (not private keys).
:Type format: string
passphrase : string :Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from.
For private keys only. The pass phrase used for deriving the encryption :Type passphrase: string
key.
pkcs : integer :Parameter pkcs: The PKCS standard to follow for assembling the key.
For *DER* and *PEM* format only.
The PKCS standard to follow for assembling the components of the key.
You have two choices: You have two choices:
- **1** (default): the public key is embedded into - with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE.
an X.509 ``SubjectPublicKeyInfo`` DER SEQUENCE. The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE.
The private key is embedded into a `PKCS#1`_ This mode is the default.
``RSAPrivateKey`` DER SEQUENCE. - with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE.
- **8**: the private key is embedded into a `PKCS#8`_ This mode is not available for public keys.
``PrivateKeyInfo`` DER SEQUENCE. This value cannot be used
for public keys.
protection : string PKCS standards are not relevant for the *OpenSSH* format.
The encryption scheme to use for protecting the private key. :Type pkcs: integer
If ``None`` (default), the behavior depends on ``format``: :Return: A byte string with the encoded public or private half.
- For *DER*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*
scheme is used. The following operations are performed:
1. A 16 byte Triple DES key is derived from the passphrase
using `Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt,
and 1 000 iterations of `Crypto.Hash.HMAC`.
2. The private key is encrypted using CBC.
3. The encrypted key is encoded according to PKCS#8.
- For *PEM*, the obsolete PEM encryption scheme is used.
It is based on MD5 for key derivation, and Triple DES for encryption.
Specifying a value for ``protection`` is only meaningful for PKCS#8
(that is, ``pkcs=8``) and only if a pass phrase is present too.
The supported schemes for PKCS#8 are listed in the
`Crypto.IO.PKCS8` module (see ``wrap_algo`` parameter).
:Return: A byte string with the encoded public or private half
of the key.
:Raise ValueError: :Raise ValueError:
When the format is unknown or when you try to encrypt a private When the format is unknown.
key with *DER* format and PKCS#1.
:attention:
If you don't provide a pass phrase, the private key will be
exported in the clear!
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
@ -388,52 +348,59 @@ class _RSAobj(pubkey.pubkey):
nb = long_to_bytes(self.n) nb = long_to_bytes(self.n)
if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb
if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb
keyparts = [ b('ssh-rsa'), eb, nb ] keyparts = [ 'ssh-rsa', eb, nb ]
keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts]) keystring = ''.join([ struct.pack(">I",len(kp))+kp for kp in keyparts])
return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1] return 'ssh-rsa '+binascii.b2a_base64(keystring)[:-1]
# DER format is always used, even in case of PEM, which simply # DER format is always used, even in case of PEM, which simply
# encodes it into BASE64. # encodes it into BASE64.
der = DerSequence()
if self.has_private(): if self.has_private():
binary_key = newDerSequence( keyType= { 1: 'RSA PRIVATE', 8: 'PRIVATE' }[pkcs]
0, der[:] = [ 0, self.n, self.e, self.d, self.p, self.q,
self.n, self.d % (self.p-1), self.d % (self.q-1),
self.e, inverse(self.q, self.p) ]
self.d, if pkcs==8:
self.p, derkey = der.encode()
self.q, der = DerSequence([0])
self.d % (self.p-1), der.append(algorithmIdentifier)
self.d % (self.q-1), der.append(DerObject('OCTET STRING', derkey).encode())
inverse(self.q, self.p)
).encode()
if pkcs==1:
keyType = 'RSA PRIVATE'
if format=='DER' and passphrase:
raise ValueError("PKCS#1 private key cannot be encrypted")
else: # PKCS#8
if format=='PEM' and protection is None:
keyType = 'PRIVATE'
binary_key = PKCS8.wrap(binary_key, oid, None)
else: else:
keyType = 'ENCRYPTED PRIVATE' keyType = "PUBLIC"
if not protection: der.append(algorithmIdentifier)
protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' bitmap = DerObject('BIT STRING')
binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection) derPK = DerSequence( [ self.n, self.e ] )
passphrase = None bitmap.payload = bchr(0x00) + derPK.encode()
else: der.append(bitmap.encode())
keyType = "RSA PUBLIC"
binary_key = newDerSequence(
algorithmIdentifier,
newDerBitString(
newDerSequence( self.n, self.e )
)
).encode()
if format=='DER': if format=='DER':
return binary_key return der.encode()
if format=='PEM': if format=='PEM':
pem_str = PEM.encode(binary_key, keyType+" KEY", passphrase, self._randfunc) pem = b("-----BEGIN " + keyType + " KEY-----\n")
return tobytes(pem_str) objenc = None
raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format) if passphrase and keyType.endswith('PRIVATE'):
# We only support 3DES for encryption
import Crypto.Hash.MD5
from Crypto.Cipher import DES3
from Crypto.Protocol.KDF import PBKDF1
salt = self._randfunc(8)
key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5)
key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5)
objenc = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt)
pem += b('Proc-Type: 4,ENCRYPTED\n')
pem += b('DEK-Info: DES-EDE3-CBC,') + binascii.b2a_hex(salt).upper() + b('\n\n')
binaryKey = der.encode()
if objenc:
# Add PKCS#7-like padding
padding = objenc.block_size-len(binaryKey)%objenc.block_size
binaryKey = objenc.encrypt(binaryKey+bchr(padding)*padding)
# Each BASE64 line can take up to 64 characters (=48 bytes of data)
chunks = [ binascii.b2a_base64(binaryKey[i:i+48]) for i in range(0, len(binaryKey), 48) ]
pem += b('').join(chunks)
pem += b("-----END " + keyType + " KEY-----")
return pem
return ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
class RSAImplementation(object): class RSAImplementation(object):
""" """
@ -572,139 +539,159 @@ class RSAImplementation(object):
key = self._math.rsa_construct(*tup) key = self._math.rsa_construct(*tup)
return _RSAobj(self, key) return _RSAobj(self, key)
def _importKeyDER(self, extern_key, passphrase=None): def _importKeyDER(self, externKey):
"""Import an RSA key (public or private half), encoded in DER form.""" """Import an RSA key (public or private half), encoded in DER form."""
try: try:
der = decode_der(DerSequence, extern_key) der = DerSequence()
der.decode(externKey, True)
# Try PKCS#1 first, for a private key # Try PKCS#1 first, for a private key
if len(der) == 9 and der.hasOnlyInts() and der[0] == 0: if len(der)==9 and der.hasOnlyInts() and der[0]==0:
# ASN.1 RSAPrivateKey element # ASN.1 RSAPrivateKey element
del der[6:] # Remove d mod (p-1), del der[6:] # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p
# d mod (q-1), and der.append(inverse(der[4],der[5])) # Add p^{-1} mod q
# q^{-1} mod p
der.append(inverse(der[4], der[5])) # Add p^{-1} mod q
del der[0] # Remove version del der[0] # Remove version
return self.construct(der[:]) return self.construct(der[:])
# Keep on trying PKCS#1, but now for a public key # Keep on trying PKCS#1, but now for a public key
if len(der) == 2: if len(der)==2:
try: # The DER object is an RSAPublicKey SEQUENCE with two elements
# The DER object is an RSAPublicKey SEQUENCE with
# two elements
if der.hasOnlyInts(): if der.hasOnlyInts():
return self.construct(der[:]) return self.construct(der[:])
# The DER object is a SubjectPublicKeyInfo SEQUENCE # The DER object is a SubjectPublicKeyInfo SEQUENCE with two elements:
# with two elements: an 'algorithmIdentifier' and a # an 'algorithm' (or 'algorithmIdentifier') SEQUENCE and a 'subjectPublicKey' BIT STRING.
# 'subjectPublicKey'BIT STRING. # 'algorithm' takes the value given a few lines above.
# 'algorithmIdentifier' takes the value given at the # 'subjectPublicKey' encapsulates the actual ASN.1 RSAPublicKey element.
# module level. if der[0]==algorithmIdentifier:
# 'subjectPublicKey' encapsulates the actual ASN.1 bitmap = DerObject()
# RSAPublicKey element. bitmap.decode(der[1], True)
if der[0] == algorithmIdentifier: if bitmap.isType('BIT STRING') and bord(bitmap.payload[0])==0x00:
bitmap = decode_der(DerBitString, der[1]) der.decode(bitmap.payload[1:], True)
rsaPub = decode_der(DerSequence, bitmap.value) if len(der)==2 and der.hasOnlyInts():
if len(rsaPub) == 2 and rsaPub.hasOnlyInts(): return self.construct(der[:])
return self.construct(rsaPub[:])
except (ValueError, EOFError):
pass
# Try PKCS#8 (possibly encrypted) # Try unencrypted PKCS#8
k = PKCS8.unwrap(extern_key, passphrase) if der[0]==0:
if k[0] == oid: # The second element in the SEQUENCE is algorithmIdentifier.
return self._importKeyDER(k[1], passphrase) # It must say RSA (see above for description).
if der[1]==algorithmIdentifier:
privateKey = DerObject()
privateKey.decode(der[2], True)
if privateKey.isType('OCTET STRING'):
return self._importKeyDER(privateKey.payload)
except (ValueError, EOFError): except ValueError, IndexError:
pass pass
raise ValueError("RSA key format is not supported") raise ValueError("RSA key format is not supported")
def importKey(self, extern_key, passphrase=None): def importKey(self, externKey, passphrase=None):
"""Import an RSA key (public or private half), encoded in standard """Import an RSA key (public or private half), encoded in standard form.
form.
:Parameter extern_key: :Parameter externKey:
The RSA key to import, encoded as a string. The RSA key to import, encoded as a string.
An RSA public key can be in any of the following formats: An RSA public key can be in any of the following formats:
- X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM - X.509 `subjectPublicKeyInfo` DER SEQUENCE (binary or PEM encoding)
encoding) - `PKCS#1`_ `RSAPublicKey` DER SEQUENCE (binary or PEM encoding)
- `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding)
- OpenSSH (textual public key only) - OpenSSH (textual public key only)
An RSA private key can be in any of the following formats: An RSA private key can be in any of the following formats:
- PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - PKCS#1 `RSAPrivateKey` DER SEQUENCE (binary or PEM encoding)
- `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` - `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE (binary or PEM encoding)
DER SEQUENCE (binary or PEM encoding)
- OpenSSH (textual public key only) - OpenSSH (textual public key only)
For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
The private key may be encrypted by means of a certain pass phrase In case of PEM encoding, the private key can be encrypted with DES or 3TDES according to a certain ``pass phrase``.
either at the PEM level or at the PKCS#8 level. Only OpenSSL-compatible pass phrases are supported.
:Type extern_key: string :Type externKey: string
:Parameter passphrase: :Parameter passphrase:
In case of an encrypted private key, this is the pass phrase from In case of an encrypted PEM key, this is the pass phrase from which the encryption key is derived.
which the decryption key is derived.
:Type passphrase: string :Type passphrase: string
:Return: An RSA key object (`_RSAobj`). :Return: An RSA key object (`_RSAobj`).
:Raise ValueError/IndexError/TypeError: :Raise ValueError/IndexError/TypeError:
When the given key cannot be parsed (possibly because the pass When the given key cannot be parsed (possibly because the pass phrase is wrong).
phrase is wrong).
.. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
.. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
""" """
extern_key = tobytes(extern_key) externKey = tobytes(externKey)
if passphrase is not None: if passphrase is not None:
passphrase = tobytes(passphrase) passphrase = tobytes(passphrase)
if extern_key.startswith(b('-----')): if externKey.startswith(b('-----')):
# This is probably a PEM encoded key. # This is probably a PEM encoded key
(der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) lines = externKey.replace(b(" "),b('')).split()
if enc_flag: keyobj = None
passphrase = None
return self._importKeyDER(der, passphrase)
if extern_key.startswith(b('ssh-rsa ')): # The encrypted PEM format
if lines[1].startswith(b('Proc-Type:4,ENCRYPTED')):
DEK = lines[2].split(b(':'))
if len(DEK)!=2 or DEK[0]!=b('DEK-Info') or not passphrase:
raise ValueError("PEM encryption format not supported.")
algo, salt = DEK[1].split(b(','))
salt = binascii.a2b_hex(salt)
import Crypto.Hash.MD5
from Crypto.Cipher import DES, DES3
from Crypto.Protocol.KDF import PBKDF1
if algo==b("DES-CBC"):
# This is EVP_BytesToKey in OpenSSL
key = PBKDF1(passphrase, salt, 8, 1, Crypto.Hash.MD5)
keyobj = DES.new(key, Crypto.Cipher.DES.MODE_CBC, salt)
elif algo==b("DES-EDE3-CBC"):
# Note that EVP_BytesToKey is note exactly the same as PBKDF1
key = PBKDF1(passphrase, salt, 16, 1, Crypto.Hash.MD5)
key += PBKDF1(key+passphrase, salt, 8, 1, Crypto.Hash.MD5)
keyobj = DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, salt)
else:
raise ValueError("Unsupport PEM encryption algorithm.")
lines = lines[2:]
der = binascii.a2b_base64(b('').join(lines[1:-1]))
if keyobj:
der = keyobj.decrypt(der)
padding = bord(der[-1])
der = der[:-padding]
return self._importKeyDER(der)
if externKey.startswith(b('ssh-rsa ')):
# This is probably an OpenSSH key # This is probably an OpenSSH key
keystring = binascii.a2b_base64(extern_key.split(b(' '))[1]) keystring = binascii.a2b_base64(externKey.split(b(' '))[1])
keyparts = [] keyparts = []
while len(keystring) > 4: while len(keystring)>4:
l = struct.unpack(">I", keystring[:4])[0] l = struct.unpack(">I",keystring[:4])[0]
keyparts.append(keystring[4:4 + l]) keyparts.append(keystring[4:4+l])
keystring = keystring[4 + l:] keystring = keystring[4+l:]
e = bytes_to_long(keyparts[1]) e = bytes_to_long(keyparts[1])
n = bytes_to_long(keyparts[2]) n = bytes_to_long(keyparts[2])
return self.construct([n, e]) return self.construct([n, e])
if bord(externKey[0])==0x30:
if bord(extern_key[0]) == 0x30:
# This is probably a DER encoded key # This is probably a DER encoded key
return self._importKeyDER(extern_key, passphrase) return self._importKeyDER(externKey)
raise ValueError("RSA key format is not supported") raise ValueError("RSA key format is not supported")
#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates #: This is the ASN.1 DER object that qualifies an algorithm as
#: a generic RSA key, even when such key will be actually used for digital #: compliant to PKCS#1 (that is, the standard RSA).
#: signatures. # It is found in all 'algorithm' fields (also called 'algorithmIdentifier').
#: # It is a SEQUENCE with the oid assigned to RSA and with its parameters (none).
#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html # 0x06 0x09 OBJECT IDENTIFIER, 9 bytes of payload
oid = "1.2.840.113549.1.1.1" # 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01
# rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1)
#: This is the standard DER object that qualifies a cryptographic algorithm # 0x05 0x00 NULL
#: in ASN.1-based data structures (e.g. X.509 certificates).
algorithmIdentifier = DerSequence( algorithmIdentifier = DerSequence(
[DerObjectId(oid).encode(), # algorithm field [ b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'),
DerNull().encode()] # parameters field DerNull().encode() ]
).encode() ).encode()
_impl = RSAImplementation() _impl = RSAImplementation()

View File

@ -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]

View File

@ -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$"

View File

@ -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

View File

@ -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 *

View File

@ -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):

View File

@ -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

View File

@ -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."""

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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:

View 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:

View File

@ -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

View File

@ -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()]

View File

@ -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

View File

@ -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

View File

@ -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__':

View File

@ -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__':

View File

@ -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

View File

@ -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):

View File

@ -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)

View 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:

View File

@ -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__':

View File

@ -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

View File

@ -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__':

View File

@ -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

View File

@ -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__':

View File

@ -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"""

View File

@ -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__':

View File

@ -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())

View File

@ -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__':

View File

@ -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

View File

@ -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",
}

View File

@ -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 = []

View File

@ -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

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -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:

View File

@ -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

Binary file not shown.

View File

@ -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

View File

@ -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"""

View 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()

View File

@ -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):