summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Crypto/Cipher/AES.py31
-rw-r--r--lib/Crypto/Cipher/ARC2.py3
-rw-r--r--lib/Crypto/Cipher/ARC4.py21
-rw-r--r--lib/Crypto/Cipher/Blowfish.py3
-rw-r--r--lib/Crypto/Cipher/CAST.py3
-rw-r--r--lib/Crypto/Cipher/DES.py11
-rw-r--r--lib/Crypto/Cipher/DES3.py13
-rw-r--r--lib/Crypto/Cipher/PKCS1_OAEP.py26
-rw-r--r--lib/Crypto/Cipher/PKCS1_v1_5.py2
-rw-r--r--lib/Crypto/Cipher/blockalgo.py16
-rw-r--r--lib/Crypto/Hash/MD2.py91
-rw-r--r--lib/Crypto/Hash/MD4.py91
-rw-r--r--lib/Crypto/Hash/MD5.py99
-rw-r--r--lib/Crypto/Hash/RIPEMD.py76
-rw-r--r--lib/Crypto/Hash/SHA.py80
-rw-r--r--lib/Crypto/Hash/SHA1.py92
-rw-r--r--lib/Crypto/Hash/SHA224.py95
-rw-r--r--lib/Crypto/Hash/SHA256.py95
-rw-r--r--lib/Crypto/Hash/SHA384.py96
-rw-r--r--lib/Crypto/Hash/SHA512.py95
-rw-r--r--lib/Crypto/Hash/__init__.py121
-rw-r--r--lib/Crypto/Hash/hashalgo.py116
-rw-r--r--lib/Crypto/IO/PEM.py163
-rw-r--r--lib/Crypto/IO/PKCS8.py209
-rw-r--r--lib/Crypto/IO/_PBES.py348
-rw-r--r--lib/Crypto/IO/__init__.py32
-rw-r--r--lib/Crypto/Protocol/KDF.py2
-rw-r--r--lib/Crypto/PublicKey/DSA.py317
-rw-r--r--lib/Crypto/PublicKey/ElGamal.py13
-rw-r--r--lib/Crypto/PublicKey/RSA.py357
-rw-r--r--lib/Crypto/PublicKey/_DSA.py8
-rw-r--r--lib/Crypto/PublicKey/__init__.py3
-rw-r--r--lib/Crypto/Random/Fortuna/FortunaAccumulator.py7
-rw-r--r--lib/Crypto/Random/Fortuna/FortunaGenerator.py2
-rw-r--r--lib/Crypto/Random/OSRNG/nt.py2
-rw-r--r--lib/Crypto/Random/random.py14
-rw-r--r--lib/Crypto/SelfTest/Cipher/common.py48
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_AES.py37
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_ARC4.py380
-rw-r--r--lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py15
-rw-r--r--lib/Crypto/SelfTest/Hash/__init__.py14
-rw-r--r--lib/Crypto/SelfTest/Hash/common.py77
-rw-r--r--lib/Crypto/SelfTest/Hash/test_HMAC.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_MD2.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_MD4.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_MD5.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_RIPEMD160.py (renamed from lib/Crypto/SelfTest/Hash/test_RIPEMD.py)10
-rw-r--r--lib/Crypto/SelfTest/Hash/test_SHA1.py (renamed from lib/Crypto/SelfTest/Hash/test_SHA.py)8
-rw-r--r--lib/Crypto/SelfTest/Hash/test_SHA224.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_SHA256.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_SHA384.py2
-rw-r--r--lib/Crypto/SelfTest/Hash/test_SHA512.py2
-rw-r--r--lib/Crypto/SelfTest/IO/__init__.py34
-rw-r--r--lib/Crypto/SelfTest/IO/test_PKCS8.py419
-rw-r--r--lib/Crypto/SelfTest/Protocol/test_KDF.py2
-rw-r--r--lib/Crypto/SelfTest/PublicKey/__init__.py8
-rw-r--r--lib/Crypto/SelfTest/PublicKey/test_RSA.py66
-rw-r--r--lib/Crypto/SelfTest/PublicKey/test_import_DSA.py389
-rw-r--r--lib/Crypto/SelfTest/PublicKey/test_import_RSA.py (renamed from lib/Crypto/SelfTest/PublicKey/test_importKey.py)123
-rw-r--r--lib/Crypto/SelfTest/Random/test_random.py2
-rw-r--r--lib/Crypto/SelfTest/Signature/test_pkcs1_15.py33
-rw-r--r--lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py16
-rw-r--r--lib/Crypto/SelfTest/Util/__init__.py1
-rw-r--r--lib/Crypto/SelfTest/Util/test_Counter.py20
-rw-r--r--lib/Crypto/SelfTest/Util/test_Padding.py140
-rw-r--r--lib/Crypto/SelfTest/Util/test_asn1.py848
-rw-r--r--lib/Crypto/SelfTest/Util/test_number.py50
-rw-r--r--lib/Crypto/SelfTest/__init__.py5
-rw-r--r--lib/Crypto/Signature/PKCS1_PSS.py29
-rw-r--r--lib/Crypto/Signature/PKCS1_v1_5.py112
-rw-r--r--lib/Crypto/Util/Counter.py39
-rw-r--r--lib/Crypto/Util/Padding.py103
-rw-r--r--lib/Crypto/Util/__init__.py19
-rw-r--r--lib/Crypto/Util/_time.py28
-rw-r--r--lib/Crypto/Util/asn1.py949
-rw-r--r--lib/Crypto/Util/py21compat.py17
-rw-r--r--lib/Crypto/Util/py3compat.py12
-rw-r--r--lib/Crypto/__init__.py2
-rw-r--r--lib/Crypto/pct_warnings.py3
79 files changed, 5127 insertions, 1700 deletions
diff --git a/lib/Crypto/Cipher/AES.py b/lib/Crypto/Cipher/AES.py
index 14f68d8..351b954 100644
--- a/lib/Crypto/Cipher/AES.py
+++ b/lib/Crypto/Cipher/AES.py
@@ -46,8 +46,21 @@ As an example, encryption can be done as follows:
__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 _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):
"""AES cipher object"""
@@ -56,7 +69,18 @@ class AESCipher (blockalgo.BlockAlgo):
"""Initialize an AES cipher object
See also `new()` at the module level."""
- blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
+
+ # 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)
def new(key, *args, **kwargs):
"""Create a new AES cipher
@@ -79,8 +103,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
@@ -89,6 +112,8 @@ def new(key, *args, **kwargs):
(*Only* `MODE_CFB`).The number of bits the plaintext and ciphertext
are segmented in.
It must be a multiple of 8. If 0 or not specified, it will be assumed to be 8.
+ use_aesni : boolean
+ Use AES-NI if available.
:Return: an `AESCipher` object
"""
diff --git a/lib/Crypto/Cipher/ARC2.py b/lib/Crypto/Cipher/ARC2.py
index 7b5f43a..ddcca47 100644
--- a/lib/Crypto/Cipher/ARC2.py
+++ b/lib/Crypto/Cipher/ARC2.py
@@ -91,8 +91,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
diff --git a/lib/Crypto/Cipher/ARC4.py b/lib/Crypto/Cipher/ARC4.py
index b745e7c..48d39f1 100644
--- a/lib/Crypto/Cipher/ARC4.py
+++ b/lib/Crypto/Cipher/ARC4.py
@@ -63,6 +63,7 @@ As an example, encryption can be done as follows:
__revision__ = "$Id$"
+from Crypto.Util.py3compat import *
from Crypto.Cipher import _ARC4
class ARC4Cipher:
@@ -74,7 +75,18 @@ class ARC4Cipher:
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)
+ 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.key_size = self._cipher.key_size
@@ -108,8 +120,17 @@ def new(key, *args, **kwargs):
The secret key to use in the symmetric cipher.
It can have any length, with a minimum of 40 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
+
+ .. _3072: http://eprint.iacr.org/2002/067.pdf
"""
return ARC4Cipher(key, *args, **kwargs)
diff --git a/lib/Crypto/Cipher/Blowfish.py b/lib/Crypto/Cipher/Blowfish.py
index 3f12bea..2ce78e9 100644
--- a/lib/Crypto/Cipher/Blowfish.py
+++ b/lib/Crypto/Cipher/Blowfish.py
@@ -85,8 +85,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
diff --git a/lib/Crypto/Cipher/CAST.py b/lib/Crypto/Cipher/CAST.py
index f08dab3..5f009a7 100644
--- a/lib/Crypto/Cipher/CAST.py
+++ b/lib/Crypto/Cipher/CAST.py
@@ -88,8 +88,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
diff --git a/lib/Crypto/Cipher/DES.py b/lib/Crypto/Cipher/DES.py
index 2fae42f..1062d23 100644
--- a/lib/Crypto/Cipher/DES.py
+++ b/lib/Crypto/Cipher/DES.py
@@ -33,12 +33,12 @@ DES should not be used for new designs. Use `AES`.
As an example, encryption can be done as follows:
- >>> from Crypto.Cipher import DES3
+ >>> from Crypto.Cipher import DES
>>> from Crypto import Random
>>>
- >>> key = b'Sixteen byte key'
- >>> iv = Random.new().read(DES3.block_size)
- >>> cipher = DES3.new(key, DES3.MODE_OFB, iv)
+ >>> key = b'-8B key-'
+ >>> iv = Random.new().read(DES.block_size)
+ >>> cipher = DES.new(key, DES.MODE_OFB, iv)
>>> plaintext = b'sona si latine loqueris '
>>> msg = iv + cipher.encrypt(plaintext)
@@ -83,8 +83,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
diff --git a/lib/Crypto/Cipher/DES3.py b/lib/Crypto/Cipher/DES3.py
index 7fedac8..0265c0c 100644
--- a/lib/Crypto/Cipher/DES3.py
+++ b/lib/Crypto/Cipher/DES3.py
@@ -44,14 +44,14 @@ as `AES`.
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.Util import Counter
>>>
- >>> key = b'-8B key-'
- >>> nonce = Random.new().read(DES.block_size/2)
- >>> ctr = Counter.new(DES.block_size*8/2, prefix=nonce)
- >>> cipher = DES.new(key, DES.MODE_CTR, counter=ctr)
+ >>> key = b'Sixteen byte key'
+ >>> nonce = Random.new().read(DES3.block_size/2)
+ >>> ctr = Counter.new(DES3.block_size*8/2, prefix=nonce)
+ >>> cipher = DES3.new(key, DES3.MODE_CTR, counter=ctr)
>>> plaintext = b'We are no longer the knights who say ni!'
>>> msg = nonce + cipher.encrypt(plaintext)
@@ -96,8 +96,7 @@ def new(key, *args, **kwargs):
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
- For all other modes, it must be `block_size` bytes longs. It is optional and
- when not present it will be given a default value of all zeroes.
+ For all other modes, it must be `block_size` bytes longs.
counter : callable
(*Only* `MODE_CTR`). A stateful function that returns the next
*counter block*, which is a byte string of `block_size` bytes.
diff --git a/lib/Crypto/Cipher/PKCS1_OAEP.py b/lib/Crypto/Cipher/PKCS1_OAEP.py
index 9afe176..ff45719 100644
--- a/lib/Crypto/Cipher/PKCS1_OAEP.py
+++ b/lib/Crypto/Cipher/PKCS1_OAEP.py
@@ -31,7 +31,7 @@ As an example, a sender may encrypt a message in this way:
>>> from Crypto.Cipher import PKCS1_OAEP
>>> from Crypto.PublicKey import RSA
>>>
- >>> message = 'To be encrypted'
+ >>> message = b'To be encrypted'
>>> key = RSA.importKey(open('pubkey.der').read())
>>> cipher = PKCS1_OAEP.new(key)
>>> ciphertext = cipher.encrypt(message)
@@ -55,7 +55,7 @@ __revision__ = "$Id$"
__all__ = [ 'new', 'PKCS1OAEP_Cipher' ]
import Crypto.Signature.PKCS1_PSS
-import Crypto.Hash.SHA
+import Crypto.Hash.SHA1
from Crypto.Util.py3compat import *
import Crypto.Util.number
@@ -70,17 +70,17 @@ class PKCS1OAEP_Cipher:
:Parameters:
key : an RSA key object
- If a private half is given, both encryption and decryption are possible.
- If a public half is given, only encryption is possible.
+ If a private half is given, both encryption and decryption are possible.
+ If a public half is given, only encryption is possible.
hashAlgo : hash object
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,
- `Crypto.Hash.SHA` (that is, SHA-1) is used.
+ `Crypto.Hash.SHA1` is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
- label : string
+ label : byte string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
@@ -93,7 +93,7 @@ class PKCS1OAEP_Cipher:
if hashAlgo:
self._hashObj = hashAlgo
else:
- self._hashObj = Crypto.Hash.SHA
+ self._hashObj = Crypto.Hash.SHA1
if mgfunc:
self._mgf = mgfunc
@@ -117,12 +117,12 @@ class PKCS1OAEP_Cipher:
section 7.1.1 of RFC3447.
:Parameters:
- message : string
+ message : byte string
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes)
minus 2, minus twice the hash output size.
- :Return: A string, the ciphertext in which the message is encrypted.
+ :Return: A byte string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raise ValueError:
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.
:Parameters:
- ct : string
+ ct : byte string
The ciphertext that contains the message to recover.
- :Return: A string, the original message.
+ :Return: A byte string, the original message.
:Raise ValueError:
If the ciphertext length is incorrect, or if the decryption does not
succeed.
@@ -238,12 +238,12 @@ def new(key, hashAlgo=None, mgfunc=None, label=b('')):
hashAlgo : hash object
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,
- `Crypto.Hash.SHA` (that is, SHA-1) is used.
+ `Crypto.Hash.SHA1` is used.
mgfunc : callable
A mask generation function that accepts two parameters: a string to
use as seed, and the lenth of the mask to generate, in bytes.
If not specified, the standard MGF1 is used (a safe choice).
- label : string
+ label : byte string
A label to apply to this particular encryption. If not specified,
an empty string is used. Specifying a label does not improve
security.
diff --git a/lib/Crypto/Cipher/PKCS1_v1_5.py b/lib/Crypto/Cipher/PKCS1_v1_5.py
index c89035d..345ffc2 100644
--- a/lib/Crypto/Cipher/PKCS1_v1_5.py
+++ b/lib/Crypto/Cipher/PKCS1_v1_5.py
@@ -34,7 +34,7 @@ As an example, a sender may encrypt a message in this way:
>>> from Crypto.PublicKey import RSA
>>> from Crypto.Hash import SHA
>>>
- >>> message = 'To be encrypted'
+ >>> message = b'To be encrypted'
>>> h = SHA.new(message)
>>>
>>> key = RSA.importKey(open('pubkey.der').read())
diff --git a/lib/Crypto/Cipher/blockalgo.py b/lib/Crypto/Cipher/blockalgo.py
index dd183dc..218a367 100644
--- a/lib/Crypto/Cipher/blockalgo.py
+++ b/lib/Crypto/Cipher/blockalgo.py
@@ -200,15 +200,15 @@ class BlockAlgo:
That also means that you cannot reuse an object for encrypting
or decrypting other data with the same key.
- This function does not perform any padding.
+ This function does not add any padding to the plaintext.
- - For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *plaintext* length
- (in bytes) must be a multiple of *block_size*.
+ - For `MODE_ECB` and `MODE_CBC`, *plaintext* length (in bytes) must be
+ a multiple of *block_size*.
- For `MODE_CFB`, *plaintext* length (in bytes) must be a multiple
of *segment_size*/8.
- - For `MODE_CTR`, *plaintext* can be of any length.
+ - For `MODE_OFB` and `MODE_CTR`, *plaintext* can be of any length.
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
unless it is the last chunk of the message.
@@ -259,15 +259,15 @@ class BlockAlgo:
That also means that you cannot reuse an object for encrypting
or decrypting other data with the same key.
- This function does not perform any padding.
+ This function does not remove any padding from the plaintext.
- - For `MODE_ECB`, `MODE_CBC`, and `MODE_OFB`, *ciphertext* length
- (in bytes) must be a multiple of *block_size*.
+ - For `MODE_ECB` and `MODE_CBC`, *ciphertext* length (in bytes) must
+ be a multiple of *block_size*.
- For `MODE_CFB`, *ciphertext* length (in bytes) must be a multiple
of *segment_size*/8.
- - For `MODE_CTR`, *ciphertext* can be of any length.
+ - For `MODE_OFB` and `MODE_CTR`, *ciphertext* can be of any length.
- For `MODE_OPENPGP`, *plaintext* must be a multiple of *block_size*,
unless it is the last chunk of the message.
diff --git a/lib/Crypto/Hash/MD2.py b/lib/Crypto/Hash/MD2.py
deleted file mode 100644
index dac959e..0000000
--- a/lib/Crypto/Hash/MD2.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/Hash/MD4.py b/lib/Crypto/Hash/MD4.py
deleted file mode 100644
index e28a201..0000000
--- a/lib/Crypto/Hash/MD4.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/Hash/MD5.py b/lib/Crypto/Hash/MD5.py
index 18e9e7b..c5df793 100644
--- a/lib/Crypto/Hash/MD5.py
+++ b/lib/Crypto/Hash/MD5.py
@@ -35,63 +35,58 @@ This algorithm is insecure. Do not use it for new designs.
.. _RFC1321: http://tools.ietf.org/html/rfc1321
"""
+from __future__ import nested_scopes
+
_revision__ = "$Id$"
-__all__ = ['new', 'digest_size', 'MD5Hash' ]
+__all__ = ['new', 'block_size', 'digest_size']
from Crypto.Util.py3compat import *
-from Crypto.Hash.hashalgo import HashAlgo
-
-try:
- # The md5 module is deprecated in Python 2.6, so use hashlib when possible.
- import hashlib
- hashFactory = hashlib.md5
-
-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')
-
- digest_size = 16
- block_size = 64
-
- def __init__(self, data=None):
- 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)
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+
+def __make_constructor():
+ try:
+ # The md5 module is deprecated in Python 2.6, so use hashlib when possible.
+ from hashlib import md5 as _hash_new
+ except ImportError:
+ from md5 import new as _hash_new
+
+ 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
+ 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()
+del __make_constructor
#: The size of the resulting hash in bytes.
-digest_size = MD5Hash.digest_size
+digest_size = new().digest_size
#: The internal block size of the hash algorithm in bytes.
-block_size = MD5Hash.block_size
-
+block_size = new().block_size
diff --git a/lib/Crypto/Hash/RIPEMD.py b/lib/Crypto/Hash/RIPEMD.py
index 33099cb..4e80235 100644
--- a/lib/Crypto/Hash/RIPEMD.py
+++ b/lib/Crypto/Hash/RIPEMD.py
@@ -18,77 +18,9 @@
# SOFTWARE.
# ===================================================================
-"""RIPEMD-160 cryptographic hash algorithm.
+# This file exists for backward compatibility with old code that refers to
+# Crypto.Hash.RIPEMD
-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
+"""Deprecated alias for `Crypto.Hash.RIPEMD160`"""
+from Crypto.Hash.RIPEMD160 import new, block_size, digest_size
diff --git a/lib/Crypto/Hash/SHA.py b/lib/Crypto/Hash/SHA.py
index 0bc5917..0cc141c 100644
--- a/lib/Crypto/Hash/SHA.py
+++ b/lib/Crypto/Hash/SHA.py
@@ -18,81 +18,7 @@
# SOFTWARE.
# ===================================================================
-"""SHA-1 cryptographic hash algorithm.
-
-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
-
+# This file exists for backward compatibility with old code that refers to
+# Crypto.Hash.SHA
+from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size
diff --git a/lib/Crypto/Hash/SHA1.py b/lib/Crypto/Hash/SHA1.py
new file mode 100644
index 0000000..9ad9f1e
--- /dev/null
+++ b/lib/Crypto/Hash/SHA1.py
@@ -0,0 +1,92 @@
+# -*- 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-1 cryptographic hash algorithm.
+
+SHA-1_ produces the 160 bit digest of a message.
+
+ >>> from Crypto.Hash import SHA1
+ >>>
+ >>> h = SHA1.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
+"""
+
+from __future__ import nested_scopes
+
+_revision__ = "$Id$"
+
+__all__ = ['new', 'block_size', 'digest_size']
+
+from Crypto.Util.py3compat import *
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+
+def __make_constructor():
+ try:
+ # The sha module is deprecated in Python 2.6, so use hashlib when possible.
+ from hashlib import sha1 as _hash_new
+ except ImportError:
+ from sha import new as _hash_new
+
+ 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 _SHA1(object):
+ digest_size = 20
+ block_size = 64
+ name = "sha1"
+ 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 _SHA1(_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()
+ _SHA1.new = _SHA1
+ return _SHA1
+
+new = __make_constructor()
+del __make_constructor
+
+#: The size of the resulting hash in bytes.
+digest_size = new().digest_size
+
+#: The internal block size of the hash algorithm in bytes.
+block_size = new().block_size
diff --git a/lib/Crypto/Hash/SHA224.py b/lib/Crypto/Hash/SHA224.py
deleted file mode 100644
index 959b56d..0000000
--- a/lib/Crypto/Hash/SHA224.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/Hash/SHA256.py b/lib/Crypto/Hash/SHA256.py
deleted file mode 100644
index b0a99b3..0000000
--- a/lib/Crypto/Hash/SHA256.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/Hash/SHA384.py b/lib/Crypto/Hash/SHA384.py
deleted file mode 100644
index 3490b02..0000000
--- a/lib/Crypto/Hash/SHA384.py
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- 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
-
-
diff --git a/lib/Crypto/Hash/SHA512.py b/lib/Crypto/Hash/SHA512.py
deleted file mode 100644
index d57548d..0000000
--- a/lib/Crypto/Hash/SHA512.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/Hash/__init__.py b/lib/Crypto/Hash/__init__.py
index 4582c66..1050c78 100644
--- a/lib/Crypto/Hash/__init__.py
+++ b/lib/Crypto/Hash/__init__.py
@@ -49,8 +49,127 @@ The hashing modules here all support the interface described in `PEP
:undocumented: _MD2, _MD4, _RIPEMD160, _SHA224, _SHA256, _SHA384, _SHA512
"""
-__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD', 'SHA',
+__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1',
'SHA224', 'SHA256', 'SHA384', 'SHA512']
__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
diff --git a/lib/Crypto/Hash/hashalgo.py b/lib/Crypto/Hash/hashalgo.py
deleted file mode 100644
index b38b3a6..0000000
--- a/lib/Crypto/Hash/hashalgo.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- 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
-
diff --git a/lib/Crypto/IO/PEM.py b/lib/Crypto/IO/PEM.py
new file mode 100644
index 0000000..89a5689
--- /dev/null
+++ b/lib/Crypto/IO/PEM.py
@@ -0,0 +1,163 @@
+# -*- coding: ascii -*-
+#
+# Util/PEM.py : Privacy Enhanced Mail utilities
+#
+# ===================================================================
+# 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.
+# ===================================================================
+"""Set of functions for encapsulating data according to the PEM format.
+
+PEM (Privacy Enhanced Mail) was an IETF standard for securing emails via a
+Public Key Infrastructure. It is specified in RFC 1421-1424.
+
+Even though it has been abandoned, the simple message encapsulation it defined
+is still widely used today for encoding *binary* cryptographic objects like
+keys and certificates into text.
+"""
+
+__all__ = ['encode', 'decode']
+
+import sys
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+from Crypto.Util.py3compat import *
+
+import re
+from binascii import hexlify, unhexlify, a2b_base64, b2a_base64
+
+from Crypto.Hash import MD5
+from Crypto.Util.Padding import pad, unpad
+from Crypto.Cipher import DES, DES3, AES
+from Crypto.Protocol.KDF import PBKDF1
+from Crypto.Random import get_random_bytes
+
+
+def encode(data, marker, passphrase=None, randfunc=None):
+ """Encode a piece of binary data into PEM format.
+
+ :Parameters:
+ data : byte string
+ The piece of binary data to encode.
+ marker : string
+ The marker for the PEM block (e.g. "PUBLIC KEY").
+ Note that there is no official master list for all allowed markers.
+ Still, you can refer to the OpenSSL_ source code.
+ passphrase : byte string
+ If given, the PEM block will be encrypted. The key is derived from
+ the passphrase.
+ randfunc : callable
+ Random number generation function; it accepts an integer N and returns
+ a byte string of random data, N bytes long. If not given, a new one is
+ instantiated.
+ :Returns:
+ The PEM block, as a string.
+
+ .. _OpenSSL: http://cvs.openssl.org/fileview?f=openssl/crypto/pem/pem.h&v=1.66.2.1.4.2
+ """
+
+ if randfunc is None:
+ randfunc = get_random_bytes
+
+ out = "-----BEGIN %s-----\n" % marker
+ if passphrase:
+ # We only support 3DES for encryption
+ salt = randfunc(8)
+ key = PBKDF1(passphrase, salt, 16, 1, MD5)
+ key += PBKDF1(key + passphrase, salt, 8, 1, MD5)
+ objenc = DES3.new(key, DES3.MODE_CBC, salt)
+ out += "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,%s\n\n" %\
+ tostr(hexlify(salt).upper())
+ # Encrypt with PKCS#7 padding
+ data = objenc.encrypt(pad(data, objenc.block_size))
+
+ # Each BASE64 line can take up to 64 characters (=48 bytes of data)
+ # b2a_base64 adds a new line character!
+ chunks = [tostr(b2a_base64(data[i:i + 48]))
+ for i in range(0, len(data), 48)]
+ out += "".join(chunks)
+ out += "-----END %s-----" % marker
+ return out
+
+
+def decode(pem_data, passphrase=None):
+ """Decode a PEM block into binary.
+
+ :Parameters:
+ pem_data : string
+ The PEM block.
+ passphrase : byte string
+ If given and the PEM block is encrypted,
+ the key will be derived from the passphrase.
+ :Returns:
+ A tuple with the binary data, the marker string, and a boolean to
+ indicate if decryption was performed.
+ :Raises ValueError:
+ If decoding fails, if the PEM file is encrypted and no passphrase has
+ been provided or if the passphrase is incorrect.
+ """
+
+ # Verify Pre-Encapsulation Boundary
+ r = re.compile("\s*-----BEGIN (.*)-----\n")
+ m = r.match(pem_data)
+ if not m:
+ raise ValueError("Not a valid PEM pre boundary")
+ marker = m.group(1)
+
+ # Verify Post-Encapsulation Boundary
+ r = re.compile("-----END (.*)-----\s*$")
+ m = r.search(pem_data)
+ if not m or m.group(1) != marker:
+ raise ValueError("Not a valid PEM post boundary")
+
+ # Removes spaces and slit on lines
+ lines = pem_data.replace(" ", '').split()
+
+ # Decrypts, if necessary
+ if lines[1].startswith('Proc-Type:4,ENCRYPTED'):
+ if not passphrase:
+ raise ValueError("PEM is encrypted, but no passphrase available")
+ DEK = lines[2].split(':')
+ if len(DEK) != 2 or DEK[0] != 'DEK-Info':
+ raise ValueError("PEM encryption format not supported.")
+ algo, salt = DEK[1].split(',')
+ salt = unhexlify(tobytes(salt))
+ if algo == "DES-CBC":
+ # This is EVP_BytesToKey in OpenSSL
+ key = PBKDF1(passphrase, salt, 8, 1, MD5)
+ objdec = DES.new(key, DES.MODE_CBC, salt)
+ elif algo == "DES-EDE3-CBC":
+ # Note that EVP_BytesToKey is note exactly the same as PBKDF1
+ key = PBKDF1(passphrase, salt, 16, 1, MD5)
+ key += PBKDF1(key + passphrase, salt, 8, 1, MD5)
+ objdec = DES3.new(key, DES3.MODE_CBC, salt)
+ elif algo == "AES-128-CBC":
+ key = PBKDF1(passphrase, salt[:8], 16, 1, MD5)
+ objdec = AES.new(key, AES.MODE_CBC, salt)
+ else:
+ raise ValueError("Unsupport PEM encryption algorithm.")
+ lines = lines[2:]
+ else:
+ objdec = None
+
+ # Decode body
+ data = a2b_base64(b(''.join(lines[1:-1])))
+ enc_flag = False
+ if objdec:
+ data = unpad(objdec.decrypt(data), objdec.block_size)
+ enc_flag = True
+
+ return (data, marker, enc_flag)
diff --git a/lib/Crypto/IO/PKCS8.py b/lib/Crypto/IO/PKCS8.py
new file mode 100644
index 0000000..ceb0f5a
--- /dev/null
+++ b/lib/Crypto/IO/PKCS8.py
@@ -0,0 +1,209 @@
+# -*- coding: utf-8 -*-
+#
+# PublicKey/PKCS8.py : PKCS#8 functions
+#
+# ===================================================================
+# 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.
+# ===================================================================
+"""
+Module for handling private keys wrapped according to `PKCS#8`_.
+
+PKCS8 is a standard for storing and transferring private key information.
+The wrapped key can either be clear or encrypted.
+
+All encryption algorithms are based on passphrase-based key derivation.
+The following mechanisms are fully supported:
+
+* *PBKDF2WithHMAC-SHA1AndAES128-CBC*
+* *PBKDF2WithHMAC-SHA1AndAES192-CBC*
+* *PBKDF2WithHMAC-SHA1AndAES256-CBC*
+* *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*
+
+The following mechanisms are only supported for importing keys.
+They are much weaker than the ones listed above, and they are provided
+for backward compatibility only:
+
+* *pbeWithMD5AndRC2-CBC*
+* *pbeWithMD5AndDES-CBC*
+* *pbeWithSHA1AndRC2-CBC*
+* *pbeWithSHA1AndDES-CBC*
+
+.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
+
+"""
+
+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.asn1 import *
+
+from Crypto.IO._PBES import PBES1, PBES2
+
+__all__ = ['wrap', 'unwrap']
+
+
+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
+
+
+def wrap(private_key, key_oid, passphrase=None, protection=None,
+ prot_params=None, key_params=None, randfunc=None):
+ """Wrap a private key into a PKCS#8 blob (clear or encrypted).
+
+ :Parameters:
+
+ private_key : byte string
+ The private key encoded in binary form. The actual encoding is
+ algorithm specific. In most cases, it is DER.
+
+ key_oid : string
+ The object identifier (OID) of the private key to wrap.
+ It is a dotted string, like "``1.2.840.113549.1.1.1``" (for RSA keys).
+
+ passphrase : (binary) string
+ The secret passphrase from which the wrapping key is derived.
+ Set it only if encryption is required.
+
+ protection : string
+ The identifier of the algorithm to use for securely wrapping the key.
+ The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'.
+
+ prot_params : dictionary
+ Parameters for the protection algorithm.
+
+ +------------------+-----------------------------------------------+
+ | Key | Description |
+ +==================+===============================================+
+ | iteration_count | The KDF algorithm is repeated several times to|
+ | | slow down brute force attacks on passwords. |
+ | | The default value is 1 000. |
+ +------------------+-----------------------------------------------+
+ | salt_size | Salt is used to thwart dictionary and rainbow |
+ | | attacks on passwords. The default value is 8 |
+ | | bytes. |
+ +------------------+-----------------------------------------------+
+
+ key_params : DER object
+ The algorithm parameters associated to the private key.
+ It is required for algorithms like DSA, but not for others like RSA.
+
+ randfunc : callable
+ Random number generation function; it should accept a single integer
+ N and return a string of random data, N bytes long.
+ If not specified, a new RNG will be instantiated
+ from ``Crypto.Random``.
+
+ :Return:
+ The PKCS#8-wrapped private key (possibly encrypted),
+ as a binary string.
+ """
+
+ if key_params is None:
+ key_params = DerNull()
+
+ #
+ # PrivateKeyInfo ::= SEQUENCE {
+ # version Version,
+ # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ # privateKey PrivateKey,
+ # attributes [0] IMPLICIT Attributes OPTIONAL
+ # }
+ #
+ pk_info = newDerSequence(
+ 0,
+ newDerSequence(
+ DerObjectId(key_oid),
+ key_params
+ ),
+ newDerOctetString(private_key)
+ )
+ pk_info_der = pk_info.encode()
+
+ if not passphrase:
+ return pk_info_der
+
+ # Encryption with PBES2
+ passphrase = tobytes(passphrase)
+ if protection is None:
+ protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
+ return PBES2.encrypt(pk_info_der, passphrase,
+ protection, prot_params, randfunc)
+
+
+def unwrap(p8_private_key, passphrase=None):
+ """Unwrap a private key from a PKCS#8 blob (clear or encrypted).
+
+ :Parameters:
+ p8_private_key : byte string
+ The private key wrapped into a PKCS#8 blob
+ passphrase : (byte) string
+ The passphrase to use to decrypt the blob (if it is encrypted).
+ :Return:
+ A tuple containing:
+
+ #. the algorithm identifier of the wrapped key (OID, dotted string)
+ #. the private key (byte string, DER encoded)
+ #. the associated parameters (byte string, DER encoded) or ``None``
+
+ :Raises ValueError:
+ If decoding fails
+ """
+
+ if passphrase:
+ passphrase = tobytes(passphrase)
+ found = False
+ for pbes in PBES1, PBES2:
+ try:
+ p8_private_key = pbes.decrypt(p8_private_key, passphrase)
+ except ValueError:
+ pass
+ else:
+ found = True
+ break
+ if not found:
+ raise ValueError("Unsupported PKCS#5 Object ID ")
+
+ pk_info = decode_der(DerSequence, p8_private_key)
+ if len(pk_info) == 2 and not passphrase:
+ raise ValueError("Not a valid clear PKCS#8 structure "
+ "(maybe it is encrypted?)")
+ if not 3 <= len(pk_info) <= 4 or pk_info[0] != 0:
+ raise ValueError("Not a valid PrivateKeyInfo SEQUENCE")
+
+ #
+ # AlgorithmIdentifier ::= SEQUENCE {
+ # algorithm OBJECT IDENTIFIER,
+ # parameters ANY DEFINED BY algorithm OPTIONAL
+ # }
+ #
+ algo_id = decode_der(DerSequence, pk_info[1])
+ if not 1 <= len(algo_id) <= 2:
+ raise ValueError("Not a valid AlgorithmIdentifier SEQUENCE")
+ algo = decode_der(DerObjectId, algo_id[0]).value
+ private_key = decode_der(DerOctetString, pk_info[2]).payload
+ if len(algo_id) == 2 and algo_id[1] != b('\x05\x00'):
+ params = algo_id[1]
+ else:
+ params = None
+ return (algo, private_key, params)
diff --git a/lib/Crypto/IO/_PBES.py b/lib/Crypto/IO/_PBES.py
new file mode 100644
index 0000000..42d5dbc
--- /dev/null
+++ b/lib/Crypto/IO/_PBES.py
@@ -0,0 +1,348 @@
+#
+# PublicKey/_PBES.py : Password-Based Encryption functions
+#
+# ===================================================================
+# 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.
+# ===================================================================
+
+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 import Random
+from Crypto.Util.asn1 import *
+
+from Crypto.Util.Padding import pad, unpad
+from Crypto.Hash import MD5, SHA1
+from Crypto.Cipher import DES, ARC2, DES3, AES
+from Crypto.Protocol.KDF import PBKDF1, PBKDF2
+
+
+# These are the ASN.1 definitions used by the PBES1/2 logic:
+#
+# EncryptedPrivateKeyInfo ::= SEQUENCE {
+# encryptionAlgorithm EncryptionAlgorithmIdentifier,
+# encryptedData EncryptedData
+# }
+#
+# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+#
+# EncryptedData ::= OCTET STRING
+#
+# AlgorithmIdentifier ::= SEQUENCE {
+# algorithm OBJECT IDENTIFIER,
+# parameters ANY DEFINED BY algorithm OPTIONAL
+# }
+#
+# PBEParameter ::= SEQUENCE {
+# salt OCTET STRING (SIZE(8)),
+# iterationCount INTEGER
+# }
+#
+# PBES2-params ::= SEQUENCE {
+# keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+# encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
+# }
+#
+# PBKDF2-params ::= SEQUENCE {
+# salt CHOICE {
+# specified OCTET STRING,
+# otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+# },
+# iterationCount INTEGER (1..MAX),
+# keyLength INTEGER (1..MAX) OPTIONAL,
+# prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
+# }
+#
+
+
+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 PBES1(object):
+ """Deprecated encryption scheme with password-based key derivation
+ (originally defined in PKCS#5 v1.5, but still present in `v2.0`__).
+
+ .. __: http://www.ietf.org/rfc/rfc2898.txt
+ """
+
+ def decrypt(data, passphrase):
+ """Decrypt a piece of data using a passphrase and *PBES1*.
+
+ The algorithm to use is automatically detected.
+
+ :Parameters:
+ data : byte string
+ The piece of data to decrypt.
+ passphrase : byte string
+ The passphrase to use for decrypting the data.
+ :Returns:
+ The decrypted data, as a binary string.
+ """
+
+ encrypted_private_key_info = decode_der(DerSequence, data)
+ encrypted_algorithm = decode_der(
+ DerSequence,
+ encrypted_private_key_info[0]
+ )
+ encrypted_data = decode_der(
+ DerOctetString,
+ encrypted_private_key_info[1]
+ ).payload
+
+ pbe_oid = decode_der(DerObjectId, encrypted_algorithm[0]).value
+ cipher_params = {}
+ if pbe_oid == "1.2.840.113549.1.5.3":
+ # PBE_MD5_DES_CBC
+ hashmod = MD5
+ ciphermod = DES
+ elif pbe_oid == "1.2.840.113549.1.5.6":
+ # PBE_MD5_RC2_CBC
+ hashmod = MD5
+ ciphermod = ARC2
+ cipher_params['effective_keylen'] = 64
+ elif pbe_oid == "1.2.840.113549.1.5.10":
+ # PBE_SHA1_DES_CBC
+ hashmod = SHA1
+ ciphermod = DES
+ elif pbe_oid == "1.2.840.113549.1.5.11":
+ # PBE_SHA1_RC2_CBC
+ hashmod = SHA1
+ ciphermod = ARC2
+ cipher_params['effective_keylen'] = 64
+ else:
+ raise ValueError("Unknown OID")
+
+ pbe_params = decode_der(DerSequence, encrypted_algorithm[1])
+ salt = decode_der(DerOctetString, pbe_params[0]).payload
+ iterations = pbe_params[1]
+
+ key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod)
+ key, iv = key_iv[:8], key_iv[8:]
+
+ cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params)
+ pt = cipher.decrypt(encrypted_data)
+ return unpad(pt, cipher.block_size)
+ decrypt = staticmethod(decrypt)
+
+
+class PBES2(object):
+ """Encryption scheme with password-based key derivation
+ (defined in `PKCS#5 v2.0`__).
+
+ .. __: http://www.ietf.org/rfc/rfc2898.txt."""
+
+ def encrypt(data, passphrase, protection, prot_params=None, randfunc=None):
+ """Encrypt a piece of data using a passphrase and *PBES2*.
+
+ :Parameters:
+ data : byte string
+ The piece of data to encrypt.
+ passphrase : byte string
+ The passphrase to use for encrypting the data.
+ protection : string
+ The identifier of the encryption algorithm to use.
+ The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'.
+ prot_params : dictionary
+ Parameters of the protection algorithm.
+
+ +------------------+-----------------------------------------------+
+ | Key | Description |
+ +==================+===============================================+
+ | iteration_count | The KDF algorithm is repeated several times to|
+ | | slow down brute force attacks on passwords. |
+ | | The default value is 1 000. |
+ +------------------+-----------------------------------------------+
+ | salt_size | Salt is used to thwart dictionary and rainbow |
+ | | attacks on passwords. The default value is 8 |
+ | | bytes. |
+ +------------------+-----------------------------------------------+
+
+ randfunc : callable
+ Random number generation function; it should accept
+ a single integer N and return a string of random data,
+ N bytes long. If not specified, a new RNG will be
+ instantiated from ``Crypto.Random``.
+
+ :Returns:
+ The encrypted data, as a binary string.
+ """
+
+ if prot_params is None:
+ prot_params = {}
+
+ if randfunc is None:
+ randfunc = Random.new().read
+
+ if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC':
+ key_size = 24
+ module = DES3
+ protection = DES3.MODE_CBC
+ enc_oid = "1.2.840.113549.3.7"
+ elif protection == 'PBKDF2WithHMAC-SHA1AndAES128-CBC':
+ key_size = 16
+ module = AES
+ protection = AES.MODE_CBC
+ enc_oid = "2.16.840.1.101.3.4.1.2"
+ elif protection == 'PBKDF2WithHMAC-SHA1AndAES192-CBC':
+ key_size = 24
+ module = AES
+ protection = AES.MODE_CBC
+ enc_oid = "2.16.840.1.101.3.4.1.22"
+ elif protection == 'PBKDF2WithHMAC-SHA1AndAES256-CBC':
+ key_size = 32
+ module = AES
+ protection = AES.MODE_CBC
+ enc_oid = "2.16.840.1.101.3.4.1.42"
+ else:
+ raise ValueError("Unknown mode")
+
+ # Get random data
+ iv = randfunc(module.block_size)
+ salt = randfunc(prot_params.get("salt_size", 8))
+
+ # Derive key from password
+ count = prot_params.get("iteration_count", 1000)
+ key = PBKDF2(passphrase, salt, key_size, count)
+ key_derivation_func = newDerSequence(
+ DerObjectId("1.2.840.113549.1.5.12"), # PBKDF2
+ newDerSequence(
+ DerOctetString(salt),
+ DerInteger(count)
+ )
+ )
+
+ # Create cipher and use it
+ cipher = module.new(key, protection, iv)
+ encrypted_data = cipher.encrypt(pad(data, cipher.block_size))
+ encryption_scheme = newDerSequence(
+ DerObjectId(enc_oid),
+ DerOctetString(iv)
+ )
+
+ # Result
+ encrypted_private_key_info = newDerSequence(
+ # encryptionAlgorithm
+ newDerSequence(
+ DerObjectId("1.2.840.113549.1.5.13"), # PBES2
+ newDerSequence(
+ key_derivation_func,
+ encryption_scheme
+ ),
+ ),
+ DerOctetString(encrypted_data)
+ )
+ return encrypted_private_key_info.encode()
+ encrypt = staticmethod(encrypt)
+
+ def decrypt(data, passphrase):
+ """Decrypt a piece of data using a passphrase and *PBES2*.
+
+ The algorithm to use is automatically detected.
+
+ :Parameters:
+ data : byte string
+ The piece of data to decrypt.
+ passphrase : byte string
+ The passphrase to use for decrypting the data.
+ :Returns:
+ The decrypted data, as a binary string.
+ """
+
+ encrypted_private_key_info = decode_der(DerSequence, data)
+ encryption_algorithm = decode_der(
+ DerSequence,
+ encrypted_private_key_info[0]
+ )
+ encrypted_data = decode_der(
+ DerOctetString,
+ encrypted_private_key_info[1]
+ ).payload
+
+ pbe_oid = decode_der(DerObjectId, encryption_algorithm[0]).value
+ if pbe_oid != "1.2.840.113549.1.5.13":
+ raise ValueError("Not a PBES2 object")
+
+ pbes2_params = decode_der(DerSequence, encryption_algorithm[1])
+
+ ### Key Derivation Function selection
+ key_derivation_func = decode_der(DerSequence, pbes2_params[0])
+ key_derivation_oid = decode_der(
+ DerObjectId,
+ key_derivation_func[0]
+ ).value
+
+ # For now, we only support PBKDF2
+ if key_derivation_oid != "1.2.840.113549.1.5.12":
+ raise ValueError("Unknown KDF")
+
+ pbkdf2_params = decode_der(DerSequence, key_derivation_func[1])
+ salt = decode_der(DerOctetString, pbkdf2_params[0]).payload
+ iteration_count = pbkdf2_params[1]
+ if len(pbkdf2_params) > 2:
+ pbkdf2_key_length = pbkdf2_params[2]
+ else:
+ pbkdf2_key_length = None
+ if len(pbkdf2_params) > 3:
+ raise ValueError("Unsupported PRF for PBKDF2")
+
+ ### Cipher selection
+ encryption_scheme = decode_der(DerSequence, pbes2_params[1])
+ encryption_oid = decode_der(
+ DerObjectId,
+ encryption_scheme[0]
+ ).value
+
+ if encryption_oid == "1.2.840.113549.3.7":
+ # DES_EDE3_CBC
+ ciphermod = DES3
+ key_size = 24
+ elif encryption_oid == "2.16.840.1.101.3.4.1.2":
+ # AES128_CBC
+ ciphermod = AES
+ key_size = 16
+ elif encryption_oid == "2.16.840.1.101.3.4.1.22":
+ # AES192_CBC
+ ciphermod = AES
+ key_size = 24
+ elif encryption_oid == "2.16.840.1.101.3.4.1.42":
+ # AES256_CBC
+ ciphermod = AES
+ key_size = 32
+ else:
+ raise ValueError("Unsupported cipher")
+
+ if pbkdf2_key_length and pbkdf2_key_length != key_size:
+ raise ValueError("Mismatch between PBKDF2 parameters"
+ " and selected cipher")
+
+ IV = decode_der(DerOctetString, encryption_scheme[1]).payload
+
+ # Create cipher
+ key = PBKDF2(passphrase, salt, key_size, iteration_count)
+ cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV)
+
+ # Decrypt data
+ pt = cipher.decrypt(encrypted_data)
+ return unpad(pt, cipher.block_size)
+ decrypt = staticmethod(decrypt)
diff --git a/lib/Crypto/IO/__init__.py b/lib/Crypto/IO/__init__.py
new file mode 100644
index 0000000..86776c4
--- /dev/null
+++ b/lib/Crypto/IO/__init__.py
@@ -0,0 +1,32 @@
+# -*- 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.
+# ===================================================================
+
+"""
+Modules for reading and writing cryptographic data.
+
+======================== =============================================
+Module Description
+======================== =============================================
+Crypto.Util.PEM Set of functions for encapsulating data according to the PEM format.
+Crypto.Util.PKCS8 Set of functions for wrapping/unwrapping private keys.
+======================== =============================================
+"""
+
+__all__ = ['PEM', 'PKCS8']
diff --git a/lib/Crypto/Protocol/KDF.py b/lib/Crypto/Protocol/KDF.py
index 973b7af..b13562a 100644
--- a/lib/Crypto/Protocol/KDF.py
+++ b/lib/Crypto/Protocol/KDF.py
@@ -39,7 +39,7 @@ import math
import struct
from Crypto.Util.py3compat import *
-from Crypto.Hash import SHA as SHA1, HMAC
+from Crypto.Hash import SHA1, HMAC
from Crypto.Util.strxor import strxor
def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None):
diff --git a/lib/Crypto/PublicKey/DSA.py b/lib/Crypto/PublicKey/DSA.py
index d6bffd6..1818def 100644
--- a/lib/Crypto/PublicKey/DSA.py
+++ b/lib/Crypto/PublicKey/DSA.py
@@ -59,14 +59,20 @@ verification.
>>> from Crypto.Random import random
>>> from Crypto.PublicKey import DSA
- >>> from Crypto.Hash import SHA
+ >>> from Crypto.Hash import SHA256
>>>
>>> message = "Hello"
- >>> key = DSA.generate(1024)
- >>> h = SHA.new(message).digest()
+ >>> key = DSA.generate(2048)
+ >>> f = open("public_key.pem", "w")
+ >>> f.write(key.publickey().exportKey(key))
+ >>> h = SHA256.new(message).digest()
>>> k = random.StrongRandom().randint(1,key.q-1)
>>> 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):
>>> print "OK"
>>> else:
@@ -79,20 +85,64 @@ verification.
__revision__ = "$Id$"
-__all__ = ['generate', 'construct', 'error', 'DSAImplementation', '_DSAobj']
+__all__ = ['generate', 'construct', 'error', 'DSAImplementation',
+ '_DSAobj', 'importKey']
+
+import binascii
+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.PublicKey import _DSA, _slowmath, pubkey
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:
from Crypto.PublicKey import _fastmath
except ImportError:
_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 defining an actual DSA key.
@@ -112,9 +162,12 @@ class _DSAobj(pubkey.pubkey):
#: - **x**, the private key.
keydata = ['y', 'g', 'p', 'q', 'x']
- def __init__(self, implementation, key):
+ def __init__(self, implementation, key, randfunc=None):
self.implementation = implementation
self.key = key
+ if randfunc is None:
+ randfunc = Random.new().read
+ self._randfunc = randfunc
def __getattr__(self, attrname):
if attrname in self.keydata:
@@ -217,6 +270,8 @@ class _DSAobj(pubkey.pubkey):
def __setstate__(self, d):
if not hasattr(self, 'implementation'):
self.implementation = DSAImplementation()
+ if not hasattr(self, '_randfunc'):
+ self._randfunc = Random.new().read
t = []
for k in self.keydata:
if not d.has_key(k):
@@ -236,6 +291,124 @@ class _DSAobj(pubkey.pubkey):
# 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))
+ 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):
"""
A DSA key factory.
@@ -243,7 +416,7 @@ class DSAImplementation(object):
This class is only internally used to implement the methods of the
`Crypto.PublicKey.DSA` module.
"""
-
+
def __init__(self, **kwargs):
"""Create a new DSA key factory.
@@ -370,9 +543,139 @@ class DSAImplementation(object):
key = self._math.dsa_construct(*tup)
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()
generate = _impl.generate
construct = _impl.construct
+importKey = _impl.importKey
error = _impl.error
# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/Crypto/PublicKey/ElGamal.py b/lib/Crypto/PublicKey/ElGamal.py
index 99af71c..0ab07fc 100644
--- a/lib/Crypto/PublicKey/ElGamal.py
+++ b/lib/Crypto/PublicKey/ElGamal.py
@@ -111,6 +111,7 @@ __all__ = ['generate', 'construct', 'error', 'ElGamalobj']
from Crypto.PublicKey.pubkey import *
from Crypto.Util import number
+from Crypto import Random
class error (Exception):
pass
@@ -242,6 +243,11 @@ class ElGamalobj(pubkey):
#: - **x**, the private key.
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):
"""Encrypt a piece of data with ElGamal.
@@ -331,8 +337,11 @@ class ElGamalobj(pubkey):
def _decrypt(self, M):
if (not hasattr(self, 'x')):
raise TypeError('Private key not available in this object')
- ax=pow(M[0], self.x, self.p)
- plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
+ r = number.getRandomRange(2, self.p-1, self._randfunc)
+ a_blind = (M[0] * pow(self.g, r, 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
def _sign(self, M, K):
diff --git a/lib/Crypto/PublicKey/RSA.py b/lib/Crypto/PublicKey/RSA.py
index 99d851d..a5afeb9 100644
--- a/lib/Crypto/PublicKey/RSA.py
+++ b/lib/Crypto/PublicKey/RSA.py
@@ -46,7 +46,7 @@ them from known components, exporting them, and importing them.
>>>
>>> key = RSA.generate(2048)
>>> f = open('mykey.pem','w')
- >>> f.write(RSA.exportKey('PEM'))
+ >>> f.write(key.exportKey('PEM'))
>>> f.close()
...
>>> f = open('mykey.pem','r')
@@ -65,31 +65,39 @@ it is recommended to use one of the standardized schemes instead (like
__revision__ = "$Id$"
-__all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation', '_RSAobj']
+__all__ = ['generate', 'construct', 'error', 'importKey', 'RSAImplementation',
+ '_RSAobj', 'oid' , 'algorithmIdentifier' ]
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.python_compat import *
+
from Crypto.Util.number import getRandomRange, bytes_to_long, long_to_bytes
from Crypto.PublicKey import _RSA, _slowmath, pubkey
+from Crypto.IO import PKCS8, PEM
from Crypto import Random
-from Crypto.Util.asn1 import DerObject, DerSequence, DerNull
+from Crypto.Util.asn1 import *
+
import binascii
import struct
from Crypto.Util.number import inverse
-from Crypto.Util.number import inverse
-
try:
from Crypto.PublicKey import _fastmath
except ImportError:
_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 defining an actual RSA key.
@@ -286,6 +294,8 @@ class _RSAobj(pubkey.pubkey):
def __setstate__(self, d):
if not hasattr(self, 'implementation'):
self.implementation = RSAImplementation()
+ if not hasattr(self, '_randfunc'):
+ self._randfunc = Random.new().read
t = []
for k in self.keydata:
if not d.has_key(k):
@@ -305,36 +315,66 @@ class _RSAobj(pubkey.pubkey):
# 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))
- def exportKey(self, format='PEM', passphrase=None, pkcs=1):
+ def exportKey(self, format='PEM', passphrase=None, pkcs=1, protection=None):
"""Export this RSA key.
- :Parameter format: The format to use for wrapping the key.
+ :Parameters:
+ format : string
+ The format to use for wrapping the key:
- - *'DER'*. Binary encoding, always unencrypted.
+ - *'DER'*. Binary encoding.
- *'PEM'*. Textual encoding, done according to `RFC1421`_/`RFC1423`_.
- Unencrypted (default) or encrypted.
- *'OpenSSH'*. Textual encoding, done according to OpenSSH specification.
Only suitable for public keys (not private keys).
- :Type format: string
- :Parameter passphrase: In case of PEM, the pass phrase to derive the encryption key from.
- :Type passphrase: string
+ passphrase : string
+ For private keys only. The pass phrase used for deriving the encryption
+ key.
+
+ pkcs : integer
+ For *DER* and *PEM* format only.
+ The PKCS standard to follow for assembling the components of the key.
+ You have two choices:
+
+ - **1** (default): the public key is embedded into
+ an X.509 ``SubjectPublicKeyInfo`` DER SEQUENCE.
+ The private key is embedded into a `PKCS#1`_
+ ``RSAPrivateKey`` DER SEQUENCE.
+ - **8**: the private key is embedded into a `PKCS#8`_
+ ``PrivateKeyInfo`` DER SEQUENCE. This value cannot be used
+ for public keys.
+
+ protection : string
+ The encryption scheme to use for protecting the private key.
+
+ If ``None`` (default), the behavior depends on ``format``:
+
+ - 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.
- :Parameter pkcs: The PKCS standard to follow for assembling the key.
- You have two choices:
+ - For *PEM*, the obsolete PEM encryption scheme is used.
+ It is based on MD5 for key derivation, and Triple DES for encryption.
- - with **1**, the public key is embedded into an X.509 `SubjectPublicKeyInfo` DER SEQUENCE.
- The private key is embedded into a `PKCS#1`_ `RSAPrivateKey` DER SEQUENCE.
- This mode is the default.
- - with **8**, the private key is embedded into a `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE.
- This mode is not available for public keys.
+ Specifying a value for ``protection`` is only meaningful for PKCS#8
+ (that is, ``pkcs=8``) and only if a pass phrase is present too.
- PKCS standards are not relevant for the *OpenSSH* format.
- :Type pkcs: integer
+ 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.
+ :Return: A byte string with the encoded public or private half
+ of the key.
:Raise ValueError:
- When the format is unknown.
+ When the format is unknown or when you try to encrypt a private
+ 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
.. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt
@@ -348,59 +388,52 @@ class _RSAobj(pubkey.pubkey):
nb = long_to_bytes(self.n)
if bord(eb[0]) & 0x80: eb=bchr(0x00)+eb
if bord(nb[0]) & 0x80: nb=bchr(0x00)+nb
- keyparts = [ 'ssh-rsa', eb, nb ]
- keystring = ''.join([ struct.pack(">I",len(kp))+kp for kp in keyparts])
- return 'ssh-rsa '+binascii.b2a_base64(keystring)[:-1]
+ keyparts = [ b('ssh-rsa'), eb, nb ]
+ keystring = b('').join([ struct.pack(">I",len(kp))+kp for kp in keyparts])
+ return b('ssh-rsa ')+binascii.b2a_base64(keystring)[:-1]
# DER format is always used, even in case of PEM, which simply
# encodes it into BASE64.
- der = DerSequence()
if self.has_private():
- keyType= { 1: 'RSA PRIVATE', 8: 'PRIVATE' }[pkcs]
- der[:] = [ 0, self.n, self.e, self.d, self.p, self.q,
- self.d % (self.p-1), self.d % (self.q-1),
- inverse(self.q, self.p) ]
- if pkcs==8:
- derkey = der.encode()
- der = DerSequence([0])
- der.append(algorithmIdentifier)
- der.append(DerObject('OCTET STRING', derkey).encode())
+ binary_key = newDerSequence(
+ 0,
+ self.n,
+ self.e,
+ self.d,
+ self.p,
+ self.q,
+ self.d % (self.p-1),
+ self.d % (self.q-1),
+ 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:
+ keyType = 'ENCRYPTED PRIVATE'
+ if not protection:
+ protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
+ binary_key = PKCS8.wrap(binary_key, oid, passphrase, protection)
+ passphrase = None
else:
- keyType = "PUBLIC"
- der.append(algorithmIdentifier)
- bitmap = DerObject('BIT STRING')
- derPK = DerSequence( [ self.n, self.e ] )
- bitmap.payload = bchr(0x00) + derPK.encode()
- der.append(bitmap.encode())
+ keyType = "RSA PUBLIC"
+ binary_key = newDerSequence(
+ algorithmIdentifier,
+ newDerBitString(
+ newDerSequence( self.n, self.e )
+ )
+ ).encode()
if format=='DER':
- return der.encode()
+ return binary_key
if format=='PEM':
- pem = b("-----BEGIN " + keyType + " KEY-----\n")
- objenc = None
- 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)
+ pem_str = PEM.encode(binary_key, keyType+" KEY", passphrase, self._randfunc)
+ return tobytes(pem_str)
+ raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format)
class RSAImplementation(object):
"""
@@ -539,159 +572,139 @@ class RSAImplementation(object):
key = self._math.rsa_construct(*tup)
return _RSAobj(self, key)
- def _importKeyDER(self, externKey):
+ def _importKeyDER(self, extern_key, passphrase=None):
"""Import an RSA key (public or private half), encoded in DER form."""
try:
- der = DerSequence()
- der.decode(externKey, True)
+ der = decode_der(DerSequence, extern_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
- del der[6:] # Remove d mod (p-1), d mod (q-1), and q^{-1} mod p
- der.append(inverse(der[4],der[5])) # Add p^{-1} mod q
+ del der[6:] # Remove d mod (p-1),
+ # d mod (q-1), and
+ # q^{-1} mod p
+ der.append(inverse(der[4], der[5])) # Add p^{-1} mod q
del der[0] # Remove version
return self.construct(der[:])
# Keep on trying PKCS#1, but now for a public key
- if len(der)==2:
- # The DER object is an RSAPublicKey SEQUENCE with two elements
- if der.hasOnlyInts():
- return self.construct(der[:])
- # The DER object is a SubjectPublicKeyInfo SEQUENCE with two elements:
- # an 'algorithm' (or 'algorithmIdentifier') SEQUENCE and a 'subjectPublicKey' BIT STRING.
- # 'algorithm' takes the value given a few lines above.
- # 'subjectPublicKey' encapsulates the actual ASN.1 RSAPublicKey element.
- if der[0]==algorithmIdentifier:
- bitmap = DerObject()
- bitmap.decode(der[1], True)
- if bitmap.isType('BIT STRING') and bord(bitmap.payload[0])==0x00:
- der.decode(bitmap.payload[1:], True)
- if len(der)==2 and der.hasOnlyInts():
- return self.construct(der[:])
-
- # Try unencrypted PKCS#8
- if der[0]==0:
- # The second element in the SEQUENCE is algorithmIdentifier.
- # 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, IndexError:
+ if len(der) == 2:
+ try:
+ # The DER object is an RSAPublicKey SEQUENCE with
+ # two elements
+ if der.hasOnlyInts():
+ return self.construct(der[:])
+ # The DER object is a SubjectPublicKeyInfo SEQUENCE
+ # with two elements: an 'algorithmIdentifier' and a
+ # 'subjectPublicKey'BIT STRING.
+ # 'algorithmIdentifier' takes the value given at the
+ # module level.
+ # 'subjectPublicKey' encapsulates the actual ASN.1
+ # RSAPublicKey element.
+ if der[0] == algorithmIdentifier:
+ bitmap = decode_der(DerBitString, der[1])
+ rsaPub = decode_der(DerSequence, bitmap.value)
+ if len(rsaPub) == 2 and rsaPub.hasOnlyInts():
+ return self.construct(rsaPub[:])
+ except (ValueError, EOFError):
+ pass
+
+ # Try PKCS#8 (possibly encrypted)
+ k = PKCS8.unwrap(extern_key, passphrase)
+ if k[0] == oid:
+ return self._importKeyDER(k[1], passphrase)
+
+ except (ValueError, EOFError):
pass
raise ValueError("RSA key format is not supported")
- def importKey(self, externKey, passphrase=None):
- """Import an RSA key (public or private half), encoded in standard form.
+ def importKey(self, extern_key, passphrase=None):
+ """Import an RSA key (public or private half), encoded in standard
+ form.
- :Parameter externKey:
+ :Parameter extern_key:
The RSA key to import, encoded as a string.
An RSA public key can be in any of the following formats:
- - X.509 `subjectPublicKeyInfo` DER SEQUENCE (binary or PEM encoding)
- - `PKCS#1`_ `RSAPublicKey` DER SEQUENCE (binary or PEM encoding)
+ - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM
+ encoding)
+ - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding)
- OpenSSH (textual public key only)
An RSA private key can be in any of the following formats:
- - PKCS#1 `RSAPrivateKey` DER SEQUENCE (binary or PEM encoding)
- - `PKCS#8`_ `PrivateKeyInfo` DER SEQUENCE (binary or PEM encoding)
+ - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding)
+ - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo``
+ DER SEQUENCE (binary or PEM encoding)
- OpenSSH (textual public key only)
For details about the PEM encoding, see `RFC1421`_/`RFC1423`_.
-
- In case of PEM encoding, the private key can be encrypted with DES or 3TDES according to a certain ``pass phrase``.
- Only OpenSSL-compatible pass phrases are supported.
- :Type externKey: string
+
+ The private key may be encrypted by means of a certain pass phrase
+ either at the PEM level or at the PKCS#8 level.
+ :Type extern_key: string
:Parameter passphrase:
- In case of an encrypted PEM key, this is the pass phrase from which the encryption key is derived.
+ In case of an encrypted private key, this is the pass phrase from
+ which the decryption key is derived.
:Type passphrase: string
-
+
:Return: An RSA key object (`_RSAobj`).
:Raise ValueError/IndexError/TypeError:
- When the given key cannot be parsed (possibly because the pass phrase is wrong).
+ 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
.. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt
.. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt
"""
- externKey = tobytes(externKey)
+ extern_key = tobytes(extern_key)
if passphrase is not None:
passphrase = tobytes(passphrase)
- if externKey.startswith(b('-----')):
- # This is probably a PEM encoded key
- lines = externKey.replace(b(" "),b('')).split()
- keyobj = None
-
- # 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 ')):
+ 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-rsa ')):
# This is probably an OpenSSH key
- keystring = binascii.a2b_base64(externKey.split(b(' '))[1])
+ keystring = binascii.a2b_base64(extern_key.split(b(' '))[1])
keyparts = []
- while len(keystring)>4:
- l = struct.unpack(">I",keystring[:4])[0]
- keyparts.append(keystring[4:4+l])
- keystring = keystring[4+l:]
+ while len(keystring) > 4:
+ l = struct.unpack(">I", keystring[:4])[0]
+ keyparts.append(keystring[4:4 + l])
+ keystring = keystring[4 + l:]
e = bytes_to_long(keyparts[1])
n = bytes_to_long(keyparts[2])
return self.construct([n, e])
- if bord(externKey[0])==0x30:
+
+ if bord(extern_key[0]) == 0x30:
# This is probably a DER encoded key
- return self._importKeyDER(externKey)
-
+ return self._importKeyDER(extern_key, passphrase)
+
raise ValueError("RSA key format is not supported")
-#: This is the ASN.1 DER object that qualifies an algorithm as
-#: compliant to PKCS#1 (that is, the standard RSA).
-# 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).
-# 0x06 0x09 OBJECT IDENTIFIER, 9 bytes of payload
-# 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x01 0x01
-# rsaEncryption (1 2 840 113549 1 1 1) (PKCS #1)
-# 0x05 0x00 NULL
+#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates
+#: a generic RSA key, even when such key will be actually used for digital
+#: signatures.
+#:
+#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html
+oid = "1.2.840.113549.1.1.1"
+
+#: This is the standard DER object that qualifies a cryptographic algorithm
+#: in ASN.1-based data structures (e.g. X.509 certificates).
algorithmIdentifier = DerSequence(
- [ b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'),
- DerNull().encode() ]
+ [DerObjectId(oid).encode(), # algorithm field
+ DerNull().encode()] # parameters field
).encode()
_impl = RSAImplementation()
diff --git a/lib/Crypto/PublicKey/_DSA.py b/lib/Crypto/PublicKey/_DSA.py
index 6b7a964..f027d92 100644
--- a/lib/Crypto/PublicKey/_DSA.py
+++ b/lib/Crypto/PublicKey/_DSA.py
@@ -30,7 +30,7 @@ __revision__ = "$Id$"
from Crypto.PublicKey.pubkey import *
from Crypto.Util import number
from Crypto.Util.number import bytes_to_long, long_to_bytes
-from Crypto.Hash import SHA
+from Crypto.Hash import SHA1
from Crypto.Util.py3compat import *
class error (Exception):
@@ -38,8 +38,8 @@ class error (Exception):
def generateQ(randfunc):
S=randfunc(20)
- hash1=SHA.new(S).digest()
- hash2=SHA.new(long_to_bytes(bytes_to_long(S)+1)).digest()
+ hash1=SHA1.new(S).digest()
+ hash2=SHA1.new(long_to_bytes(bytes_to_long(S)+1)).digest()
q = bignum(0)
for i in range(0,20):
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)
while C<4096:
for k in range(0, n+1):
- V[k]=bytes_to_long(SHA.new(S+bstr(N)+bstr(k)).digest())
+ V[k]=bytes_to_long(SHA1.new(S+bstr(N)+bstr(k)).digest())
W=V[n] % powb
for k in range(n-1, -1, -1):
W=(W<<160L)+V[k]
diff --git a/lib/Crypto/PublicKey/__init__.py b/lib/Crypto/PublicKey/__init__.py
index 503809f..df60c25 100644
--- a/lib/Crypto/PublicKey/__init__.py
+++ b/lib/Crypto/PublicKey/__init__.py
@@ -36,6 +36,9 @@ Crypto.PublicKey.RSA (Signing, encryption, and blinding)
:undocumented: _DSA, _RSA, _fastmath, _slowmath, pubkey
"""
+class KeyFormatError(ValueError):
+ pass
+
__all__ = ['RSA', 'DSA', 'ElGamal']
__revision__ = "$Id$"
diff --git a/lib/Crypto/Random/Fortuna/FortunaAccumulator.py b/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
index 6ffbdc5..5ffe825 100644
--- a/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
+++ b/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
@@ -36,6 +36,9 @@ import warnings
from Crypto.pct_warnings import ClockRewindWarning
import SHAd256
+# If the system has monotonic time, we'll use it.
+from Crypto.Util._time import maybe_monotonic_time
+
import FortunaGenerator
class FortunaPool(object):
@@ -136,7 +139,7 @@ class FortunaAccumulator(object):
self.last_reseed = None
def random_data(self, bytes):
- current_time = time.time()
+ current_time = maybe_monotonic_time()
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)
self.last_reseed = None
@@ -149,7 +152,7 @@ class FortunaAccumulator(object):
def _reseed(self, current_time=None):
if current_time is None:
- current_time = time.time()
+ current_time = maybe_monotonic_time()
seed = []
self.reseed_count += 1
self.last_reseed = current_time
diff --git a/lib/Crypto/Random/Fortuna/FortunaGenerator.py b/lib/Crypto/Random/Fortuna/FortunaGenerator.py
index 723fa63..09351fc 100644
--- a/lib/Crypto/Random/Fortuna/FortunaGenerator.py
+++ b/lib/Crypto/Random/Fortuna/FortunaGenerator.py
@@ -25,7 +25,7 @@
__revision__ = "$Id$"
import sys
-if sys.version_info[0] is 2 and sys.version_info[1] is 1:
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
diff --git a/lib/Crypto/Random/OSRNG/nt.py b/lib/Crypto/Random/OSRNG/nt.py
index c1c2f44..40aa495 100644
--- a/lib/Crypto/Random/OSRNG/nt.py
+++ b/lib/Crypto/Random/OSRNG/nt.py
@@ -25,7 +25,7 @@
__revision__ = "$Id$"
__all__ = ['WindowsRNG']
-import winrandom
+from Crypto.Random.OSRNG import winrandom
from rng_base import BaseRNG
class WindowsRNG(BaseRNG):
diff --git a/lib/Crypto/Random/random.py b/lib/Crypto/Random/random.py
index bef02e6..6b1c57a 100644
--- a/lib/Crypto/Random/random.py
+++ b/lib/Crypto/Random/random.py
@@ -103,13 +103,13 @@ class StrongRandom(object):
def shuffle(self, x):
"""Shuffle the sequence in place."""
- # Make a (copy) of the list of objects we want to shuffle
- items = list(x)
-
- # Choose a random item (without replacement) until all the items have been
- # chosen.
- for i in xrange(len(x)):
- x[i] = items.pop(self.randrange(len(items)))
+ # Fisher-Yates shuffle. O(n)
+ # See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ # Working backwards from the end of the array, we choose a random item
+ # from the remaining items until all items have been chosen.
+ for i in xrange(len(x)-1, 0, -1): # iterate from len(x)-1 downto 1
+ j = self.randrange(0, i+1) # choose random j such that 0 <= j <= i
+ x[i], x[j] = x[j], x[i] # exchange x[i] and x[j]
def sample(self, population, k):
"""Return a k-length list of unique elements chosen from the population sequence."""
diff --git a/lib/Crypto/SelfTest/Cipher/common.py b/lib/Crypto/SelfTest/Cipher/common.py
index 8bebed9..a20a3aa 100644
--- a/lib/Crypto/SelfTest/Cipher/common.py
+++ b/lib/Crypto/SelfTest/Cipher/common.py
@@ -24,6 +24,8 @@
"""Self-testing for PyCrypto hash modules"""
+from __future__ import nested_scopes
+
__revision__ = "$Id$"
import sys
@@ -195,18 +197,43 @@ class CTRWraparoundTest(unittest.TestCase):
self.module_name = params.get('module_name', None)
def shortDescription(self):
- return """Regression test: %s with MODE_CTR should raise OverflowError on wraparound when shortcut used""" % (self.module_name,)
+ return """Regression test: %s with MODE_CTR raising OverflowError on wraparound""" % (self.module_name,)
def runTest(self):
from Crypto.Util import Counter
- for disable_shortcut in (0, 1): # (False, True) Test CTR-mode shortcut and PyObject_CallObject code paths
- for little_endian in (0, 1): # (False, True) Test both endiannesses
- 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)
- cipher = self.module.new(a2b_hex(self.key), self.module.MODE_CTR, counter=ctr)
- block = b("\x00") * self.module.block_size
- cipher.encrypt(block)
- self.assertRaises(OverflowError, cipher.encrypt, block)
+ def pythonCounter():
+ 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
+ block = b("\x00") * self.module.block_size
+
+ # 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.encrypt(block)
+ self.assertRaises(OverflowError, cipher.encrypt, block)
+ self.assertRaises(OverflowError, cipher.encrypt, block)
class CFBSegmentSizeTest(unittest.TestCase):
@@ -289,7 +316,7 @@ class IVLengthTest(unittest.TestCase):
def _dummy_counter(self):
return "\0" * self.module.block_size
-def make_block_tests(module, module_name, test_data):
+def make_block_tests(module, module_name, test_data, additional_params=dict()):
tests = []
extra_tests_added = 0
for i in range(len(test_data)):
@@ -326,6 +353,7 @@ def make_block_tests(module, module_name, test_data):
name = "%s #%d: %s" % (module_name, i+1, description)
params['description'] = name
params['module_name'] = module_name
+ params.update(additional_params)
# Add extra test(s) to the test suite before the current test
if not extra_tests_added:
@@ -343,7 +371,7 @@ def make_block_tests(module, module_name, test_data):
tests.append(CipherSelfTest(module, params))
# When using CTR mode, test that the interface behaves like a stream cipher
- if p_mode == 'CTR':
+ if p_mode in ('OFB', 'CTR'):
tests.append(CipherStreamingSelfTest(module, params))
# When using CTR mode, test the non-shortcut code path.
diff --git a/lib/Crypto/SelfTest/Cipher/test_AES.py b/lib/Crypto/SelfTest/Cipher/test_AES.py
index ea7c323..8fd4a6f 100644
--- a/lib/Crypto/SelfTest/Cipher/test_AES.py
+++ b/lib/Crypto/SelfTest/Cipher/test_AES.py
@@ -26,8 +26,11 @@
__revision__ = "$Id$"
-from common import dict # For compatibility with Python 2.1 and 2.2
+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 binascii import hexlify
# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples.
@@ -1321,6 +1324,30 @@ test_data = [
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'+
'30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710',
'874d6191b620e3261bef6864990db6ce'+'9806f66b7970fdff8617187bb9fffdff'+
'5ae4df3edbd5d35e5b4f09020db03eab'+'1e031dda2fbe03d1792170a0f3009cee',
@@ -1422,8 +1449,14 @@ test_data = [
def get_tests(config={}):
from Crypto.Cipher import AES
+ from Crypto.Util import cpuid
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__':
import unittest
diff --git a/lib/Crypto/SelfTest/Cipher/test_ARC4.py b/lib/Crypto/SelfTest/Cipher/test_ARC4.py
index 4e039d1..801d2cb 100644
--- a/lib/Crypto/SelfTest/Cipher/test_ARC4.py
+++ b/lib/Crypto/SelfTest/Cipher/test_ARC4.py
@@ -27,6 +27,10 @@
__revision__ = "$Id$"
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.
test_data = [
@@ -68,10 +72,382 @@ test_data = [
"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={}):
- from Crypto.Cipher import ARC4
from common import make_stream_tests
- return make_stream_tests(ARC4, "ARC4", test_data)
+ tests = make_stream_tests(ARC4, "ARC4", test_data)
+ tests += list_test_cases(RFC6229_Tests)
+ tests += list_test_cases(Drop_Tests)
+ return tests
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py b/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py
index accca61..86c38a3 100644
--- a/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py
+++ b/lib/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py
@@ -31,7 +31,7 @@ from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex
from Crypto.Util.py3compat import *
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP as PKCS
-from Crypto.Hash import MD2,MD5,SHA as SHA1,SHA256,RIPEMD
+from Crypto.Hash import MD2,MD5,SHA1,SHA256,RIPEMD160
from Crypto import Random
def rws(t):
@@ -314,11 +314,12 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
# Encrypt/Decrypt messages of length [0..128-2*20-2]
for pt_len in xrange(0,128-2*20-2):
pt = self.rng(pt_len)
- ct = PKCS.encrypt(pt, self.key1024)
- pt2 = PKCS.decrypt(ct, self.key1024)
+ cipher = PKCS.new(self.key1024)
+ ct = cipher.encrypt(pt)
+ pt2 = cipher.decrypt(ct)
self.assertEqual(pt,pt2)
- def testEncryptDecrypt1(self):
+ def testEncryptDecrypt2(self):
# Helper function to monitor what's requested from RNG
global asked
def localRng(N):
@@ -326,7 +327,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
asked += N
return self.rng(N)
# Verify that OAEP is friendly to all hashes
- for hashmod in (MD2,MD5,SHA1,SHA256,RIPEMD):
+ for hashmod in (MD2,MD5,SHA1,SHA256,RIPEMD160):
# Verify that encrypt() asks for as many random bytes
# as the hash output size
asked = 0
@@ -337,7 +338,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
self.assertEqual(cipher.decrypt(ct), pt)
self.failUnless(asked > hashmod.digest_size)
- def testEncryptDecrypt2(self):
+ def testEncryptDecrypt3(self):
# Verify that OAEP supports labels
pt = self.rng(35)
xlabel = self.rng(22)
@@ -345,7 +346,7 @@ class PKCS1_OAEP_Tests(unittest.TestCase):
ct = cipher.encrypt(pt)
self.assertEqual(cipher.decrypt(ct), pt)
- def testEncryptDecrypt3(self):
+ def testEncryptDecrypt4(self):
# Verify that encrypt() uses the custom MGF
global mgfcalls
# Helper function to monitor what's requested from MGF
diff --git a/lib/Crypto/SelfTest/Hash/__init__.py b/lib/Crypto/SelfTest/Hash/__init__.py
index bb19f9b..d6c8e57 100644
--- a/lib/Crypto/SelfTest/Hash/__init__.py
+++ b/lib/Crypto/SelfTest/Hash/__init__.py
@@ -28,13 +28,13 @@ __revision__ = "$Id$"
def get_tests(config={}):
tests = []
- from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.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_MD5; tests += test_MD5.get_tests(config=config)
- from Crypto.SelfTest.Hash import test_RIPEMD; tests += test_RIPEMD.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_HMAC; tests += test_HMAC.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_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_SHA1; tests += test_SHA1.get_tests(config=config)
+ from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config)
try:
from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config)
from Crypto.SelfTest.Hash import test_SHA384; tests += test_SHA384.get_tests(config=config)
diff --git a/lib/Crypto/SelfTest/Hash/common.py b/lib/Crypto/SelfTest/Hash/common.py
index f77fb0f..48cebe7 100644
--- a/lib/Crypto/SelfTest/Hash/common.py
+++ b/lib/Crypto/SelfTest/Hash/common.py
@@ -29,7 +29,10 @@ __revision__ = "$Id$"
import sys
import unittest
import binascii
+import Crypto.Hash
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
if sys.hexversion < 0x02030000:
@@ -94,11 +97,27 @@ class HashSelfTest(unittest.TestCase):
self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest()
self.assertEqual(self.expected, out4) # h = .new(data); h.digest()
- # Verify that new() object method produces a fresh hash object
- h2 = h.new()
- h2.update(self.input)
- out5 = binascii.b2a_hex(h2.digest())
- self.assertEqual(self.expected, out5)
+ # Verify that the .new() method produces a fresh hash object, except
+ # 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.update(self.input)
+ out5 = binascii.b2a_hex(h2.digest())
+ 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):
def __init__(self, hashmod, oid):
@@ -107,16 +126,38 @@ class HashTestOID(unittest.TestCase):
self.oid = oid
def runTest(self):
+ from Crypto.Signature import PKCS1_v1_5
h = self.hashmod.new()
- if self.oid==None:
- try:
- raised = 0
- a = h.oid
- except AttributeError:
- raised = 1
- self.assertEqual(raised,1)
- else:
- self.assertEqual(h.oid, self.oid)
+ self.assertEqual(PKCS1_v1_5._HASH_OIDS[h.name], self.oid)
+
+class HashDocStringTest(unittest.TestCase):
+ def __init__(self, hashmod):
+ unittest.TestCase.__init__(self)
+ self.hashmod = hashmod
+
+ def runTest(self):
+ docstring = self.hashmod.__doc__
+ 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):
@@ -178,11 +219,13 @@ def make_hash_tests(module, module_name, test_data, digest_size, oid=None):
description = row[2].encode('latin-1')
name = "%s #%d: %s" % (module_name, i+1, description)
tests.append(HashSelfTest(module, name, expected, input))
- if oid is not None:
- oid = b(oid)
name = "%s #%d: digest_size" % (module_name, i+1)
tests.append(HashDigestSizeSelfTest(module, name, digest_size))
- tests.append(HashTestOID(module, oid))
+ if oid is not None:
+ tests.append(HashTestOID(module, oid))
+ tests.append(HashDocStringTest(module))
+ if getattr(module, 'name', None) is not None:
+ tests.append(GenericHashConstructorTest(module))
return tests
def make_mac_tests(module, module_name, test_data, hashmods):
diff --git a/lib/Crypto/SelfTest/Hash/test_HMAC.py b/lib/Crypto/SelfTest/Hash/test_HMAC.py
index c01c97b..85bdf47 100644
--- a/lib/Crypto/SelfTest/Hash/test_HMAC.py
+++ b/lib/Crypto/SelfTest/Hash/test_HMAC.py
@@ -203,7 +203,7 @@ hashlib_test_data = [
def get_tests(config={}):
global test_data
- from Crypto.Hash import HMAC, MD5, SHA as SHA1, SHA256
+ from Crypto.Hash import HMAC, MD5, SHA1, SHA256
from common import make_mac_tests
hashmods = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256, default=None)
try:
diff --git a/lib/Crypto/SelfTest/Hash/test_MD2.py b/lib/Crypto/SelfTest/Hash/test_MD2.py
index db636d4..fd03e78 100644
--- a/lib/Crypto/SelfTest/Hash/test_MD2.py
+++ b/lib/Crypto/SelfTest/Hash/test_MD2.py
@@ -54,7 +54,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(MD2, "MD2", test_data,
digest_size=16,
- oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02")
+ oid="1.2.840.113549.2.2")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_MD4.py b/lib/Crypto/SelfTest/Hash/test_MD4.py
index 1727bb6..7dbf49f 100644
--- a/lib/Crypto/SelfTest/Hash/test_MD4.py
+++ b/lib/Crypto/SelfTest/Hash/test_MD4.py
@@ -54,7 +54,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(MD4, "MD4", test_data,
digest_size=16,
- oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04")
+ oid="1.2.840.113549.2.4")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_MD5.py b/lib/Crypto/SelfTest/Hash/test_MD5.py
index 2e293fc..0683113 100644
--- a/lib/Crypto/SelfTest/Hash/test_MD5.py
+++ b/lib/Crypto/SelfTest/Hash/test_MD5.py
@@ -54,7 +54,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(MD5, "MD5", test_data,
digest_size=16,
- oid="\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05")
+ oid="1.2.840.113549.2.5")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_RIPEMD.py b/lib/Crypto/SelfTest/Hash/test_RIPEMD160.py
index 6673a93..b0d6980 100644
--- a/lib/Crypto/SelfTest/Hash/test_RIPEMD.py
+++ b/lib/Crypto/SelfTest/Hash/test_RIPEMD160.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# SelfTest/Hash/test_RIPEMD.py: Self-test for the RIPEMD-160 hash function
+# SelfTest/Hash/test_RIPEMD160.py: Self-test for the RIPEMD-160 hash function
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
@@ -22,7 +22,7 @@
# SOFTWARE.
# ===================================================================
-#"""Self-test suite for Crypto.Hash.RIPEMD"""
+#"""Self-test suite for Crypto.Hash.RIPEMD160"""
__revision__ = "$Id$"
@@ -59,11 +59,11 @@ test_data = [
]
def get_tests(config={}):
- from Crypto.Hash import RIPEMD
+ from Crypto.Hash import RIPEMD160
from common import make_hash_tests
- return make_hash_tests(RIPEMD, "RIPEMD", test_data,
+ return make_hash_tests(RIPEMD160, "RIPEMD160", test_data,
digest_size=20,
- oid="\x06\x05\x2b\x24\x03\02\x01")
+ oid="1.3.36.3.2.1")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_SHA.py b/lib/Crypto/SelfTest/Hash/test_SHA1.py
index 7d72e77..436f7de 100644
--- a/lib/Crypto/SelfTest/Hash/test_SHA.py
+++ b/lib/Crypto/SelfTest/Hash/test_SHA1.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# SelfTest/Hash/SHA.py: Self-test for the SHA-1 hash function
+# SelfTest/Hash/SHA1.py: Self-test for the SHA-1 hash function
#
# Written in 2008 by Dwayne C. Litzenberger <dlitz@dlitz.net>
#
@@ -50,11 +50,11 @@ test_data = [
]
def get_tests(config={}):
- from Crypto.Hash import SHA
+ from Crypto.Hash import SHA1
from common import make_hash_tests
- return make_hash_tests(SHA, "SHA", test_data,
+ return make_hash_tests(SHA1, "SHA1", test_data,
digest_size=20,
- oid="\x06\x05\x2B\x0E\x03\x02\x1A")
+ oid="1.3.14.3.2.26")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_SHA224.py b/lib/Crypto/SelfTest/Hash/test_SHA224.py
index a60f35a..eb28ebc 100644
--- a/lib/Crypto/SelfTest/Hash/test_SHA224.py
+++ b/lib/Crypto/SelfTest/Hash/test_SHA224.py
@@ -55,7 +55,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(SHA224, "SHA224", test_data,
digest_size=28,
- oid='\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04')
+ oid='2.16.840.1.101.3.4.2.4')
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_SHA256.py b/lib/Crypto/SelfTest/Hash/test_SHA256.py
index 4b45110..50bdba8 100644
--- a/lib/Crypto/SelfTest/Hash/test_SHA256.py
+++ b/lib/Crypto/SelfTest/Hash/test_SHA256.py
@@ -81,7 +81,7 @@ def get_tests(config={}):
from common import make_hash_tests
tests = make_hash_tests(SHA256, "SHA256", test_data,
digest_size=32,
- oid="\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01")
+ oid="2.16.840.1.101.3.4.2.1")
if config.get('slow_tests'):
tests += [LargeSHA256Test()]
diff --git a/lib/Crypto/SelfTest/Hash/test_SHA384.py b/lib/Crypto/SelfTest/Hash/test_SHA384.py
index b7a72c0..27d16b3 100644
--- a/lib/Crypto/SelfTest/Hash/test_SHA384.py
+++ b/lib/Crypto/SelfTest/Hash/test_SHA384.py
@@ -53,7 +53,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(SHA384, "SHA384", test_data,
digest_size=48,
- oid='\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02')
+ oid='2.16.840.1.101.3.4.2.2')
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/Hash/test_SHA512.py b/lib/Crypto/SelfTest/Hash/test_SHA512.py
index cb86177..04a505e 100644
--- a/lib/Crypto/SelfTest/Hash/test_SHA512.py
+++ b/lib/Crypto/SelfTest/Hash/test_SHA512.py
@@ -50,7 +50,7 @@ def get_tests(config={}):
from common import make_hash_tests
return make_hash_tests(SHA512, "SHA512", test_data,
digest_size=64,
- oid="\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03")
+ oid="2.16.840.1.101.3.4.2.3")
if __name__ == '__main__':
import unittest
diff --git a/lib/Crypto/SelfTest/IO/__init__.py b/lib/Crypto/SelfTest/IO/__init__.py
new file mode 100644
index 0000000..084904e
--- /dev/null
+++ b/lib/Crypto/SelfTest/IO/__init__.py
@@ -0,0 +1,34 @@
+#
+# SelfTest/IO/__init__.py: Self-test for input/output module
+#
+# ===================================================================
+# 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 for I/O"""
+
+def get_tests(config={}):
+ tests = []
+ from Crypto.SelfTest.IO import test_PKCS8; tests += test_PKCS8.get_tests(config=config)
+ return tests
+
+if __name__ == '__main__':
+ import unittest
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
+
diff --git a/lib/Crypto/SelfTest/IO/test_PKCS8.py b/lib/Crypto/SelfTest/IO/test_PKCS8.py
new file mode 100644
index 0000000..09d3554
--- /dev/null
+++ b/lib/Crypto/SelfTest/IO/test_PKCS8.py
@@ -0,0 +1,419 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/PublicKey/test_PKCS8.py: Self-test for the PKCS8 module
+#
+# ===================================================================
+# 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-tests for Crypto.PublicKey.PKCS8 module"""
+
+__revision__ = "$Id$"
+
+import unittest
+import sys
+
+from Crypto.Util.py3compat import *
+from Crypto.Util.asn1 import *
+from Crypto.IO import PKCS8
+from binascii import *
+
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+
+oid_key = '1.2.840.113549.1.1.1'
+
+# Original RSA key (in DER format)
+# hexdump -v -e '32/1 "%02x" "\n"' key.der
+clear_key="""
+308201ab020100025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf16
+0c951a870b71783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f0
+6fe20faeebb0c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d2
+5c08050203010001025a00afa09c70d528299b7552fe766b5d20f9a221d66938
+c3b68371d48515359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb
+3a50b8e17ba297b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee89
+3f039395022d0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e8
+8dfbc3f7e0bb83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd7
+1f56ae7d973e08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3
+c24f022d0ac334eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec9
+4fcf16352f6b3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb03
+09920905c236d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5
+022d0cd88ed14fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa3
+7e2e93df3ff1a0fd3490111dcdbc4c
+"""
+
+# Same key as above, wrapped in PKCS#8 but w/o password
+#
+# openssl pkcs8 -topk8 -inform DER -nocrypt -in key.der -outform DER -out keyp8.der
+# hexdump -v -e '32/1 "%02x" "\n"' keyp8.der
+wrapped_clear_key="""
+308201c5020100300d06092a864886f70d0101010500048201af308201ab0201
+00025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf160c951a870b71
+783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f06fe20faeebb0
+c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d25c0805020301
+0001025a00afa09c70d528299b7552fe766b5d20f9a221d66938c3b68371d485
+15359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb3a50b8e17ba2
+97b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee893f039395022d
+0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e88dfbc3f7e0bb
+83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd71f56ae7d973e
+08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3c24f022d0ac3
+34eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec94fcf16352f6b
+3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb0309920905c236
+d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5022d0cd88ed1
+4fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa37e2e93df3ff1
+a0fd3490111dcdbc4c
+"""
+
+###
+#
+# The key above will now be encrypted with different algorithms.
+# The password is always 'TestTest'.
+#
+# Each item in the wrapped_enc_keys list contains:
+# * wrap algorithm
+# * iteration count
+# * Salt
+# * IV
+# * Expected result
+###
+wrapped_enc_keys = []
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -v2 des3
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC',
+2048,
+"47EA7227D8B22E2F", # IV
+"E3F7A838AB911A4D", # Salt
+"""
+30820216304006092a864886f70d01050d3033301b06092a864886f70d01050c
+300e0408e3f7a838ab911a4d02020800301406082a864886f70d0307040847ea
+7227d8b22e2f048201d0ea388b374d2d0e4ceb7a5139f850fdff274884a6e6c0
+64326e09d00dbba9018834edb5a51a6ae3d1806e6e91eebf33788ce71fee0637
+a2ebf58859dd32afc644110c390274a6128b50c39b8d907823810ec471bada86
+6f5b75d8ea04ad310fad2e73621696db8e426cd511ee93ec1714a1a7db45e036
+4bf20d178d1f16bbb250b32c2d200093169d588de65f7d99aad9ddd0104b44f1
+326962e1520dfac3c2a800e8a14f678dff2b3d0bb23f69da635bf2a643ac934e
+219a447d2f4460b67149e860e54f365da130763deefa649c72b0dcd48966a2d3
+4a477444782e3e66df5a582b07bbb19778a79bd355074ce331f4a82eb966b0c4
+52a09eab6116f2722064d314ae433b3d6e81d2436e93fdf446112663cde93b87
+9c8be44beb45f18e2c78fee9b016033f01ecda51b9b142091fa69f65ab784d2c
+5ad8d34be6f7f1464adfc1e0ef3f7848f40d3bdea4412758f2fcb655c93d8f4d
+f6fa48fc5aa4b75dd1c017ab79ac9d737233a6d668f5364ccf47786debd37334
+9c10c9e6efbe78430a61f71c89948aa32cdc3cc7338cf994147819ce7ab23450
+c8f7d9b94c3bb377d17a3fa204b601526317824b142ff6bc843fa7815ece89c0
+839573f234dac8d80cc571a045353d61db904a4398d8ef3df5ac
+"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+-1, # pbeWithMD5AndDES-CBC, only decoding is supported
+-1,
+"",
+"",
+"""
+308201f1301b06092a864886f70d010503300e0408f9b990c89af1d41b020208
+00048201d0c6267fe8592903891933d559e71a7ca68b2e39150f19daca0f7921
+52f97e249d72f670d5140e9150433310ed7c7ee51927693fd39884cb9551cea5
+a7b746f7edf199f8787d4787a35dad930d7db057b2118851211b645ac8b90fa6
+b0e7d49ac8567cbd5fff226e87aa9129a0f52c45e9307752e8575c3b0ff756b7
+31fda6942d15ecb6b27ea19370ccc79773f47891e80d22b440d81259c4c28eac
+e0ca839524116bcf52d8c566e49a95ddb0e5493437279a770a39fd333f3fca91
+55884fad0ba5aaf273121f893059d37dd417da7dcfd0d6fa7494968f13b2cc95
+65633f2c891340193e5ec00e4ee0b0e90b3b93da362a4906360845771ade1754
+9df79140be5993f3424c012598eadd3e7c7c0b4db2c72cf103d7943a5cf61420
+93370b9702386c3dd4eb0a47f34b579624a46a108b2d13921fa1b367495fe345
+6aa128aa70f8ca80ae13eb301e96c380724ce67c54380bbea2316c1faf4d058e
+b4ca2e23442047606b9bc4b3bf65b432cb271bea4eb35dd3eb360d3be8612a87
+a50e96a2264490aeabdc07c6e78e5dbf4fe3388726d0e2a228346bf3c2907d68
+2a6276b22ae883fb30fa611f4e4193e7a08480fcd7db48308bacbd72bf4807aa
+11fd394859f97d22982f7fe890b2e2a0f7e7ffb693
+"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v1 PBE-SHA1-RC2-64
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+-1, # pbeWithSHA1AndRC2-CBC, only decoding is supported
+-1,
+"",
+"",
+"""
+308201f1301b06092a864886f70d01050b300e04083ee943bdae185008020208
+00048201d0e4614d9371d3ff10ceabc2f6a7a13a0f449f9a714144e46518ea55
+e3e6f0cde24031d01ef1f37ec40081449ef01914faf45983dde0d2bc496712de
+8dd15a5527dff4721d9016c13f34fb93e3ce68577e30146266d71b539f854e56
+753a192cf126ed4812734d86f81884374f1100772f78d0646e9946407637c565
+d070acab413c55952f7237437f2e48cae7fa0ff8d370de2bf446dd08049a3663
+d9c813ac197468c02e2b687e7ca994cf7f03f01b6eca87dbfed94502c2094157
+ea39f73fe4e591df1a68b04d19d9adab90bb9898467c1464ad20bf2b8fb9a5ff
+d3ec91847d1c67fd768a4b9cfb46572eccc83806601372b6fad0243f58f623b7
+1c5809dea0feb8278fe27e5560eed8448dc93f5612f546e5dd7c5f6404365eb2
+5bf3396814367ae8b15c5c432b57eaed1f882c05c7f6517ee9e42b87b7b8d071
+9d6125d1b52f7b2cca1f6bd5f584334bf90bce1a7d938274cafe27b68e629698
+b16e27ae528db28593af9adcfccbebb3b9e1f2af5cd5531b51968389caa6c091
+e7de1f1b96f0d258e54e540d961a7c0ef51fda45d6da5fddd33e9bbfd3a5f8d7
+d7ab2e971de495cddbc86d38444fee9f0ac097b00adaf7802dabe0cff5b43b45
+4f26b7b547016f89be52676866189911c53e2f2477"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v1 PBE-MD5-RC2-64
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+-1, # pbeWithMD5AndRC2-CBC, only decoding is supported
+-1,
+"",
+"",
+"""
+308201f1301b06092a864886f70d010506300e0408f5cd2fee56d9b4b8020208
+00048201d086454942d6166a19d6b108465bd111e7080911f573d54b1369c676
+df28600e84936bfec04f91023ff16499e2e07178c340904f12ffa6886ab66228
+32bf43c2bff5a0ed14e765918cf5fc543ad49566246f7eb3fc044fa5a9c25f40
+8fc8c8296b91658d3bb1067c0aba008c4fefd9e2bcdbbbd63fdc8085482bccf4
+f150cec9a084259ad441a017e5d81a1034ef2484696a7a50863836d0eeda45cd
+8cee8ecabfed703f8d9d4bbdf3a767d32a0ccdc38550ee2928d7fe3fa27eda5b
+5c7899e75ad55d076d2c2d3c37d6da3d95236081f9671dab9a99afdb1cbc890e
+332d1a91105d9a8ce08b6027aa07367bd1daec3059cb51f5d896124da16971e4
+0ca4bcadb06c854bdf39f42dd24174011414e51626d198775eff3449a982df7b
+ace874e77e045eb6d7c3faef0750792b29a068a6291f7275df1123fac5789c51
+27ace42836d81633faf9daf38f6787fff0394ea484bbcd465b57d4dbee3cf8df
+b77d1db287b3a6264c466805be5a4fe85cfbca180699859280f2dd8e2c2c10b5
+7a7d2ac670c6039d41952fbb0e4f99b560ebe1d020e1b96d02403283819c00cc
+529c51f0b0101555e4c58002ba3c6e3c12e3fde1aec94382792e96d9666a2b33
+3dc397b22ecab67ee38a552fec29a1d4ff8719c748"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v1 PBE-SHA1-DES
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+-1, # pbeWithSHA1AndDES-CBC, only decoding is supported
+-1,
+"",
+"",
+"""
+308201f1301b06092a864886f70d01050a300e04089bacc9cf1e8f734e020208
+00048201d03e502f3ceafe8fd19ab2939576bfdded26d719b2441db1459688f5
+9673218b41ec1f739edf1e460bd927bc28470c87b2d4fc8ea02ba17b47a63c49
+c5c1bee40529dadfd3ef8b4472c730bc136678c78abfb34670ec9d7dcd17ee3f
+892f93f2629e6e0f4b24ecb9f954069bf722f466dece3913bb6abbd2c471d9a5
+c5eea89b14aaccda43d30b0dd0f6eb6e9850d9747aa8aa8414c383ad01c374ee
+26d3552abec9ba22669cc9622ccf2921e3d0c8ecd1a70e861956de0bec6104b5
+b649ac994970c83f8a9e84b14a7dff7843d4ca3dd4af87cea43b5657e15ae0b5
+a940ce5047f006ab3596506600724764f23757205fe374fee04911336d655acc
+03e159ec27789191d1517c4f3f9122f5242d44d25eab8f0658cafb928566ca0e
+8f6589aa0c0ab13ca7a618008ae3eafd4671ee8fe0b562e70b3623b0e2a16eee
+97fd388087d2e03530c9fe7db6e52eccc7c48fd701ede35e08922861a9508d12
+bc8bbf24f0c6bee6e63dbcb489b603d4c4a78ce45bf2eab1d5d10456c42a65a8
+3a606f4e4b9b46eb13b57f2624b651859d3d2d5192b45dbd5a2ead14ff20ca76
+48f321309aa56d8c0c4a192b580821cc6c70c75e6f19d1c5414da898ec4dd39d
+b0eb93d6ba387a80702dfd2db610757ba340f63230
+"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v2 aes128
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+'PBKDF2WithHMAC-SHA1AndAES128-CBC',
+2048,
+"4F66EE5D3BCD531FE6EBF4B4E73016B8", # IV
+"479F25156176C53A", # Salt
+"""
+3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
+300e0408479f25156176c53a02020800301d060960864801650304010204104f
+66ee5d3bcd531fe6ebf4b4e73016b8048201d0e33cfa560423f589d097d21533
+3b880a5ebac5b2ac58b4e73b0d787aee7764f034fe34ca1d1bd845c0a7c3316f
+afbfb2129e03dcaf5a5031394206492828dacef1e04639bee5935e0f46114202
+10bc6c37182f4889be11c5d0486c398f4be952e5740f65de9d8edeb275e2b406
+e19bc29ad5ebb97fa536344fc3d84c7e755696f12b810898de4e6f069b8a81c8
+0aab0d45d7d062303aaa4a10c2ce84fdb5a03114039cfe138e38bb15b2ced717
+93549cdad85e730b14d9e2198b663dfdc8d04a4349eb3de59b076ad40b116d4a
+25ed917c576bc7c883c95ef0f1180e28fc9981bea069594c309f1aa1b253ceab
+a2f0313bb1372bcb51a745056be93d77a1f235a762a45e8856512d436b2ca0f7
+dd60fbed394ba28978d2a2b984b028529d0a58d93aba46c6bbd4ac1e4013cbaa
+63b00988bc5f11ccc40141c346762d2b28f64435d4be98ec17c1884985e3807e
+e550db606600993efccf6de0dfc2d2d70b5336a3b018fa415d6bdd59f5777118
+16806b7bc17c4c7e20ad7176ebfa5a1aa3f6bc10f04b77afd443944642ac9cca
+d740e082b4a3bbb8bafdd34a0b3c5f2f3c2aceccccdccd092b78994b845bfa61
+706c3b9df5165ed1dbcbf1244fe41fc9bf993f52f7658e2f87e1baaeacb0f562
+9d905c
+"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v2 aes192
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+'PBKDF2WithHMAC-SHA1AndAES192-CBC',
+2048,
+"5CFC2A4FF7B63201A4A8A5B021148186", # IV
+"D718541C264944CE", # Salt
+"""
+3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
+300e0408d718541c264944ce02020800301d060960864801650304011604105c
+fc2a4ff7b63201a4a8a5b021148186048201d08e74aaa21b8bcfb15b9790fe95
+b0e09ddb0f189b6fb1682fdb9f122b804650ddec3c67a1df093a828b3e5fbcc6
+286abbcc5354c482fd796d972e919ca8a5eba1eaa2293af1d648013ddad72106
+75622264dfba55dafdda39e338f058f1bdb9846041ffff803797d3fdf3693135
+8a192729ea8346a7e5e58e925a2e2e4af0818581859e8215d87370eb4194a5ff
+bae900857d4c591dbc651a241865a817eaede9987c9f9ae4f95c0bf930eea88c
+4d7596e535ffb7ca369988aba75027a96b9d0bc9c8b0b75f359067fd145a378b
+02aaa15e9db7a23176224da48a83249005460cc6e429168657f2efa8b1af7537
+d7d7042f2d683e8271b21d591090963eeb57aea6172f88da139e1614d6a7d1a2
+1002d5a7a93d6d21156e2b4777f6fc069287a85a1538c46b7722ccde591ab55c
+630e1ceeb1ac42d1b41f3f654e9da86b5efced43775ea68b2594e50e4005e052
+0fe753c0898120c2c07265367ff157f6538a1e4080d6f9d1ca9eb51939c9574e
+f2e4e1e87c1434affd5808563cddd376776dbbf790c6a40028f311a8b58dafa2
+0970ed34acd6e3e89d063987893b2b9570ddb8cc032b05a723bba9444933ebf3
+c624204be72f4190e0245197d0cb772bec933fd8442445f9a28bd042d5a3a1e9
+9a8a07
+"""
+))
+
+#
+# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der
+# -outform DER -out keyenc.der -v2 aes192
+# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der
+#
+wrapped_enc_keys.append((
+'PBKDF2WithHMAC-SHA1AndAES256-CBC',
+2048,
+"323351F94462AC563E053A056252C2C4", # IV
+"02A6CD0D12E727B5", # Salt
+"""
+3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c
+300e040802a6cd0d12e727b502020800301d060960864801650304012a041032
+3351f94462ac563e053a056252c2c4048201d07f4ef1c7be21aae738a20c5632
+b8bdbbb9083b6e7f68822267b1f481fd27fdafd61a90660de6e4058790e4c912
+bf3f319a7c37e6eb3d956daaa143865020d554bf6215e8d7492359aaeef45d6e
+d85a686ed26c0bf7c18d071d827a86f0b73e1db0c0e7f3d42201544093302a90
+551ad530692468c47ac15c69500b8ca67d4a17b64d15cecc035ae50b768a36cf
+07c395afa091e9e6f86f665455fbdc1b21ad79c0908b73da5de75a9b43508d5d
+44dc97a870cd3cd9f01ca24452e9b11c1b4982946702cfcbfda5b2fcc0203fb5
+0b52a115760bd635c94d4c95ac2c640ee9a04ffaf6ccff5a8d953dd5d88ca478
+c377811c521f2191639c643d657a9e364af88bb7c14a356c2b0b4870a23c2f54
+d41f8157afff731471dccc6058b15e1151bcf84b39b5e622a3a1d65859c912a5
+591b85e034a1f6af664f030a6bfc8c3d20c70f32b54bcf4da9c2da83cef49cf8
+e9a74f0e5d358fe50b88acdce6a9db9a7ad61536212fc5f877ebfc7957b8bda4
+b1582a0f10d515a20ee06cf768db9c977aa6fbdca7540d611ff953012d009dac
+e8abd059f8e8ffea637c9c7721f817aaf0bb23403e26a0ef0ff0e2037da67d41
+af728481f53443551a9bff4cea023164e9622b5441a309e1f4bff98e5bf76677
+8d7cd9
+"""
+))
+
+def txt2bin(inputs):
+ s = b('').join([b(x) for x in inputs if not (x in '\n\r\t ')])
+ return unhexlify(s)
+
+class Rng:
+ def __init__(self, output):
+ self.output=output
+ self.idx=0
+ def __call__(self, n):
+ output = self.output[self.idx:self.idx+n]
+ self.idx += n
+ return output
+
+class PKCS8_Decrypt(unittest.TestCase):
+
+ def setUp(self):
+ self.oid_key = oid_key
+ self.clear_key = txt2bin(clear_key)
+ self.wrapped_clear_key = txt2bin(wrapped_clear_key)
+ self.wrapped_enc_keys = []
+ for t in wrapped_enc_keys:
+ self.wrapped_enc_keys.append((
+ t[0],
+ t[1],
+ txt2bin(t[2]),
+ txt2bin(t[3]),
+ txt2bin(t[4])
+ ))
+
+ ### NO ENCRYTION
+
+ def test1(self):
+ """Verify unwrapping w/o encryption"""
+ res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key)
+ self.assertEqual(res1, self.oid_key)
+ self.assertEqual(res2, self.clear_key)
+
+ def test2(self):
+ """Verify wrapping w/o encryption"""
+ wrapped = PKCS8.wrap(self.clear_key, self.oid_key)
+ res1, res2, res3 = PKCS8.unwrap(wrapped)
+ self.assertEqual(res1, self.oid_key)
+ self.assertEqual(res2, self.clear_key)
+
+ ## ENCRYPTION
+
+ def test3(self):
+ """Verify unwrapping with encryption"""
+
+ for t in self.wrapped_enc_keys:
+ res1, res2, res3 = PKCS8.unwrap(t[4], b("TestTest"))
+ self.assertEqual(res1, self.oid_key)
+ self.assertEqual(res2, self.clear_key)
+
+ def test4(self):
+ """Verify wrapping with encryption"""
+
+ for t in self.wrapped_enc_keys:
+ if t[0]==-1:
+ continue
+ rng = Rng(t[2]+t[3])
+ params = { 'iteration_count':t[1] }
+ wrapped = PKCS8.wrap(
+ self.clear_key,
+ self.oid_key,
+ b("TestTest"),
+ protection=t[0],
+ prot_params=params,
+ key_params=None,
+ randfunc=rng)
+ self.assertEqual(wrapped, t[4])
+
+def get_tests(config={}):
+ from Crypto.SelfTest.st_common import list_test_cases
+ listTests = []
+ listTests += list_test_cases(PKCS8_Decrypt)
+ return listTests
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
diff --git a/lib/Crypto/SelfTest/Protocol/test_KDF.py b/lib/Crypto/SelfTest/Protocol/test_KDF.py
index 119836b..f0a44d1 100644
--- a/lib/Crypto/SelfTest/Protocol/test_KDF.py
+++ b/lib/Crypto/SelfTest/Protocol/test_KDF.py
@@ -26,7 +26,7 @@ import unittest
from binascii import unhexlify
from Crypto.SelfTest.st_common import list_test_cases
-from Crypto.Hash import SHA as SHA1,HMAC
+from Crypto.Hash import SHA1, HMAC
from Crypto.Protocol.KDF import *
diff --git a/lib/Crypto/SelfTest/PublicKey/__init__.py b/lib/Crypto/SelfTest/PublicKey/__init__.py
index 61ba53f..23a13a4 100644
--- a/lib/Crypto/SelfTest/PublicKey/__init__.py
+++ b/lib/Crypto/SelfTest/PublicKey/__init__.py
@@ -32,7 +32,13 @@ def get_tests(config={}):
tests = []
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_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)
return tests
diff --git a/lib/Crypto/SelfTest/PublicKey/test_RSA.py b/lib/Crypto/SelfTest/PublicKey/test_RSA.py
index c971042..2884317 100644
--- a/lib/Crypto/SelfTest/PublicKey/test_RSA.py
+++ b/lib/Crypto/SelfTest/PublicKey/test_RSA.py
@@ -28,6 +28,7 @@ __revision__ = "$Id$"
import sys
import os
+import pickle
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
@@ -87,6 +88,21 @@ class RSATest(unittest.TestCase):
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):
global RSA, Random, bytes_to_long
from Crypto.PublicKey import RSA
@@ -178,6 +194,31 @@ class RSATest(unittest.TestCase):
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):
# Check capabilities
self.assertEqual(1, rsaObj.has_private())
@@ -352,6 +393,20 @@ class RSAFastMathTest(RSATest):
def 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):
def setUp(self):
RSATest.setUp(self)
@@ -388,6 +443,17 @@ class RSASlowMathTest(RSATest):
def 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={}):
tests = []
tests += list_test_cases(RSATest)
diff --git a/lib/Crypto/SelfTest/PublicKey/test_import_DSA.py b/lib/Crypto/SelfTest/PublicKey/test_import_DSA.py
new file mode 100644
index 0000000..1cb6837
--- /dev/null
+++ b/lib/Crypto/SelfTest/PublicKey/test_import_DSA.py
@@ -0,0 +1,389 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/PublicKey/test_import_DSA.py: Self-test for importing DSA 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.
+# ===================================================================
+
+import unittest
+
+from Crypto.PublicKey import DSA, KeyFormatError
+from Crypto.SelfTest.st_common import *
+from Crypto.Util.py3compat import *
+
+from binascii import unhexlify
+
+class ImportKeyTests(unittest.TestCase):
+
+ y = 92137165128186062214622779787483327510946462589285775188003362705875131352591574106484271700740858696583623951844732128165434284507709057439633739849986759064015013893156866539696757799934634945787496920169462601722830899660681779448742875054459716726855443681559131362852474817534616736104831095601710736729L
+ p = 162452170958135306109773853318304545923250830605675936228618290525164105310663722368377131295055868997377338797580997938253236213714988311430600065853662861806894003694743806769284131194035848116051021923956699231855223389086646903420682639786976554552864568460372266462812137447840653688476258666833303658691L
+ q = 988791743931120302950649732173330531512663554851L
+ g = 85583152299197514738065570254868711517748965097380456700369348466136657764813442044039878840094809620913085570225318356734366886985903212775602770761953571967834823306046501307810937486758039063386311593890777319935391363872375452381836756832784184928202587843258855704771836753434368484556809100537243908232L
+ x = 540873410045082450874416847965843801027716145253L
+
+ def setUp(self):
+
+ # It is easier to write test vectors in text form,
+ # and convert them to byte strigs dynamically here
+ for mname, mvalue in ImportKeyTests.__dict__.items():
+ if mname[:4] in ('der_', 'pem_', 'ssh_'):
+ if mname[:4] == 'der_':
+ mvalue = unhexlify(tobytes(mvalue))
+ mvalue = tobytes(mvalue)
+ setattr(self, mname, mvalue)
+
+ # 1. SubjectPublicKeyInfo
+ der_public=\
+ '308201b73082012b06072a8648ce3804013082011e02818100e756ee1717f4b6'+\
+ '794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a2757695ec91'+\
+ '5697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8b81b47'+\
+ '9a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656cecb4c'+\
+ '8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad32f48c'+\
+ 'd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb7eaeae'+\
+ '3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466cf444f3'+\
+ '4b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b92370040a'+\
+ 'ca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074b41c56'+\
+ 'ae43fd300d89262e4efd89943f99a651b03888038185000281810083352a69a1'+\
+ '32f34843d2a0eb995bff4e2f083a73f0049d2c91ea2f0ce43d144abda48199e4'+\
+ 'b003c570a8af83303d45105f606c5c48d925a40ed9c2630c2fa4cdbf838539de'+\
+ 'b9a29f919085f2046369f627ca84b2cb1e2c7940564b670f963ab1164d4e2ca2'+\
+ 'bf6ffd39f12f548928bf4d2d1b5e6980b4f1be4c92a91986fba559'
+
+ def testImportKey1(self):
+ key_obj = self.dsa.importKey(self.der_public)
+ self.failIf(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+
+ def testExportKey1(self):
+ tup = (self.y, self.g, self.p, self.q)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('DER')
+ self.assertEqual(self.der_public, encoded)
+
+ # 2.
+ pem_public="""\
+-----BEGIN DSA PUBLIC KEY-----
+MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/
+j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtH
+mjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2
+qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzrfq6u
+NxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa
+5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxW
+rkP9MA2JJi5O/YmUP5mmUbA4iAOBhQACgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPw
+BJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTne
+uaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmA
+tPG+TJKpGYb7pVk=
+-----END DSA PUBLIC KEY-----"""
+
+ def testImportKey2(self):
+ for pem in (self.pem_public, tostr(self.pem_public)):
+ key_obj = self.dsa.importKey(pem)
+ self.failIf(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+
+ def testExportKey2(self):
+ tup = (self.y, self.g, self.p, self.q)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('PEM')
+ self.assertEqual(self.pem_public, encoded)
+
+ # 3. OpenSSL/OpenSSH format
+ der_private=\
+ '308201bb02010002818100e756ee1717f4b6794c7c214724a19763742c45572b'+\
+ '4b3f8ff3b44f3be9f44ce039a2757695ec915697da74ef914fcd1b05660e2419'+\
+ 'c761d639f45d2d79b802dbd23e7ab8b81b479a380e1f30932584ba2a0b955032'+\
+ '342ebc83cb5ca906e7b0d7cd6fe656cecb4c8b5a77123a8c6750a481e3b06057'+\
+ 'aff6aa6eba620b832d60c3021500ad32f48cd3ae0c45a198a61fa4b5e2032076'+\
+ '3b2302818079dfdc3d614fe635fceb7eaeae3718dc2efefb45282993ac6749dc'+\
+ '83c223d8c1887296316b3b0b54466cf444f34b82e3554d0b90a778faaf1306f0'+\
+ '25dae6a3e36c7f93dd5bac4052b92370040aca70b8d5820599711900efbc9618'+\
+ '12c355dd9beffe0981da85c5548074b41c56ae43fd300d89262e4efd89943f99'+\
+ 'a651b038880281810083352a69a132f34843d2a0eb995bff4e2f083a73f0049d'+\
+ '2c91ea2f0ce43d144abda48199e4b003c570a8af83303d45105f606c5c48d925'+\
+ 'a40ed9c2630c2fa4cdbf838539deb9a29f919085f2046369f627ca84b2cb1e2c'+\
+ '7940564b670f963ab1164d4e2ca2bf6ffd39f12f548928bf4d2d1b5e6980b4f1'+\
+ 'be4c92a91986fba55902145ebd9a3f0b82069d98420986b314215025756065'
+
+ def testImportKey3(self):
+ key_obj = self.dsa.importKey(self.der_private)
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey3(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('DER', pkcs8=False)
+ self.assertEqual(self.der_private, encoded)
+
+ # 4.
+ pem_private="""\
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQDnVu4XF/S2eUx8IUckoZdjdCxFVytLP4/ztE876fRM4DmidXaV
+7JFWl9p075FPzRsFZg4kGcdh1jn0XS15uALb0j56uLgbR5o4Dh8wkyWEuioLlVAy
+NC68g8tcqQbnsNfNb+ZWzstMi1p3EjqMZ1CkgeOwYFev9qpuumILgy1gwwIVAK0y
+9IzTrgxFoZimH6S14gMgdjsjAoGAed/cPWFP5jX8636urjcY3C7++0UoKZOsZ0nc
+g8Ij2MGIcpYxazsLVEZs9ETzS4LjVU0LkKd4+q8TBvAl2uaj42x/k91brEBSuSNw
+BArKcLjVggWZcRkA77yWGBLDVd2b7/4JgdqFxVSAdLQcVq5D/TANiSYuTv2JlD+Z
+plGwOIgCgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LAD
+xXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4s
+eUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVkCFF69mj8L
+ggadmEIJhrMUIVAldWBl
+-----END DSA PRIVATE KEY-----"""
+
+ def testImportKey4(self):
+ for pem in (self.pem_private, tostr(self.pem_private)):
+ key_obj = self.dsa.importKey(pem)
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey4(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('PEM', pkcs8=False)
+ self.assertEqual(self.pem_private, encoded)
+
+ # 5. PKCS8 (unencrypted)
+ der_pkcs8=\
+ '3082014a0201003082012b06072a8648ce3804013082011e02818100e756ee17'+\
+ '17f4b6794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a27576'+\
+ '95ec915697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8'+\
+ 'b81b479a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656'+\
+ 'cecb4c8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad'+\
+ '32f48cd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb'+\
+ '7eaeae3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466c'+\
+ 'f444f34b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b923'+\
+ '70040aca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074'+\
+ 'b41c56ae43fd300d89262e4efd89943f99a651b03888041602145ebd9a3f0b82'+\
+ '069d98420986b314215025756065'
+
+ def testImportKey5(self):
+ key_obj = self.dsa.importKey(self.der_pkcs8)
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey5(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('DER')
+ self.assertEqual(self.der_pkcs8, encoded)
+ encoded = key.exportKey('DER', pkcs8=True)
+ self.assertEqual(self.der_pkcs8, encoded)
+
+ # 6.
+ pem_pkcs8="""\
+-----BEGIN PRIVATE KEY-----
+MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVX
+K0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4
+uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47Bg
+V6/2qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzr
+fq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG
+8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0
+tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAQWAhRevZo/C4IGnZhCCYazFCFQJXVgZQ==
+-----END PRIVATE KEY-----"""
+
+ def testImportKey6(self):
+ for pem in (self.pem_pkcs8, tostr(self.pem_pkcs8)):
+ key_obj = self.dsa.importKey(pem)
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey6(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('PEM')
+ self.assertEqual(self.pem_pkcs8, encoded)
+ encoded = key.exportKey('PEM', pkcs8=True)
+ self.assertEqual(self.pem_pkcs8, encoded)
+
+ # 7. OpenSSH/RFC4253
+ ssh_pub="""ssh-dss AAAAB3NzaC1kc3MAAACBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2qm66YguDLWDDAAAAFQCtMvSM064MRaGYph+kteIDIHY7IwAAAIB539w9YU/mNfzrfq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAAAAIEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVk="""
+
+ def testImportKey7(self):
+ for ssh in (self.ssh_pub, tostr(self.ssh_pub)):
+ key_obj = self.dsa.importKey(ssh)
+ self.failIf(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+
+ def testExportKey7(self):
+ tup = (self.y, self.g, self.p, self.q)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('OpenSSH')
+ self.assertEqual(self.ssh_pub, encoded)
+
+ # 8. Encrypted OpenSSL/OpenSSH
+ pem_private_encrypted="""\
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,70B6908939D65E9F2EB999E8729788CE
+
+4V6GHRDpCrdZ8MBjbyp5AlGUrjvr2Pn2e2zVxy5RBt4FBj9/pa0ae0nnyUPMLSUU
+kKyOR0topRYTVRLElm4qVrb5uNZ3hRwfbklr+pSrB7O9eHz9V5sfOQxyODS07JxK
+k1OdOs70/ouMXLF9EWfAZOmWUccZKHNblUwg1p1UrZIz5jXw4dUE/zqhvXh6d+iC
+ADsICaBCjCrRQJKDp50h3+ndQjkYBKVH+pj8TiQ79U7lAvdp3+iMghQN6YXs9mdI
+gFpWw/f97oWM4GHZFqHJ+VSMNFjBiFhAvYV587d7Lk4dhD8sCfbxj42PnfRgUItc
+nnPqHxmhMQozBWzYM4mQuo3XbF2WlsNFbOzFVyGhw1Bx1s91qvXBVWJh2ozrW0s6
+HYDV7ZkcTml/4kjA/d+mve6LZ8kuuR1qCiZx6rkffhh1gDN/1Xz3HVvIy/dQ+h9s
+5zp7PwUoWbhqp3WCOr156P6gR8qo7OlT6wMh33FSXK/mxikHK136fV2shwTKQVII
+rJBvXpj8nACUmi7scKuTWGeUoXa+dwTZVVe+b+L2U1ZM7+h/neTJiXn7u99PFUwu
+xVJtxaV37m3aXxtCsPnbBg==
+-----END DSA PRIVATE KEY-----"""
+
+ def testImportKey8(self):
+ for pem in (self.pem_private_encrypted, tostr(self.pem_private_encrypted)):
+ key_obj = self.dsa.importKey(pem, "PWDTEST")
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey8(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ encoded = key.exportKey('PEM', pkcs8=False, passphrase="PWDTEST")
+ key = self.dsa.importKey(encoded, "PWDTEST")
+ self.assertEqual(self.y, key.key.y)
+ self.assertEqual(self.p, key.key.p)
+ self.assertEqual(self.q, key.key.q)
+ self.assertEqual(self.g, key.key.g)
+ self.assertEqual(self.x, key.key.x)
+
+ # 9. Encrypted PKCS8
+ # pbeWithMD5AndDES-CBC
+ pem_pkcs8_encrypted="""\
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBcTAbBgkqhkiG9w0BBQMwDgQI0GC3BJ/jSw8CAggABIIBUHc1cXZpExIE9tC7
+7ryiW+5ihtF2Ekurq3e408GYSAu5smJjN2bvQXmzRFBz8W38K8eMf1sbWroZ4+zn
+kZSbb9nSm5kAa8lR2+oF2k+WRswMR/PTC3f/D9STO2X0QxdrzKgIHEcSGSHp5jTx
+aVvbkCDHo9vhBTl6S3ogZ48As/MEro76+9igUwJ1jNhIQZPJ7e20QH5qDpQFFJN4
+CKl2ENSEuwGiqBszItFy4dqH0g63ZGZV/xt9wSO9Rd7SK/EbA/dklOxBa5Y/VItM
+gnIhs9XDMoGYyn6F023EicNJm6g/bVQk81BTTma4tm+12TKGdYm+QkeZvCOMZylr
+Wv67cKwO3cAXt5C3QXMDgYR64XvuaT5h7C0igMp2afSXJlnbHEbFxQVJlv83T4FM
+eZ4k+NQDbEL8GiHmFxzDWQAuPPZKJWEEEV2p/To+WOh+kSDHQw==
+-----END ENCRYPTED PRIVATE KEY-----"""
+
+ def testImportKey9(self):
+ for pem in (self.pem_pkcs8_encrypted, tostr(self.pem_pkcs8_encrypted)):
+ key_obj = self.dsa.importKey(pem, "PWDTEST")
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ # 10. Encrypted PKCS8
+ # pkcs5PBES2 /
+ # pkcs5PBKDF2 (rounds=1000, salt=D725BF1B6B8239F4) /
+ # des-EDE3-CBC (iv=27A1C66C42AFEECE)
+ #
+ der_pkcs8_encrypted=\
+ '30820196304006092a864886f70d01050d3033301b06092a864886f70d01050c'+\
+ '300e0408d725bf1b6b8239f4020203e8301406082a864886f70d0307040827a1'+\
+ 'c66c42afeece048201505cacfde7bf8edabb3e0d387950dc872662ea7e9b1ed4'+\
+ '400d2e7e6186284b64668d8d0328c33a9d9397e6f03df7cb68268b0a06b4e22f'+\
+ '7d132821449ecf998a8b696dbc6dd2b19e66d7eb2edfeb4153c1771d49702395'+\
+ '4f36072868b5fcccf93413a5ac4b2eb47d4b3f681c6bd67ae363ed776f45ae47'+\
+ '174a00098a7c930a50f820b227ddf50f9742d8e950d02586ff2dac0e3c372248'+\
+ 'e5f9b6a7a02f4004f20c87913e0f7b52bccc209b95d478256a890b31d4c9adec'+\
+ '21a4d157a179a93a3dad06f94f3ce486b46dfa7fc15fd852dd7680bbb2f17478'+\
+ '7e71bd8dbaf81eca7518d76c1d26256e95424864ba45ca5d47d7c5a421be02fa'+\
+ 'b94ab01e18593f66cf9094eb5c94b9ecf3aa08b854a195cf87612fbe5e96c426'+\
+ '2b0d573e52dc71ba3f5e468c601e816c49b7d32c698b22175e89aaef0c443770'+\
+ '5ef2f88a116d99d8e2869a4fd09a771b84b49e4ccb79aadcb1c9'
+
+ def testImportKey10(self):
+ key_obj = self.dsa.importKey(self.der_pkcs8_encrypted, "PWDTEST")
+ self.failUnless(key_obj.has_private())
+ self.assertEqual(self.y, key_obj.key.y)
+ self.assertEqual(self.p, key_obj.key.p)
+ self.assertEqual(self.q, key_obj.key.q)
+ self.assertEqual(self.g, key_obj.key.g)
+ self.assertEqual(self.x, key_obj.key.x)
+
+ def testExportKey10(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ randfunc = BytesIO(unhexlify(b("27A1C66C42AFEECE") + b("D725BF1B6B8239F4"))).read
+ key._randfunc = randfunc
+ encoded = key.exportKey('DER', pkcs8=True, passphrase="PWDTEST")
+ self.assertEqual(self.der_pkcs8_encrypted, encoded)
+
+ # ----
+
+ def testImportError1(self):
+ self.assertRaises(KeyFormatError, self.dsa.importKey, self.der_pkcs8_encrypted, "wrongpwd")
+
+ def testExportError2(self):
+ tup = (self.y, self.g, self.p, self.q, self.x)
+ key = self.dsa.construct(tup)
+ self.assertRaises(ValueError, key.exportKey, 'DER', pkcs8=False, passphrase="PWDTEST")
+
+class ImportKeyTestsSlow(ImportKeyTests):
+ def setUp(self):
+ ImportKeyTests.setUp(self)
+ self.dsa = DSA.DSAImplementation(use_fast_math=0)
+
+class ImportKeyTestsFast(ImportKeyTests):
+ def setUp(self):
+ ImportKeyTests.setUp(self)
+ self.dsa = DSA.DSAImplementation(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')
+
diff --git a/lib/Crypto/SelfTest/PublicKey/test_importKey.py b/lib/Crypto/SelfTest/PublicKey/test_import_RSA.py
index 28a7eee..ff65e77 100644
--- a/lib/Crypto/SelfTest/PublicKey/test_importKey.py
+++ b/lib/Crypto/SelfTest/PublicKey/test_import_RSA.py
@@ -66,7 +66,8 @@ BX85JB8zqwHB
# The same RSA private key as in rsaKeyPEM, but now encrypted
rsaKeyEncryptedPEM=(
-
+
+ # PEM encryption
# With DES and passphrase 'test'
('test', u'''-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
@@ -79,32 +80,30 @@ 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"),
+-----END RSA PRIVATE KEY-----'''),
+
+ # PKCS8 encryption
+ ('winter', u'''-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeZIsbW3O+JcCAggA
+MBQGCCqGSIb3DQMHBAgSM2p0D8FilgSCAWBhFyP2tiGKVpGj3mO8qIBzinU60ApR
+3unvP+N6j7LVgnV2lFGaXbJ6a1PbQXe+2D6DUyBLo8EMXrKKVLqOMGkFMHc0UaV6
+R6MmrsRDrbOqdpTuVRW+NVd5J9kQQh4xnfU/QrcPPt7vpJvSf4GzG0n666Ki50OV
+M/feuVlIiyGXY6UWdVDpcOV72cq02eNUs/1JWdh2uEBvA9fCL0c07RnMrdT+CbJQ
+NjJ7f8ULtp7xvR9O3Al/yJ4Wv3i4VxF1f3MCXzhlUD4I0ONlr0kJWgeQ80q/cWhw
+ntvgJwnCn2XR1h6LA8Wp+0ghDTsL2NhJpWd78zClGhyU4r3hqu1XDjoXa7YCXCix
+jCV15+ViDJzlNCwg+W6lRg18sSLkCT7alviIE0U5tHc6UPbbHwT5QqAxAABaP+nZ
+CGqJGyiwBzrKebjgSm/KRd4C91XqcsysyH2kKPfT51MLAoD4xelOURBP
+-----END ENCRYPTED PRIVATE KEY-----'''
+ ),
)
- rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY-----
+ rsaPublicKeyPEM = u'''-----BEGIN RSA PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T
Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ==
------END PUBLIC KEY-----'''
+-----END RSA PUBLIC KEY-----'''
# Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM'
- rsaPublicKeyOpenSSH = '''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n'''
+ rsaPublicKeyOpenSSH = b('''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n''')
# The private key, in PKCS#1 format encoded with DER
rsaKeyDER = a2b_hex(
@@ -298,25 +297,85 @@ Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ==
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):
+ def testExportKey7(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):
+ def testExportKey8(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))
+ def testExportKey9(self):
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ self.assertRaises(ValueError, key.exportKey, "invalid-format")
+
+ def testExportKey10(self):
+ # Export and re-import the encrypted key. It must match.
+ # PEM envelope, PKCS#1, old PEM encryption
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ outkey = key.exportKey('PEM', 'test')
+ self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1)
+ self.failUnless(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1)
+ inkey = RSA.importKey(outkey, 'test')
+ self.assertEqual(key.n, inkey.n)
+ self.assertEqual(key.e, inkey.e)
+ self.assertEqual(key.d, inkey.d)
+
+ def testExportKey11(self):
+ # Export and re-import the encrypted key. It must match.
+ # PEM envelope, PKCS#1, old PEM encryption
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ outkey = key.exportKey('PEM', 'test', pkcs=1)
+ self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1)
+ self.failUnless(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1)
+ inkey = RSA.importKey(outkey, 'test')
+ self.assertEqual(key.n, inkey.n)
+ self.assertEqual(key.e, inkey.e)
+ self.assertEqual(key.d, inkey.d)
+
+ def testExportKey12(self):
+ # Export and re-import the encrypted key. It must match.
+ # PEM envelope, PKCS#8, old PEM encryption
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ outkey = key.exportKey('PEM', 'test', pkcs=8)
+ self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1)
+ self.failUnless(tostr(outkey).find('BEGIN PRIVATE KEY')!=-1)
+ inkey = RSA.importKey(outkey, 'test')
+ self.assertEqual(key.n, inkey.n)
+ self.assertEqual(key.e, inkey.e)
+ self.assertEqual(key.d, inkey.d)
+
+ def testExportKey13(self):
+ # Export and re-import the encrypted key. It must match.
+ # PEM envelope, PKCS#8, PKCS#8 encryption
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ outkey = key.exportKey('PEM', 'test', pkcs=8,
+ protection='PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC')
+ self.failUnless(tostr(outkey).find('4,ENCRYPTED')==-1)
+ self.failUnless(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1)
+ inkey = RSA.importKey(outkey, 'test')
+ self.assertEqual(key.n, inkey.n)
+ self.assertEqual(key.e, inkey.e)
+ self.assertEqual(key.d, inkey.d)
+
+ def testExportKey14(self):
+ # Export and re-import the encrypted key. It must match.
+ # DER envelope, PKCS#8, PKCS#8 encryption
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ outkey = key.exportKey('DER', 'test', pkcs=8)
+ inkey = RSA.importKey(outkey, 'test')
+ self.assertEqual(key.n, inkey.n)
+ self.assertEqual(key.e, inkey.e)
+ self.assertEqual(key.d, inkey.d)
+
+ def testExportKey15(self):
+ # Verify that that error an condition is detected when trying to
+ # use a password with DER encoding and PKCS#1.
+ key = self.rsa.construct([self.n, self.e, self.d, self.p, self.q, self.pInv])
+ self.assertRaises(ValueError, key.exportKey, 'DER', 'test', 1)
+
class ImportKeyTestsSlow(ImportKeyTests):
def setUp(self):
self.rsa = RSA.RSAImplementation(use_fast_math=0)
diff --git a/lib/Crypto/SelfTest/Random/test_random.py b/lib/Crypto/SelfTest/Random/test_random.py
index f9ffc66..3e85c3c 100644
--- a/lib/Crypto/SelfTest/Random/test_random.py
+++ b/lib/Crypto/SelfTest/Random/test_random.py
@@ -133,7 +133,7 @@ class SimpleTest(unittest.TestCase):
self.assertEqual(b('1') in z, True)
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,2))
# 2to3 wraps a list() around it, alas - but I want to shoot
# myself in the foot here! :D
diff --git a/lib/Crypto/SelfTest/Signature/test_pkcs1_15.py b/lib/Crypto/SelfTest/Signature/test_pkcs1_15.py
index bc36696..976eb97 100644
--- a/lib/Crypto/SelfTest/Signature/test_pkcs1_15.py
+++ b/lib/Crypto/SelfTest/Signature/test_pkcs1_15.py
@@ -123,7 +123,7 @@ class PKCS1_15_Tests(unittest.TestCase):
'''4a700a16432a291a3194646952687d5316458b8b86fb0a25aa30e0dcecdb
442676759ac63d56ec1499c3ae4c0013c2053cabd5b5804848994541ac16
fa243a4d''',
- SHA
+ SHA1
),
#
@@ -146,7 +146,7 @@ class PKCS1_15_Tests(unittest.TestCase):
A9D20970C54E6651070B0144D43844C899320DD8FA7819F7EBC6A7715287332E
C8675C136183B3F8A1F81EF969418267130A756FDBB2C71D9A667446E34E0EAD
9CF31BFB66F816F319D0B7E430A5F2891553986E003720261C7E9022C0D9F11F''',
- SHA
+ SHA1
)
)
@@ -197,7 +197,7 @@ class PKCS1_15_Tests(unittest.TestCase):
rng = Random.new().read
key = RSA.generate(1024, rng)
- for hashmod in (MD2,MD5,SHA,SHA224,SHA256,SHA384,SHA512,RIPEMD):
+ for hashmod in (MD2,MD5,SHA1,SHA224,SHA256,SHA384,SHA512,RIPEMD160):
h = hashmod.new()
h.update(b('blah blah blah'))
@@ -206,10 +206,37 @@ class PKCS1_15_Tests(unittest.TestCase):
result = signer.verify(h, s)
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={}):
tests = []
tests += list_test_cases(PKCS1_15_Tests)
+ tests += list_test_cases(PKCS1_15_NoParams)
return tests
if __name__ == '__main__':
diff --git a/lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py b/lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py
index f5256a5..314d2b8 100644
--- a/lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py
+++ b/lib/Crypto/SelfTest/Signature/test_pkcs1_pss.py
@@ -136,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
3b ce 7e 61''',
# Hash algorithm
- SHA
+ SHA1
),
#
@@ -192,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
3e 67 76 af''',
# Hash
- SHA
+ SHA1
),
#
@@ -238,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
d5 6d f4 2d''',
# Hash
- SHA
+ SHA1
),
#
@@ -285,7 +285,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
# Salt
'''57 bf 16 0b cb 02 bb 1d c7 28 0c f0 45 85 30 b7
d2 83 2f f7''',
- SHA
+ SHA1
),
#
@@ -339,7 +339,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
# Salt
'''1d 65 49 1d 79 c8 64 b3 73 00 9b e6 f6 f2 46 7b
ac 4c 78 fa''',
- SHA
+ SHA1
)
)
@@ -380,7 +380,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
self.failUnless(result)
def testSignVerify(self):
- h = SHA.new()
+ h = SHA1.new()
h.update(b('blah blah blah'))
rng = Random.new().read
@@ -394,7 +394,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
return bchr(0x00)*maskLen
# Verify that PSS is friendly to all ciphers
- for hashmod in (MD2,MD5,SHA,SHA224,SHA256,SHA384,RIPEMD):
+ for hashmod in (MD2,MD5,SHA1,SHA224,SHA256,SHA384,RIPEMD160):
h = hashmod.new()
h.update(b('blah blah blah'))
@@ -406,7 +406,7 @@ class PKCS1_PSS_Tests(unittest.TestCase):
self.failUnless(signer.verify(h, s))
self.assertEqual(key.asked, h.digest_size)
- h = SHA.new()
+ h = SHA1.new()
h.update(b('blah blah blah'))
# Verify that sign() uses a different salt length
diff --git a/lib/Crypto/SelfTest/Util/__init__.py b/lib/Crypto/SelfTest/Util/__init__.py
index abd640a..f404d0b 100644
--- a/lib/Crypto/SelfTest/Util/__init__.py
+++ b/lib/Crypto/SelfTest/Util/__init__.py
@@ -34,6 +34,7 @@ def get_tests(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_Counter; tests += test_Counter.get_tests(config=config)
+ from Crypto.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config)
return tests
if __name__ == '__main__':
diff --git a/lib/Crypto/SelfTest/Util/test_Counter.py b/lib/Crypto/SelfTest/Util/test_Counter.py
index 33c9bd7..7dbfc97 100644
--- a/lib/Crypto/SelfTest/Util/test_Counter.py
+++ b/lib/Crypto/SelfTest/Util/test_Counter.py
@@ -39,34 +39,24 @@ class CounterTests(unittest.TestCase):
from Crypto.Util import Counter
def test_BE_shortcut(self):
- """Big endian, shortcut enabled"""
+ """Big endian"""
c = Counter.new(128)
- self.assertEqual(c.__PCT_CTR_SHORTCUT__,True) # assert_
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):
- """Little endian, shortcut enabled"""
+ """Little endian"""
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):
- """Big endian, shortcut disabled"""
+ """Big endian, with disable_shortcut"""
+ # Just testing API backward-compatibility. disable_shortcut is now a no-op.
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)
- self.assertRaises(AttributeError, getattr, c, '__PCT_CTR_SHORTCUT__')
def test_LE_no_shortcut(self):
"""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)
- self.assertRaises(AttributeError, getattr, c, '__PCT_CTR_SHORTCUT__')
def test_BE_defaults(self):
"""128-bit, Big endian, defaults"""
diff --git a/lib/Crypto/SelfTest/Util/test_Padding.py b/lib/Crypto/SelfTest/Util/test_Padding.py
new file mode 100644
index 0000000..5a3d199
--- /dev/null
+++ b/lib/Crypto/SelfTest/Util/test_Padding.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+#
+# SelfTest/Util/test_Padding.py: Self-test for padding functions
+#
+# ===================================================================
+# 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.
+# ===================================================================
+
+import unittest
+from binascii import unhexlify as uh
+
+from Crypto.Util.py3compat import *
+from Crypto.SelfTest.st_common import list_test_cases
+from Crypto.Util.Padding import *
+
+class PKCS7_Tests(unittest.TestCase):
+
+ def test1(self):
+ padded = pad(b(""), 4)
+ self.failUnless(padded == uh(b("04040404")))
+ padded = pad(b(""), 4, 'pkcs7')
+ self.failUnless(padded == uh(b("04040404")))
+ back = unpad(padded, 4)
+ self.failUnless(back == b(""))
+
+ def test2(self):
+ padded = pad(uh(b("12345678")), 4)
+ self.failUnless(padded == uh(b("1234567804040404")))
+ back = unpad(padded, 4)
+ self.failUnless(back == uh(b("12345678")))
+
+ def test3(self):
+ padded = pad(uh(b("123456")), 4)
+ self.failUnless(padded == uh(b("12345601")))
+ back = unpad(padded, 4)
+ self.failUnless(back == uh(b("123456")))
+
+ def test4(self):
+ padded = pad(uh(b("1234567890")), 4)
+ self.failUnless(padded == uh(b("1234567890030303")))
+ back = unpad(padded, 4)
+ self.failUnless(back == uh(b("1234567890")))
+
+ def testn1(self):
+ self.assertRaises(ValueError, pad, uh(b("12")), 4, 'pkcs8')
+
+ def testn2(self):
+ self.assertRaises(ValueError, unpad, b("\0\0\0"), 4)
+
+ def testn3(self):
+ self.assertRaises(ValueError, unpad, b("123456\x02"), 4)
+ self.assertRaises(ValueError, unpad, b("123456\x00"), 4)
+ self.assertRaises(ValueError, unpad, b("123456\x05\x05\x05\x05\x05"), 4)
+
+class X923_Tests(unittest.TestCase):
+
+ def test1(self):
+ padded = pad(b(""), 4, 'x923')
+ self.failUnless(padded == uh(b("00000004")))
+ back = unpad(padded, 4, 'x923')
+ self.failUnless(back == b(""))
+
+ def test2(self):
+ padded = pad(uh(b("12345678")), 4, 'x923')
+ self.failUnless(padded == uh(b("1234567800000004")))
+ back = unpad(padded, 4, 'x923')
+ self.failUnless(back == uh(b("12345678")))
+
+ def test3(self):
+ padded = pad(uh(b("123456")), 4, 'x923')
+ self.failUnless(padded == uh(b("12345601")))
+ back = unpad(padded, 4, 'x923')
+ self.failUnless(back == uh(b("123456")))
+
+ def test4(self):
+ padded = pad(uh(b("1234567890")), 4, 'x923')
+ self.failUnless(padded == uh(b("1234567890000003")))
+ back = unpad(padded, 4, 'x923')
+ self.failUnless(back == uh(b("1234567890")))
+
+ def testn1(self):
+ self.assertRaises(ValueError, unpad, b("123456\x02"), 4, 'x923')
+ self.assertRaises(ValueError, unpad, b("123456\x00"), 4, 'x923')
+ self.assertRaises(ValueError, unpad, b("123456\x00\x00\x00\x00\x05"), 4, 'x923')
+
+class ISO7816_Tests(unittest.TestCase):
+
+ def test1(self):
+ padded = pad(b(""), 4, 'iso7816')
+ self.failUnless(padded == uh(b("80000000")))
+ back = unpad(padded, 4, 'iso7816')
+ self.failUnless(back == b(""))
+
+ def test2(self):
+ padded = pad(uh(b("12345678")), 4, 'iso7816')
+ self.failUnless(padded == uh(b("1234567880000000")))
+ back = unpad(padded, 4, 'iso7816')
+ self.failUnless(back == uh(b("12345678")))
+
+ def test3(self):
+ padded = pad(uh(b("123456")), 4, 'iso7816')
+ self.failUnless(padded == uh(b("12345680")))
+ #import pdb; pdb.set_trace()
+ back = unpad(padded, 4, 'iso7816')
+ self.failUnless(back == uh(b("123456")))
+
+ def test4(self):
+ padded = pad(uh(b("1234567890")), 4, 'iso7816')
+ self.failUnless(padded == uh(b("1234567890800000")))
+ back = unpad(padded, 4, 'iso7816')
+ self.failUnless(back == uh(b("1234567890")))
+
+ def testn1(self):
+ self.assertRaises(ValueError, unpad, b("123456\x81"), 4, 'iso7816')
+
+def get_tests(config={}):
+ tests = []
+ tests += list_test_cases(PKCS7_Tests)
+ tests += list_test_cases(X923_Tests)
+ tests += list_test_cases(ISO7816_Tests)
+ return tests
+
+if __name__ == '__main__':
+ suite = lambda: unittest.TestSuite(get_tests())
+ unittest.main(defaultTest='suite')
+
diff --git a/lib/Crypto/SelfTest/Util/test_asn1.py b/lib/Crypto/SelfTest/Util/test_asn1.py
index 578dabe..58d12b4 100644
--- a/lib/Crypto/SelfTest/Util/test_asn1.py
+++ b/lib/Crypto/SelfTest/Util/test_asn1.py
@@ -28,262 +28,622 @@ import unittest
import sys
from Crypto.Util.py3compat import *
-from Crypto.Util.asn1 import DerSequence, DerObject
+from Crypto.Util.asn1 import *
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
class DerObjectTests(unittest.TestCase):
- def testObjEncode1(self):
- # No payload
- der = DerObject(b('\x33'))
- self.assertEquals(der.encode(), b('\x33\x00'))
- # Small payload
- der.payload = b('\x45')
- self.assertEquals(der.encode(), b('\x33\x01\x45'))
- # Invariant
- self.assertEquals(der.encode(), b('\x33\x01\x45'))
- # Initialize with numerical tag
- der = DerObject(b(0x33))
- der.payload = b('\x45')
- self.assertEquals(der.encode(), b('\x33\x01\x45'))
-
- def testObjEncode2(self):
- # Known types
- der = DerObject('SEQUENCE')
- self.assertEquals(der.encode(), b('\x30\x00'))
- der = DerObject('BIT STRING')
- self.assertEquals(der.encode(), b('\x03\x00'))
-
- def testObjEncode3(self):
- # Long payload
- der = DerObject(b('\x34'))
- der.payload = b("0")*128
- self.assertEquals(der.encode(), b('\x34\x81\x80' + "0"*128))
-
- def testObjDecode1(self):
- # Decode short payload
- der = DerObject()
- der.decode(b('\x20\x02\x01\x02'))
- self.assertEquals(der.payload, b("\x01\x02"))
- self.assertEquals(der.typeTag, 0x20)
-
- def testObjDecode2(self):
- # Decode short payload
- der = DerObject()
- der.decode(b('\x22\x81\x80' + "1"*128))
- self.assertEquals(der.payload, b("1")*128)
- self.assertEquals(der.typeTag, 0x22)
+ 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):
+ # No payload
+ der = DerObject(b('\x02'))
+ self.assertEquals(der.encode(), b('\x02\x00'))
+ # Small payload (primitive)
+ der.payload = b('\x45')
+ self.assertEquals(der.encode(), b('\x02\x01\x45'))
+ # Invariant
+ self.assertEquals(der.encode(), b('\x02\x01\x45'))
+ # Initialize with numerical tag
+ der = DerObject(0x04)
+ der.payload = b('\x45')
+ self.assertEquals(der.encode(), b('\x04\x01\x45'))
+ # Initialize with constructed type
+ der = DerObject(b('\x10'), constructed=True)
+ self.assertEquals(der.encode(), b('\x30\x00'))
+
+ def testObjEncode2(self):
+ # Initialize with payload
+ der = DerObject(0x03, b('\x12\x12'))
+ self.assertEquals(der.encode(), b('\x03\x02\x12\x12'))
+
+ def testObjEncode3(self):
+ # Long payload
+ der = DerObject(b('\x10'))
+ der.payload = b("0")*128
+ self.assertEquals(der.encode(), b('\x10\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):
+ # Decode short payload
+ der = DerObject(0x02)
+ der.decode(b('\x02\x02\x01\x02'))
+ self.assertEquals(der.payload, b("\x01\x02"))
+ self.assertEquals(der._idOctet, 0x02)
+
+ def testObjDecode2(self):
+ # Decode long 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.decode(b('\x65\x01\x88'))
+ self.assertEquals(der._idOctet, 0x65)
+ self.assertEquals(der.payload, b('\x88'))
+
+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):
- def testEncode1(self):
- # Empty sequence
- der = DerSequence()
- self.assertEquals(der.encode(), b('0\x00'))
- self.failIf(der.hasOnlyInts())
- # One single-byte integer (zero)
- der.append(0)
- self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
- self.failUnless(der.hasOnlyInts())
- # Invariant
- self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
-
- def testEncode2(self):
- # One single-byte integer (non-zero)
- der = DerSequence()
- der.append(127)
- self.assertEquals(der.encode(), b('0\x03\x02\x01\x7f'))
- # Indexing
- der[0] = 1
- self.assertEquals(len(der),1)
- self.assertEquals(der[0],1)
- self.assertEquals(der[-1],1)
- self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
- #
- der[:] = [1]
- self.assertEquals(len(der),1)
- self.assertEquals(der[0],1)
- self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
-
- def testEncode3(self):
- # One multi-byte integer (non-zero)
- der = DerSequence()
- der.append(0x180L)
- self.assertEquals(der.encode(), b('0\x04\x02\x02\x01\x80'))
-
- def testEncode4(self):
- # One very long integer
- der = DerSequence()
- der.append(2**2048)
- 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('\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 testEncode5(self):
- # One single-byte integer (looks negative)
- der = DerSequence()
- der.append(0xFFL)
- self.assertEquals(der.encode(), b('0\x04\x02\x02\x00\xff'))
-
- def testEncode6(self):
- # Two integers
- der = DerSequence()
- der.append(0x180L)
- der.append(0xFFL)
- self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
- self.failUnless(der.hasOnlyInts())
- #
- der.append(0x01)
- der[1:] = [9,8]
- self.assertEquals(len(der),3)
- self.assertEqual(der[1:],[9,8])
- self.assertEqual(der[1:-1],[9])
- self.assertEquals(der.encode(), b('0\x0A\x02\x02\x01\x80\x02\x01\x09\x02\x01\x08'))
-
- def testEncode6(self):
- # One integer and another type (no matter what it is)
- der = DerSequence()
- der.append(0x180L)
- der.append(b('\x00\x02\x00\x00'))
- self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00'))
- self.failIf(der.hasOnlyInts())
-
- ####
-
- def testDecode1(self):
- # Empty sequence
- der = DerSequence()
- der.decode(b('0\x00'))
- self.assertEquals(len(der),0)
- # One single-byte integer (zero)
- der.decode(b('0\x03\x02\x01\x00'))
- self.assertEquals(len(der),1)
- self.assertEquals(der[0],0)
- # Invariant
- der.decode(b('0\x03\x02\x01\x00'))
- self.assertEquals(len(der),1)
- self.assertEquals(der[0],0)
-
- def testDecode2(self):
- # One single-byte integer (non-zero)
- der = DerSequence()
- der.decode(b('0\x03\x02\x01\x7f'))
- self.assertEquals(len(der),1)
- 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):
- # One very long integer
- der = DerSequence()
- der.decode(b('0\x82\x01\x05')+
- 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(len(der),1)
- 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):
- # Two integers
- der = DerSequence()
- der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
- self.assertEquals(len(der),2)
- self.assertEquals(der[0],0x180L)
- self.assertEquals(der[1],0xFFL)
-
- def testDecode7(self):
- # One integer and 2 other types
- der = DerSequence()
- der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00'))
- self.assertEquals(len(der),3)
- self.assertEquals(der[0],0x180L)
- self.assertEquals(der[1],b('\x24\x02\xb6\x63'))
- self.assertEquals(der[2],b('\x12\x00'))
-
- def testDecode8(self):
- # Only 2 other types
- der = DerSequence()
- der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))
- self.assertEquals(len(der),2)
- self.assertEquals(der[0],b('\x24\x02\xb6\x63'))
- self.assertEquals(der[1],b('\x12\x00'))
-
- def testErrDecode1(self):
- # Not a sequence
- der = DerSequence()
- self.assertRaises(ValueError, der.decode, b(''))
- self.assertRaises(ValueError, der.decode, b('\x00'))
- self.assertRaises(ValueError, der.decode, b('\x30'))
-
- def testErrDecode2(self):
- # Wrong payload type
- der = DerSequence()
- self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'), True)
-
- def testErrDecode3(self):
- # Wrong length format
- der = DerSequence()
- self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00'))
- self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01'))
- self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01'))
-
- def testErrDecode4(self):
- # Wrong integer format
- der = DerSequence()
- # Multi-byte encoding for zero
- #self.assertRaises(ValueError, der.decode, '\x30\x04\x02\x02\x00\x00')
- # Negative integer
- self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\xFF'))
+ 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):
+ # Empty sequence
+ der = DerSequence()
+ self.assertEquals(der.encode(), b('0\x00'))
+ self.failIf(der.hasOnlyInts())
+ # One single-byte integer (zero)
+ der.append(0)
+ 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(False))
+ # Invariant
+ self.assertEquals(der.encode(), b('0\x03\x02\x01\x00'))
+
+ def testEncode2(self):
+ # Indexing
+ der = DerSequence()
+ der.append(0)
+ der[0] = 1
+ self.assertEquals(len(der),1)
+ self.assertEquals(der[0],1)
+ self.assertEquals(der[-1],1)
+ self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
+ #
+ der[:] = [1]
+ self.assertEquals(len(der),1)
+ self.assertEquals(der[0],1)
+ self.assertEquals(der.encode(), b('0\x03\x02\x01\x01'))
+
+ def testEncode3(self):
+ # One multi-byte integer (non-zero)
+ der = DerSequence()
+ der.append(0x180L)
+ self.assertEquals(der.encode(), b('0\x04\x02\x02\x01\x80'))
+
+ def testEncode4(self):
+ # One very long integer
+ der = DerSequence()
+ der.append(2L**2048)
+ 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('\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 testEncode5(self):
+ der = DerSequence()
+ der += 1
+ der += b('\x30\x00')
+ self.assertEquals(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00'))
+
+ def testEncode6(self):
+ # Two positive integers
+ der = DerSequence()
+ der.append(0x180L)
+ der.append(0xFFL)
+ self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
+ 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[1:] = [9,8]
+ self.assertEquals(len(der),3)
+ self.assertEqual(der[1:],[9,8])
+ self.assertEqual(der[1:-1],[9])
+ self.assertEquals(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08'))
+
+ def testEncode7(self):
+ # One integer and another type (no matter what it is)
+ der = DerSequence()
+ der.append(0x180L)
+ der.append(b('\x00\x02\x00\x00'))
+ self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x00\x02\x00\x00'))
+ self.failIf(der.hasOnlyInts())
+
+ ####
+
+ def testDecode1(self):
+ # Empty sequence
+ der = DerSequence()
+ der.decode(b('0\x00'))
+ self.assertEquals(len(der),0)
+ # One single-byte integer (zero)
+ der.decode(b('0\x03\x02\x01\x00'))
+ self.assertEquals(len(der),1)
+ self.assertEquals(der[0],0)
+ # Invariant
+ der.decode(b('0\x03\x02\x01\x00'))
+ self.assertEquals(len(der),1)
+ self.assertEquals(der[0],0)
+
+ def testDecode2(self):
+ # One single-byte integer (non-zero)
+ der = DerSequence()
+ der.decode(b('0\x03\x02\x01\x7f'))
+ self.assertEquals(len(der),1)
+ self.assertEquals(der[0],127)
+
+ def testDecode4(self):
+ # One very long integer
+ der = DerSequence()
+ der.decode(b('0\x82\x01\x05')+
+ 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(len(der),1)
+ self.assertEquals(der[0],2L**2048)
+
+ def testDecode6(self):
+ # Two integers
+ der = DerSequence()
+ der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff'))
+ self.assertEquals(len(der),2)
+ self.assertEquals(der[0],0x180L)
+ self.assertEquals(der[1],0xFFL)
+
+ def testDecode7(self):
+ # One integer and 2 other types
+ der = DerSequence()
+ der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00'))
+ self.assertEquals(len(der),3)
+ self.assertEquals(der[0],0x180L)
+ self.assertEquals(der[1],b('\x24\x02\xb6\x63'))
+ self.assertEquals(der[2],b('\x12\x00'))
+
+ def testDecode8(self):
+ # Only 2 other types
+ der = DerSequence()
+ der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))
+ self.assertEquals(len(der),2)
+ self.assertEquals(der[0],b('\x24\x02\xb6\x63'))
+ 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):
+ # Not a sequence
+ der = DerSequence()
+ self.assertRaises(EOFError, der.decode, b(''))
+ self.assertRaises(ValueError, der.decode, b('\x00'))
+ self.assertRaises(EOFError, der.decode, b('\x30'))
+
+ def testErrDecode2(self):
+ der = DerSequence()
+ # Too much data
+ self.assertRaises(ValueError, der.decode, b('\x30\x00\x00'))
+
+ def testErrDecode3(self):
+ # Wrong length format
+ der = DerSequence()
+ # Missing length in sub-item
+ 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\x04\x02\x81\x01\x01'))
+
+class DerOctetStringTests(unittest.TestCase):
+
+ def testInit1(self):
+ der = newDerOctetString(b('\xFF'))
+ self.assertEquals(der.encode(), b('\x04\x01\xFF'))
+
+ def testEncode1(self):
+ # 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={}):
from Crypto.SelfTest.st_common import list_test_cases
listTests = []
listTests += list_test_cases(DerObjectTests)
+ listTests += list_test_cases(DerIntegerTests)
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
if __name__ == '__main__':
diff --git a/lib/Crypto/SelfTest/Util/test_number.py b/lib/Crypto/SelfTest/Util/test_number.py
index 0502e9e..2201a93 100644
--- a/lib/Crypto/SelfTest/Util/test_number.py
+++ b/lib/Crypto/SelfTest/Util/test_number.py
@@ -32,6 +32,9 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
import unittest
+class MyError(Exception):
+ """Dummy exception used for tests"""
+
# 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.
@@ -276,6 +279,11 @@ class MiscTests(unittest.TestCase):
self.assertEqual(number.size(0xa2ba40),8*3)
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):
"""Test that mpzToLongObj and longObjToMPZ (internal functions) roundtrip negative numbers correctly."""
n = -100000000000000000000000000000000000L
@@ -284,9 +292,49 @@ class MiscTests(unittest.TestCase):
self.assertEqual(n, k.n)
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={}):
from Crypto.SelfTest.st_common import list_test_cases
- return list_test_cases(MiscTests)
+ tests = 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__':
suite = lambda: unittest.TestSuite(get_tests())
diff --git a/lib/Crypto/SelfTest/__init__.py b/lib/Crypto/SelfTest/__init__.py
index 40b3969..cb5782f 100644
--- a/lib/Crypto/SelfTest/__init__.py
+++ b/lib/Crypto/SelfTest/__init__.py
@@ -66,11 +66,13 @@ def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs
raise ValueError("'module' and 'tests' arguments are mutually exclusive")
if stream is None:
kwargs['stream'] = StringIO()
+ else:
+ kwargs['stream'] = stream
runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs)
result = runner.run(suite)
if not result.wasSuccessful():
if stream is None:
- sys.stderr.write(stream.getvalue())
+ sys.stderr.write(kwargs['stream'].getvalue())
raise SelfTestError("Self-test failed", result)
return result
@@ -83,6 +85,7 @@ def get_tests(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 Signature; tests += Signature.get_tests(config=config)
+ from Crypto.SelfTest import IO; tests += IO.get_tests(config=config)
return tests
if __name__ == '__main__':
diff --git a/lib/Crypto/Signature/PKCS1_PSS.py b/lib/Crypto/Signature/PKCS1_PSS.py
index 4f50eb8..3840959 100644
--- a/lib/Crypto/Signature/PKCS1_PSS.py
+++ b/lib/Crypto/Signature/PKCS1_PSS.py
@@ -30,22 +30,22 @@ For example, a sender may authenticate a message using SHA-1 and PSS like
this:
>>> from Crypto.Signature import PKCS1_PSS
- >>> from Crypto.Hash import SHA
- >>> from Crypto.PublicKey import RSA
+ >>> from Crypto.Hash import SHA1
+ >>> from Crypto.PublicKey import RSA1
>>> from Crypto import Random
>>>
>>> message = 'To be signed'
>>> key = RSA.importKey(open('privkey.der').read())
- >>> h = SHA.new()
+ >>> h = SHA1.new()
>>> h.update(message)
>>> signer = PKCS1_PSS.new(key)
- >>> signature = PKCS1_PSS.sign(key)
+ >>> signature = signer.sign(key)
At the receiver side, verification can be done like using the public part of
the RSA key:
>>> key = RSA.importKey(open('pubkey.der').read())
- >>> h = SHA.new()
+ >>> h = SHA1.new()
>>> h.update(message)
>>> verifier = PKCS1_PSS.new(key)
>>> if verifier.verify(h, signature):
@@ -72,6 +72,7 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
import Crypto.Util.number
from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes
from Crypto.Util.strxor import strxor
+from Crypto.Hash import new as Hash_new
class PSS_SigScheme:
"""This signature scheme can perform PKCS#1 PSS RSA signature or verification."""
@@ -203,7 +204,11 @@ def MGF1(mgfSeed, maskLen, hash):
T = b("")
for counter in xrange(ceil_div(maskLen, hash.digest_size)):
c = long_to_bytes(counter, 4)
- T = T + hash.new(mgfSeed + c).digest()
+ try:
+ 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)
return T[:maskLen]
@@ -253,7 +258,11 @@ def EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen):
if randFunc and sLen>0:
salt = randFunc(sLen)
# Step 5 and 6
- h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt)
+ try:
+ 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
db = bchr(0x00)*(emLen-sLen-mhash.digest_size-2) + bchr(0x01) + salt
# Step 9
@@ -328,7 +337,11 @@ def EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen):
salt = b("")
if sLen: salt = db[-sLen:]
# Step 12 and 13
- hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest()
+ try:
+ 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
if h!=hp:
return False
diff --git a/lib/Crypto/Signature/PKCS1_v1_5.py b/lib/Crypto/Signature/PKCS1_v1_5.py
index 73ac251..4ea1224 100644
--- a/lib/Crypto/Signature/PKCS1_v1_5.py
+++ b/lib/Crypto/Signature/PKCS1_v1_5.py
@@ -60,9 +60,13 @@ the RSA key:
__revision__ = "$Id$"
__all__ = [ 'new', 'PKCS115_SigScheme' ]
+import sys
+
import Crypto.Util.number
from Crypto.Util.number import ceil_div
-from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
+from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
class PKCS115_SigScheme:
@@ -150,7 +154,13 @@ class PKCS115_SigScheme:
em1 = bchr(0x00)*(k-len(m)) + m
# Step 3
try:
- em2 = EMSA_PKCS1_V1_5_ENCODE(mhash, k)
+ em2_with_params = EMSA_PKCS1_V1_5_ENCODE(mhash, k, True)
+ # 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:
return 0
# Step 4
@@ -158,9 +168,9 @@ class PKCS115_SigScheme:
# 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).
#
- return em1==em2
+ return em1==em2_with_params or em1==em2_without_params
-def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
+def EMSA_PKCS1_V1_5_ENCODE(hash, emLen, with_hash_parameters=True):
"""
Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
in PKCS#1 v2.1 (RFC3447, 9.2).
@@ -174,6 +184,9 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
The hash object that holds the digest of the message being signed.
emLen : int
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``
had to be BER-encoded. This means that old signatures
@@ -181,11 +194,6 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
is not supported in DER. Such encoding cannot be
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.
"""
@@ -208,7 +216,19 @@ def EMSA_PKCS1_V1_5_ENCODE(hash, emLen):
# { OID id-sha512 PARAMETERS NULL }
# }
#
- digestAlgo = DerSequence([hash.oid, DerNull().encode()])
+ # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters
+ # 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())
digestInfo = DerSequence([
digestAlgo.encode(),
@@ -234,3 +254,75 @@ def new(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",
+
+}
+
diff --git a/lib/Crypto/Util/Counter.py b/lib/Crypto/Util/Counter.py
index 01b804a..5a6fd77 100644
--- a/lib/Crypto/Util/Counter.py
+++ b/lib/Crypto/Util/Counter.py
@@ -44,9 +44,10 @@ An example of usage is the following:
>>> from Crypto.Cipher import AES
>>> from Crypto.Util import Counter
>>>
- >>> pt = b'\x00'*1000000
+ >>> pt = b'X'*1000000
>>> ctr = Counter.new(128)
- >>> cipher = AES.new(b'\x00'*16, AES.MODE_CTR, counter=ctr)
+ >>> key = b'AES-128 symm key'
+ >>> cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
>>> ct = cipher.encrypt(pt)
:undocumented: __package__
@@ -56,11 +57,15 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 1:
from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
+from Crypto.pct_warnings import DisableShortcut_DeprecationWarning
from Crypto.Util import _counter
import struct
+import warnings
+
# Factory function
-def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_endian=False, allow_wraparound=False, disable_shortcut=False):
+_deprecated = "deprecated"
+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.
Each call to the function returns the next counter block.
@@ -68,7 +73,7 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
prefix || counter value || postfix
- The counter value is incremented by one at each call.
+ The counter value is incremented by 1 at each call.
:Parameters:
nbits : integer
@@ -81,17 +86,18 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
used.
initial_value : integer
The initial value of the counter. Default value is 1.
+ overflow : integer
+ This value is currently ignored.
little_endian : boolean
- If True, the counter number will be encoded in little endian format.
- If False (default), in big endian format.
+ If *True*, the counter number will be encoded in little endian format.
+ If *False* (default), in big endian format.
allow_wraparound : boolean
- If True, the function will raise an *OverflowError* exception as soon
- as the counter wraps around. If False (default), the counter will
- simply restart from zero.
- disable_shortcut : boolean
- If True, do not make ciphers from `Crypto.Cipher` bypass the Python
- layer when invoking the counter block function.
- If False (default), bypass the Python layer.
+ If *True*, the counter will automatically restart from zero after
+ reaching the maximum value (``2**nbits-1``).
+ If *False* (default), the object will raise an *OverflowError*.
+ disable_shortcut : deprecated
+ This option is a no-op for backward compatibility. It will be removed
+ in a future version. Don't use it.
:Returns:
The counter block function.
"""
@@ -108,10 +114,13 @@ def new(nbits, prefix=b(""), suffix=b(""), initial_value=1, overflow=0, little_e
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:
- return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
+ return _counter._newLE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
else:
- return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound, disable_shortcut=disable_shortcut)
+ return _counter._newBE(bstr(prefix), bstr(suffix), initval, allow_wraparound=allow_wraparound)
def _encode(n, nbytes, little_endian=False):
retval = []
diff --git a/lib/Crypto/Util/Padding.py b/lib/Crypto/Util/Padding.py
new file mode 100644
index 0000000..b8498a3
--- /dev/null
+++ b/lib/Crypto/Util/Padding.py
@@ -0,0 +1,103 @@
+#
+# -*- coding: utf-8 -*-
+#
+# Util/Padding.py : Functions to manage padding
+#
+# ===================================================================
+# 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.
+# ===================================================================
+
+""" Functions to manage padding
+
+This module provides minimal support for adding and removing standard padding
+from data.
+"""
+
+__all__ = [ 'PaddingError', 'pad', 'unpad' ]
+
+from Crypto.Util.py3compat import *
+
+class PaddingError(ValueError):
+ """Exception raised when padding is incorrect and cannot be removed."""
+ pass
+
+def pad(data_to_pad, block_size, style='pkcs7'):
+ """Apply standard padding.
+
+ :Parameters:
+ data_to_pad : byte string
+ The data that needs to be padded.
+ block_size : integer
+ The block boundary to use for padding. The output length is guaranteed
+ to be a multiple of ``block_size``.
+ style : string
+ Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*.
+ :Return:
+ The original data with the appropriate padding added at the end.
+ """
+
+ padding_len = block_size-len(data_to_pad)%block_size
+ if style == 'pkcs7':
+ padding = bchr(padding_len)*padding_len
+ elif style == 'x923':
+ padding = bchr(0)*(padding_len-1) + bchr(padding_len)
+ elif style == 'iso7816':
+ padding = bchr(128) + bchr(0)*(padding_len-1)
+ else:
+ raise ValueError("Unknown padding style")
+ return data_to_pad + padding
+
+def unpad(padded_data, block_size, style='pkcs7'):
+ """Remove standard padding.
+
+ :Parameters:
+ padded_data : byte string
+ A piece of data with padding that needs to be stripped.
+ block_size : integer
+ The block boundary to use for padding. The input length
+ must be a multiple of ``block_size``.
+ style : string
+ Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*.
+ :Return:
+ Data without padding.
+ :Raises PaddingError:
+ if the padding is incorrect.
+ """
+
+ pdata_len = len(padded_data)
+ if pdata_len % block_size:
+ raise PaddingError("Input data is not padded")
+ if style in ('pkcs7', 'x923'):
+ padding_len = bord(padded_data[-1])
+ if padding_len<1 or padding_len>min(block_size, pdata_len):
+ raise PaddingError("Padding is incorrect.")
+ if style == 'pkcs7':
+ if padded_data[-padding_len:]!=bchr(padding_len)*padding_len:
+ raise PaddingError("PKCS#7 padding is incorrect.")
+ else:
+ if padded_data[-padding_len:-1]!=bchr(0)*(padding_len-1):
+ raise PaddingError("ANSI X.923 padding is incorrect.")
+ elif style == 'iso7816':
+ padding_len = pdata_len - padded_data.rfind(bchr(128))
+ if padding_len<1 or padding_len>min(block_size, pdata_len):
+ raise PaddingError("Padding is incorrect.")
+ if padding_len>1 and padded_data[1-padding_len:]!=bchr(0)*(padding_len-1):
+ raise PaddingError("ISO 7816-4 padding is incorrect.")
+ else:
+ raise ValueError("Unknown padding style")
+ return padded_data[:-padding_len]
+
diff --git a/lib/Crypto/Util/__init__.py b/lib/Crypto/Util/__init__.py
index a3bef8a..b2030c0 100644
--- a/lib/Crypto/Util/__init__.py
+++ b/lib/Crypto/Util/__init__.py
@@ -23,15 +23,22 @@
Contains useful modules that don't belong into any of the
other Crypto.* subpackages.
-Crypto.Util.number Number-theoretic functions (primality testing, etc.)
-Crypto.Util.randpool Random number generation
-Crypto.Util.RFC1751 Converts between 128-bit keys and human-readable
- strings of words.
-Crypto.Util.asn1 Minimal support for ASN.1 DER encoding
+======================== =============================================
+Module Description
+======================== =============================================
+`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.
+`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' ]
+__all__ = ['randpool', 'RFC1751', 'number', 'strxor', 'asn1', 'Counter',
+ 'Padding' ]
__revision__ = "$Id$"
diff --git a/lib/Crypto/Util/_time.py b/lib/Crypto/Util/_time.py
new file mode 100644
index 0000000..ff4c6a9
--- /dev/null
+++ b/lib/Crypto/Util/_time.py
@@ -0,0 +1,28 @@
+# -*- coding: ascii -*-
+#
+# _time.py : Internal monotonic time module.
+#
+# Written in 2013 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.
+# ===================================================================
+
+try:
+ from time import monotonic as maybe_monotonic_time
+except ImportError:
+ from time import time as maybe_monotonic_time
diff --git a/lib/Crypto/Util/asn1.py b/lib/Crypto/Util/asn1.py
index dd5ec31..0e471a3 100644
--- a/lib/Crypto/Util/asn1.py
+++ b/lib/Crypto/Util/asn1.py
@@ -19,148 +19,349 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
+""" ASN.1 DER encoding and decoding
+
+This module provides minimal support for encoding and decoding `ASN.1`_ DER
+objects.
+
+.. _`ASN.1`: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/layman.asc
+
+"""
+
+from __future__ import nested_scopes
-from Crypto.Util.number import long_to_bytes, bytes_to_long
import sys
+
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
from Crypto.Util.py3compat import *
+if sys.version_info[0] == 2 and sys.version_info[1] == 1:
+ from Crypto.Util.py21compat import *
+
+from Crypto.Util.number import long_to_bytes, bytes_to_long
+
+__all__ = [ 'DerObject', 'DerInteger', 'DerOctetString', 'DerNull',
+ 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf',
+ 'newDerInteger', 'newDerOctetString', 'newDerSequence',
+ 'newDerObjectId', 'newDerBitString', 'newDerSetOf' ]
+
+def _isInt(x, onlyNonNegative=False):
+ test = 0
+ try:
+ test += x
+ except TypeError:
+ return False
+ return not onlyNonNegative or x>=0
+
+class BytesIO_EOF(BytesIO):
+ """This class differs from BytesIO in that an EOFError exception is
+ raised whenever EOF is reached."""
-__all__ = [ 'DerObject', 'DerInteger', 'DerOctetString', 'DerNull', 'DerSequence', 'DerObjectId' ]
+ def __init__(self, *params):
+ BytesIO.__init__(self, *params)
+ self.setRecord(False)
-class DerObject:
+ def setRecord(self, record):
+ self._record = record
+ self._recording = b("")
+
+ def read(self, length):
+ s = BytesIO.read(self, length)
+ if len(s)<length:
+ raise EOFError
+ if self._record:
+ self._recording += s
+ return s
+
+ def read_byte(self):
+ return self.read(1)[0]
+
+class NoDerElementError(EOFError):
+ pass
+
+class DerObject(object):
"""Base class for defining a single DER object.
- Instantiate this class ONLY when you have to decode a DER element.
+ This class should never be directly instantiated.
"""
- # Known TAG types
- typeTags = { 'SEQUENCE': 0x30, 'BIT STRING': 0x03, 'INTEGER': 0x02,
- 'OCTET STRING': 0x04, 'NULL': 0x05, 'OBJECT IDENTIFIER': 0x06 }
+ def __init__(self, asn1Id=None, payload=b(''), implicit=None, constructed=False):
+ """Initialize the DER object according to a specific ASN.1 type.
+
+ :Parameters:
+ asn1Id : integer
+ The universal DER tag identifier for this object
+ (e.g. 0x10 for a SEQUENCE). If None, the tag is not known
+ yet.
- def __init__(self, ASN1Type=None, payload=b('')):
- """Initialize the DER object according to a specific type.
+ payload : byte string
+ The initial payload of the object.
+ If not specified, the payload is empty.
- The ASN.1 type is either specified as the ASN.1 string (e.g.
- 'SEQUENCE'), directly with its numerical tag or with no tag
- at all (None)."""
- if isInt(ASN1Type) or ASN1Type is None:
- self.typeTag = ASN1Type
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag *asn1Id*.
+
+ constructed : bool
+ True when the ASN.1 type is *constructed*.
+ False when it is *primitive*.
+ """
+
+ if asn1Id==None:
+ self._idOctet = None
+ return
+ asn1Id = self._convertTag(asn1Id)
+ self._implicit = implicit
+ if implicit:
+ # In a BER/DER identifier octet:
+ # * bits 4-0 contain the tag value
+ # * bit 5 is set if the type is 'construted'
+ # and unset if 'primitive'
+ # * bits 7-6 depend on the encoding class
+ #
+ # Class | Bit 7, Bit 6
+ # universal | 0 0
+ # application | 0 1
+ # context-spec | 1 0 (default for IMPLICIT)
+ # private | 1 1
+ #
+ self._idOctet = 0x80 | self._convertTag(implicit)
else:
- if len(ASN1Type)==1:
- self.typeTag = ord(ASN1Type)
- else:
- self.typeTag = self.typeTags.get(ASN1Type)
+ self._idOctet = asn1Id
+ if constructed:
+ self._idOctet |= 0x20
self.payload = payload
- def isType(self, ASN1Type):
- return self.typeTags[ASN1Type]==self.typeTag
-
- def _lengthOctets(self, payloadLen):
- """Return a byte string that encodes the given payload length (in
- bytes) in a format suitable for a DER length tag (L).
+ def _convertTag(self, tag):
+ """Check if *tag* is a real DER tag.
+ Convert it from a character to number if necessary.
"""
+ if not _isInt(tag):
+ if len(tag)==1:
+ tag = bord(tag[0])
+ # Ensure that tag is a low tag
+ if not (_isInt(tag) and 0 <= tag < 0x1F):
+ raise ValueError("Wrong DER tag")
+ return tag
+
+ def _lengthOctets(self):
+ """Build length octets according to the current object's payload.
+
+ Return a byte string that encodes the payload length (in
+ bytes) in a format suitable for DER length octets (L).
+ """
+ payloadLen = len(self.payload)
if payloadLen>127:
encoding = long_to_bytes(payloadLen)
return bchr(len(encoding)+128) + encoding
return bchr(payloadLen)
def encode(self):
- """Return a complete DER element, fully encoded as a TLV."""
- return bchr(self.typeTag) + self._lengthOctets(len(self.payload)) + self.payload
+ """Return this DER element, fully encoded as a binary byte string."""
+ # Concatenate identifier octets, length octets,
+ # and contents octets
+ return bchr(self._idOctet) + self._lengthOctets() + self.payload
- def _decodeLen(self, idx, der):
- """Given a (part of a) DER element, and an index to the first byte of
- a DER length tag (L), return a tuple with the payload size,
- and the index of the first byte of the such payload (V).
+ def _decodeLen(self, s):
+ """Decode DER length octets from a file."""
- Raises a ValueError exception if the DER length is invalid.
- Raises an IndexError exception if the DER element is too short.
- """
- length = bord(der[idx])
+ length = bord(s.read_byte())
if length<=127:
- return (length,idx+1)
- payloadLength = bytes_to_long(der[idx+1:idx+1+(length & 0x7F)])
+ return length
+ payloadLength = bytes_to_long(s.read(length & 0x7F))
+ # According to DER (but not BER) the long form is used
+ # only when the length doesn't fit into 7 bits.
if payloadLength<=127:
- raise ValueError("Not a DER length tag.")
- return (payloadLength, idx+1+(length & 0x7F))
+ raise ValueError("Not a DER length tag (but still valid BER).")
+ return payloadLength
- def decode(self, derEle, noLeftOvers=0):
+ def decode(self, derEle):
"""Decode a complete DER element, and re-initializes this
object with it.
- @param derEle A complete DER element. It must start with a DER T
- tag.
- @param noLeftOvers Indicate whether it is acceptable to complete the
- parsing of the DER element and find that not all
- bytes in derEle have been used.
- @return Index of the first unused byte in the given DER element.
-
- Raises a ValueError exception in case of parsing errors.
- Raises an IndexError exception if the DER element is too short.
+ :Parameters:
+ derEle : byte string
+ A complete DER element.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
"""
+
+ s = BytesIO_EOF(derEle)
+ self._decodeFromStream(s)
+ # There shouldn't be other bytes left
+ try:
+ b = s.read_byte()
+ raise ValueError("Unexpected extra data after the DER structure")
+ except EOFError:
+ pass
+
+ def _decodeFromStream(self, s):
+ """Decode a complete DER element from a file."""
+
try:
- self.typeTag = bord(derEle[0])
- if (self.typeTag & 0x1F)==0x1F:
- raise ValueError("Unsupported DER tag")
- (length,idx) = self._decodeLen(1, derEle)
- if noLeftOvers and len(derEle) != (idx+length):
- raise ValueError("Not a DER structure")
- self.payload = derEle[idx:idx+length]
- except IndexError:
- raise ValueError("Not a valid DER SEQUENCE.")
- return idx+length
+ idOctet = bord(s.read_byte())
+ except EOFError:
+ raise NoDerElementError
+ if self._idOctet != None:
+ if idOctet != self._idOctet:
+ raise ValueError("Unexpected DER tag")
+ else:
+ self._idOctet = idOctet
+ length = self._decodeLen(s)
+ self.payload = s.read(length)
class DerInteger(DerObject):
- def __init__(self, value = 0):
- """Class to model an INTEGER DER element.
+ """Class to model a DER INTEGER.
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerInteger
+ >>> from binascii import hexlify, unhexlify
+ >>> int_der = DerInteger(9)
+ >>> print hexlify(int_der.encode())
- Limitation: only non-negative values are supported.
+ which will show ``020109``, the DER encoding of 9.
+
+ And for decoding:
+
+ >>> s = unhexlify(b'020109')
+ >>> try:
+ >>> int_der = DerInteger()
+ >>> int_der.decode(s)
+ >>> print int_der.value
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER INTEGER"
+
+ the output will be ``9``.
+ """
+
+ def __init__(self, value=0, implicit=None):
+ """Initialize the DER object as an INTEGER.
+
+ :Parameters:
+ value : integer
+ The value of the integer.
+
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for INTEGER (2).
"""
- DerObject.__init__(self, 'INTEGER')
- self.value = value
+
+ DerObject.__init__(self, 0x02, b(''), implicit, False)
+ self.value = value #: The integer value
def encode(self):
- """Return a complete INTEGER DER element, fully encoded as a TLV."""
- self.payload = long_to_bytes(self.value)
- if bord(self.payload[0])>127:
+ """Return the DER INTEGER, fully encoded as a
+ binary string."""
+
+ number = self.value
+ self.payload = b('')
+ while True:
+ self.payload = bchr(number&255) + self.payload
+ if 128 <= number <= 255:
self.payload = bchr(0x00) + self.payload
+ if -128 <= number <= 255:
+ break
+ number >>= 8
return DerObject.encode(self)
- def decode(self, derEle, noLeftOvers=0):
- """Decode a complete INTEGER DER element, and re-initializes this
+ def decode(self, derEle):
+ """Decode a complete DER INTEGER DER, and re-initializes this
object with it.
- @param derEle A complete INTEGER DER element. It must start with a DER
- INTEGER tag.
- @param noLeftOvers Indicate whether it is acceptable to complete the
- parsing of the DER element and find that not all
- bytes in derEle have been used.
- @return Index of the first unused byte in the given DER element.
-
- Raises a ValueError exception if the DER element is not a
- valid non-negative INTEGER.
- Raises an IndexError exception if the DER element is too short.
+ :Parameters:
+ derEle : byte string
+ A complete INTEGER DER element.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
"""
- tlvLength = DerObject.decode(self, derEle, noLeftOvers)
- if self.typeTag!=self.typeTags['INTEGER']:
- raise ValueError ("Not a DER INTEGER.")
- if bord(self.payload[0])>127:
- raise ValueError ("Negative INTEGER.")
- self.value = bytes_to_long(self.payload)
- return tlvLength
+ DerObject.decode(self, derEle)
+
+ def _decodeFromStream(self, s):
+ """Decode a complete DER INTEGER from a file."""
+
+ # Fill up self.payload
+ DerObject._decodeFromStream(self, s)
+
+ # Derive self.value from self.payload
+ self.value = 0L
+ bits = 1
+ for i in self.payload:
+ self.value *= 256
+ self.value += bord(i)
+ bits <<= 8
+ if self.payload and bord(self.payload[0]) & 0x80:
+ self.value -= bits
+
+def newDerInteger(number):
+ """Create a DerInteger object, already initialized with an integer."""
+
+ der = DerInteger(number)
+ return der
class DerSequence(DerObject):
- """Class to model a SEQUENCE DER element.
+ """Class to model a DER SEQUENCE.
- This object behave like a dynamic Python sequence.
- Sub-elements that are INTEGERs, look like Python integers.
- Any other sub-element is a binary string encoded as the complete DER
+ This object behaves like a dynamic Python sequence.
+
+ Sub-elements that are INTEGERs behave like Python integers.
+
+ Any other sub-element is a binary string encoded as a complete DER
sub-element (TLV).
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerSequence, DerInteger
+ >>> from binascii import hexlify, unhexlify
+ >>> obj_der = unhexlify('070102')
+ >>> seq_der = DerSequence([4])
+ >>> seq_der.append(9)
+ >>> seq_der.append(obj_der.encode())
+ >>> print hexlify(seq_der.encode())
+
+ which will show ``3009020104020109070102``, the DER encoding of the
+ sequence containing ``4``, ``9``, and the object with payload ``02``.
+
+ For decoding:
+
+ >>> s = unhexlify(b'3009020104020109070102')
+ >>> try:
+ >>> seq_der = DerSequence()
+ >>> seq_der.decode(s)
+ >>> print len(seq_der)
+ >>> print seq_der[0]
+ >>> print seq_der[:]
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER SEQUENCE"
+
+ the output will be::
+
+ 3
+ 4
+ [4L, 9L, b'\x07\x01\x02']
+
"""
- def __init__(self, startSeq=None):
- """Initialize the SEQUENCE DER object. Always empty
- initially."""
- DerObject.__init__(self, 'SEQUENCE')
+ def __init__(self, startSeq=None, implicit=None):
+ """Initialize the DER object as a SEQUENCE.
+
+ :Parameters:
+ startSeq : Python sequence
+ A sequence whose element are either integers or
+ other DER objects.
+
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for SEQUENCE (16).
+ """
+
+ DerObject.__init__(self, 0x10, b(''), implicit, True)
if startSeq==None:
self._seq = []
else:
@@ -182,105 +383,517 @@ class DerSequence(DerObject):
return self._seq[max(0, i):max(0, j)]
def __len__(self):
return len(self._seq)
+ def __iadd__(self, item):
+ self._seq.append(item)
+ return self
def append(self, item):
- return self._seq.append(item)
-
- def hasInts(self):
- """Return the number of items in this sequence that are numbers."""
- return len(filter(isInt, self._seq))
-
- def hasOnlyInts(self):
- """Return True if all items in this sequence are numbers."""
- return self._seq and self.hasInts()==len(self._seq)
+ self._seq.append(item)
+ return self
+
+ def hasInts(self, onlyNonNegative=True):
+ """Return the number of items in this sequence that are
+ integers.
+
+ :Parameters:
+ onlyNonNegative : boolean
+ If True, negative integers are not counted in.
+ """
+ def _isInt2(x):
+ return _isInt(x, onlyNonNegative)
+ return len(filter(_isInt2, self._seq))
+
+ def hasOnlyInts(self, onlyNonNegative=True):
+ """Return True if all items in this sequence are integers
+ or non-negative integers.
+
+ This function returns False is the sequence is empty,
+ or at least one member is not an integer.
+
+ :Parameters:
+ onlyNonNegative : boolean
+ If True, the presence of negative integers
+ causes the method to return False."""
+ return self._seq and self.hasInts(onlyNonNegative)==len(self._seq)
def encode(self):
- """Return the DER encoding for the ASN.1 SEQUENCE, containing
- the non-negative integers and longs added to this object.
-
- Limitation: Raises a ValueError exception if it some elements
- in the sequence are neither Python integers nor complete DER INTEGERs.
+ """Return this DER SEQUENCE, fully encoded as a
+ binary string.
+
+ :Raises ValueError:
+ If some elements in the sequence are neither integers
+ nor byte strings.
"""
self.payload = b('')
for item in self._seq:
+ try:
+ self.payload += item
+ except TypeError:
try:
- self.payload += item
- except:
- try:
- self.payload += DerInteger(item).encode()
- except:
- raise ValueError("Trying to DER encode an unknown object")
+ self.payload += DerInteger(item).encode()
+ except TypeError:
+ raise ValueError("Trying to DER encode an unknown object")
return DerObject.encode(self)
- def decode(self, derEle, noLeftOvers=0):
- """Decode a complete SEQUENCE DER element, and re-initializes this
+ def decode(self, derEle):
+ """Decode a complete DER SEQUENCE, and re-initializes this
object with it.
- @param derEle A complete SEQUENCE DER element. It must start with a DER
- SEQUENCE tag.
- @param noLeftOvers Indicate whether it is acceptable to complete the
- parsing of the DER element and find that not all
- bytes in derEle have been used.
- @return Index of the first unused byte in the given DER element.
+ :Parameters:
+ derEle : byte string
+ A complete SEQUENCE DER element.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
DER INTEGERs are decoded into Python integers. Any other DER
element is not decoded. Its validity is not checked.
-
- Raises a ValueError exception if the DER element is not a
- valid DER SEQUENCE.
- Raises an IndexError exception if the DER element is too short.
"""
+ DerObject.decode(self, derEle)
+ def _decodeFromStream(self, s):
+ """Decode a complete DER SEQUENCE from a file."""
+
self._seq = []
- try:
- tlvLength = DerObject.decode(self, derEle, noLeftOvers)
- if self.typeTag!=self.typeTags['SEQUENCE']:
- raise ValueError("Not a DER SEQUENCE.")
- # Scan one TLV at once
- idx = 0
- while idx<len(self.payload):
- typeTag = bord(self.payload[idx])
- if typeTag==self.typeTags['INTEGER']:
- newInteger = DerInteger()
- idx += newInteger.decode(self.payload[idx:])
- self._seq.append(newInteger.value)
- else:
- itemLen,itemIdx = self._decodeLen(idx+1,self.payload)
- self._seq.append(self.payload[idx:itemIdx+itemLen])
- idx = itemIdx + itemLen
- except IndexError:
- raise ValueError("Not a valid DER SEQUENCE.")
- return tlvLength
+
+ # Fill up self.payload
+ DerObject._decodeFromStream(self, s)
+
+ # Add one item at a time to self.seq, by scanning self.payload
+ p = BytesIO_EOF(self.payload)
+ while True:
+ try:
+ p.setRecord(True)
+ der = DerObject()
+ der._decodeFromStream(p)
+
+ # Parse INTEGERs differently
+ if der._idOctet != 0x02:
+ self._seq.append(p._recording)
+ else:
+ derInt = DerInteger()
+ derInt.decode(p._recording)
+ self._seq.append(derInt.value)
+
+ except NoDerElementError:
+ break
+ # end
+
+def newDerSequence(*der_objs):
+ """Create a DerSequence object, already initialized with all objects
+ passed as parameters."""
+
+ der = DerSequence()
+ for obj in der_objs:
+ if isinstance(obj, DerObject):
+ der += obj.encode()
+ else:
+ der += obj
+ return der
class DerOctetString(DerObject):
- def __init__(self, value = b('')):
- DerObject.__init__(self, 'OCTET STRING')
- self.payload = value
-
- def decode(self, derEle, noLeftOvers=0):
- p = DerObject.decode(derEle, noLeftOvers)
- if not self.isType("OCTET STRING"):
- raise ValueError("Not a valid OCTET STRING.")
- return p
+ """Class to model a DER OCTET STRING.
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerOctetString
+ >>> from binascii import hexlify, unhexlify
+ >>> os_der = DerOctetString(b'\\xaa')
+ >>> os_der.payload += b'\\xbb'
+ >>> print hexlify(os_der.encode())
+
+ which will show ``0402aabb``, the DER encoding for the byte string
+ ``b'\\xAA\\xBB'``.
+
+ For decoding:
+
+ >>> s = unhexlify(b'0402aabb')
+ >>> try:
+ >>> os_der = DerOctetString()
+ >>> os_der.decode(s)
+ >>> print hexlify(os_der.payload)
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER OCTET STRING"
+
+ the output will be ``aabb``.
+ """
+
+ def __init__(self, value=b(''), implicit=None):
+ """Initialize the DER object as an OCTET STRING.
+
+ :Parameters:
+ value : byte string
+ The initial payload of the object.
+ If not specified, the payload is empty.
+
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for OCTET STRING (4).
+ """
+ DerObject.__init__(self, 0x04, value, implicit, False)
+
+def newDerOctetString(binstring):
+ """Create a DerOctetString object, already initialized with the binary
+ string."""
+
+ if isinstance(binstring, DerObject):
+ der = DerOctetString(binstring.encode())
+ else:
+ der = DerOctetString(binstring)
+ return der
class DerNull(DerObject):
+ """Class to model a DER NULL element."""
+
def __init__(self):
- DerObject.__init__(self, 'NULL')
+ """Initialize the DER object as a NULL."""
+
+ DerObject.__init__(self, 0x05, b(''), False)
class DerObjectId(DerObject):
- def __init__(self):
- DerObject.__init__(self, 'OBJECT IDENTIFIER')
+ """Class to model a DER OBJECT ID.
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerObjectId
+ >>> from binascii import hexlify, unhexlify
+ >>> oid_der = DerObjectId("1.2")
+ >>> oid_der.value += ".840.113549.1.1.1"
+ >>> print hexlify(oid_der.encode())
+
+ which will show ``06092a864886f70d010101``, the DER encoding for the
+ RSA Object Identifier ``1.2.840.113549.1.1.1``.
+
+ For decoding:
+
+ >>> s = unhexlify(b'06092a864886f70d010101')
+ >>> try:
+ >>> oid_der = DerObjectId()
+ >>> oid_der.decode(s)
+ >>> print oid_der.value
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER OBJECT ID"
+
+ the output will be ``1.2.840.113549.1.1.1``.
+ """
+
+ def __init__(self, value='', implicit=None):
+ """Initialize the DER object as an OBJECT ID.
+
+ :Parameters:
+ value : string
+ The initial Object Identifier (e.g. "1.2.0.0.6.2").
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for OBJECT ID (6).
+ """
+ DerObject.__init__(self, 0x06, b(''), implicit, False)
+ self.value = value #: The Object ID, a dot separated list of integers
+
+ def encode(self):
+ """Return the DER OBJECT ID, fully encoded as a
+ binary string."""
+
+ comps = map(int,self.value.split("."))
+ if len(comps)<2:
+ raise ValueError("Not a valid Object Identifier string")
+ self.payload = bchr(40*comps[0]+comps[1])
+ for v in comps[2:]:
+ enc = []
+ while v:
+ enc.insert(0, (v & 0x7F) | 0x80)
+ v >>= 7
+ enc[-1] &= 0x7F
+ self.payload += b('').join(map(bchr, enc))
+ return DerObject.encode(self)
+
+ def decode(self, derEle):
+ """Decode a complete DER OBJECT ID, and re-initializes this
+ object with it.
+
+ :Parameters:
+ derEle : byte string
+ A complete DER OBJECT ID.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
+ """
- def decode(self, derEle, noLeftOvers=0):
- p = DerObject.decode(derEle, noLeftOvers)
- if not self.isType("OBJECT IDENTIFIER"):
- raise ValueError("Not a valid OBJECT IDENTIFIER.")
- return p
+ DerObject.decode(self, derEle)
+
+ def _decodeFromStream(self, s):
+ """Decode a complete DER OBJECT ID from a file."""
+
+ # Fill up self.payload
+ DerObject._decodeFromStream(self, s)
+
+ # Derive self.value from self.payload
+ p = BytesIO_EOF(self.payload)
+ comps = list(map(str, divmod(bord(p.read_byte()),40)))
+ v = 0
+ try:
+ while True:
+ c = p.read_byte()
+ v = v*128 + (bord(c) & 0x7F)
+ if not (bord(c) & 0x80):
+ comps.append(str(v))
+ v = 0
+ except EOFError:
+ pass
+ self.value = '.'.join(comps)
+
+def newDerObjectId(dottedstring):
+ """Create a DerObjectId object, already initialized with the given Object
+ Identifier (a dotted string)."""
+
+ der = DerObjectId(dottedstring)
+ return der
+
+class DerBitString(DerObject):
+ """Class to model a DER BIT STRING.
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerBitString
+ >>> from binascii import hexlify, unhexlify
+ >>> bs_der = DerBitString(b'\\xaa')
+ >>> bs_der.value += b'\\xbb'
+ >>> print hexlify(bs_der.encode())
+
+ which will show ``040300aabb``, the DER encoding for the bit string
+ ``b'\\xAA\\xBB'``.
+
+ For decoding:
+
+ >>> s = unhexlify(b'040300aabb')
+ >>> try:
+ >>> bs_der = DerBitString()
+ >>> bs_der.decode(s)
+ >>> print hexlify(bs_der.value)
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER OCTET STRING"
+
+ the output will be ``aabb``.
+ """
+
+ def __init__(self, value=b(''), implicit=None):
+ """Initialize the DER object as a BIT STRING.
+
+ :Parameters:
+ value : byte string
+ The initial, packed bit string.
+ If not specified, the bit string is empty.
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for OCTET STRING (3).
+ """
+ DerObject.__init__(self, 0x03, b(''), implicit, False)
+ self.value = value #: The bitstring value (packed)
+
+ def encode(self):
+ """Return the DER BIT STRING, fully encoded as a
+ binary string."""
+
+ # Add padding count byte
+ self.payload = b('\x00') + self.value
+ return DerObject.encode(self)
+
+ def decode(self, derEle):
+ """Decode a complete DER BIT STRING, and re-initializes this
+ object with it.
+
+ :Parameters:
+ derEle : byte string
+ A complete DER BIT STRING.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
+ """
-def isInt(x):
- test = 0
- try:
- test += x
- except TypeError:
- return 0
- return 1
+ DerObject.decode(self, derEle)
+
+ def _decodeFromStream(self, s):
+ """Decode a complete DER BIT STRING DER from a file."""
+
+ # Fill-up self.payload
+ DerObject._decodeFromStream(self, s)
+
+ if self.payload and bord(self.payload[0])!=0:
+ raise ValueError("Not a valid BIT STRING")
+
+ # Fill-up self.value
+ self.value = b('')
+ # Remove padding count byte
+ if self.payload:
+ self.value = self.payload[1:]
+
+def newDerBitString(binstring):
+ """Create a DerStringString object, already initialized with the binary
+ string."""
+
+ if isinstance(binstring, DerObject):
+ der = DerBitString(binstring.encode())
+ else:
+ der = DerBitString(binstring)
+ return der
+
+class DerSetOf(DerObject):
+ """Class to model a DER SET OF.
+
+ An example of encoding is:
+
+ >>> from Crypto.Util.asn1 import DerBitString
+ >>> from binascii import hexlify, unhexlify
+ >>> so_der = DerSetOf([4,5])
+ >>> so_der.add(6)
+ >>> print hexlify(so_der.encode())
+
+ which will show ``3109020104020105020106``, the DER encoding
+ of a SET OF with items 4,5, and 6.
+
+ For decoding:
+
+ >>> s = unhexlify(b'3109020104020105020106')
+ >>> try:
+ >>> so_der = DerSetOf()
+ >>> so_der.decode(s)
+ >>> print [x for x in so_der]
+ >>> except (ValueError, EOFError):
+ >>> print "Not a valid DER SET OF"
+
+ the output will be ``[4L, 5L, 6L]``.
+ """
+
+ def __init__(self, startSet=None, implicit=None):
+ """Initialize the DER object as a SET OF.
+
+ :Parameters:
+ startSet : container
+ The initial set of integers or DER encoded objects.
+ implicit : integer
+ The IMPLICIT tag to use for the encoded object.
+ It overrides the universal tag for SET OF (17).
+ """
+ DerObject.__init__(self, 0x11, b(''), implicit, True)
+ self._seq = []
+ self._elemOctet = None
+ if startSet:
+ for e in startSet:
+ self.add(e)
+
+ def __getitem__(self, n):
+ return self._seq[n]
+
+ def __iter__(self):
+ return iter(self._seq)
+
+ def __len__(self):
+ return len(self._seq)
+
+ def add(self, elem):
+ """Add an element to the set.
+
+ :Parameters:
+ elem : byte string or integer
+ An element of the same type of objects already in the set.
+ It can be an integer or a DER encoded object.
+ """
+ if _isInt(elem):
+ eo = 0x02
+ else:
+ eo = bord(elem[0])
+ if self._elemOctet != eo:
+ if self._elemOctet:
+ raise ValueError("New element does not belong to the set")
+ self._elemOctet = eo
+ if not elem in self._seq:
+ self._seq.append(elem)
+
+ def decode(self, derEle):
+ """Decode a complete SET OF DER element, and re-initializes this
+ object with it.
+
+ DER INTEGERs are decoded into Python integers. Any other DER
+ element is left undecoded; its validity is not checked.
+
+ :Parameters:
+ derEle : byte string
+ A complete DER BIT SET OF.
+
+ :Raise ValueError:
+ In case of parsing errors.
+ :Raise EOFError:
+ If the DER element is too short.
+ """
+
+ DerObject.decode(self, derEle)
+
+ def _decodeFromStream(self, s):
+ """Decode a complete DER SET OF from a file."""
+
+ self._seq = []
+
+ # Fill up self.payload
+ DerObject._decodeFromStream(self, s)
+
+ # Add one item at a time to self.seq, by scanning self.payload
+ p = BytesIO_EOF(self.payload)
+ setIdOctet = -1
+ while True:
+ try:
+ p.setRecord(True)
+ der = DerObject()
+ der._decodeFromStream(p)
+
+ # Verify that all members are of the same type
+ if setIdOctet < 0:
+ setIdOctet = der._idOctet
+ else:
+ if setIdOctet != der._idOctet:
+ raise ValueError("Not all elements are of the same DER type")
+
+ # Parse INTEGERs differently
+ if setIdOctet != 0x02:
+ self._seq.append(p._recording)
+ else:
+ derInt = DerInteger()
+ derInt.decode(p._recording)
+ self._seq.append(derInt.value)
+
+ except NoDerElementError:
+ break
+ # end
+
+ def encode(self):
+ """Return this SET OF DER element, fully encoded as a
+ binary string.
+ """
+ # Elements in the set must be ordered in lexicographic order
+ ordered = []
+ for item in self._seq:
+ if _isInt(item):
+ bys = DerInteger(item).encode()
+ else:
+ bys = item
+ ordered.append(bys)
+ ordered.sort()
+ self.payload = b('').join(ordered)
+ return DerObject.encode(self)
+
+def newDerSetOf(*der_objs):
+ """Create a DerSequence object, already initialized with all objects
+ passed as parameters."""
+
+ der = DerSetOf()
+ for obj in der_objs:
+ if isinstance(obj, DerObject):
+ der.add(obj.encode())
+ else:
+ der.add(obj)
+ return der
diff --git a/lib/Crypto/Util/py21compat.py b/lib/Crypto/Util/py21compat.py
index 624408b..658fd36 100644
--- a/lib/Crypto/Util/py21compat.py
+++ b/lib/Crypto/Util/py21compat.py
@@ -81,4 +81,21 @@ except TypeError:
return True
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:
diff --git a/lib/Crypto/Util/py3compat.py b/lib/Crypto/Util/py3compat.py
index 34e5224..b8b89bf 100644
--- a/lib/Crypto/Util/py3compat.py
+++ b/lib/Crypto/Util/py3compat.py
@@ -77,12 +77,18 @@ if sys.version_info[0] == 2:
return s.encode('latin-1')
except:
return ''.join(s)
+ def tostr(bs):
+ return unicode(bs, 'latin-1')
else:
def tobytes(s):
if isinstance(s, unicode):
return s.encode("latin-1")
else:
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:
def b(s):
return s.encode("latin-1") # utf-8 would cause some side-effects we don't want
@@ -103,5 +109,9 @@ else:
return s.encode("latin-1")
else:
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:
diff --git a/lib/Crypto/__init__.py b/lib/Crypto/__init__.py
index c27402e..db238d7 100644
--- a/lib/Crypto/__init__.py
+++ b/lib/Crypto/__init__.py
@@ -41,7 +41,7 @@ Crypto.Util
generation, number theoretic functions)
"""
-__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature']
+__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', 'IO']
__version__ = '2.6.1' # See also below and setup.py
__revision__ = "$Id$"
diff --git a/lib/Crypto/pct_warnings.py b/lib/Crypto/pct_warnings.py
index 9b4361e..d6adc5b 100644
--- a/lib/Crypto/pct_warnings.py
+++ b/lib/Crypto/pct_warnings.py
@@ -49,6 +49,9 @@ class ClockRewindWarning(CryptoRuntimeWarning):
class GetRandomNumber_DeprecationWarning(CryptoDeprecationWarning):
"""Issued when Crypto.Util.number.getRandomNumber is invoked."""
+class DisableShortcut_DeprecationWarning(CryptoDeprecationWarning):
+ """Issued when Counter.new(disable_shortcut=...) is invoked."""
+
class PowmInsecureWarning(CryptoRuntimeWarning):
"""Warning for when _fastmath is built without mpz_powm_sec"""