basic functionalty
This commit is contained in:
368
modules/Crypto/Signature/PKCS1_PSS.py
Normal file
368
modules/Crypto/Signature/PKCS1_PSS.py
Normal file
@@ -0,0 +1,368 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Signature/PKCS1_PSS.py : PKCS#1 PPS
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""RSA digital signature protocol with appendix according to PKCS#1 PSS.
|
||||
|
||||
See RFC3447__ or the `original RSA Labs specification`__.
|
||||
|
||||
This scheme is more properly called ``RSASSA-PSS``.
|
||||
|
||||
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 SHA1
|
||||
>>> from Crypto.PublicKey import RSA1
|
||||
>>> from Crypto import Random
|
||||
>>>
|
||||
>>> message = 'To be signed'
|
||||
>>> key = RSA.importKey(open('privkey.der').read())
|
||||
>>> h = SHA1.new()
|
||||
>>> h.update(message)
|
||||
>>> signer = PKCS1_PSS.new(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 = SHA1.new()
|
||||
>>> h.update(message)
|
||||
>>> verifier = PKCS1_PSS.new(key)
|
||||
>>> if verifier.verify(h, signature):
|
||||
>>> print "The signature is authentic."
|
||||
>>> else:
|
||||
>>> print "The signature is not authentic."
|
||||
|
||||
:undocumented: __revision__, __package__
|
||||
|
||||
.. __: http://www.ietf.org/rfc/rfc3447.txt
|
||||
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125
|
||||
"""
|
||||
|
||||
# Allow nested scopes in Python 2.1
|
||||
# See http://oreilly.com/pub/a/python/2001/04/19/pythonnews.html
|
||||
from __future__ import nested_scopes
|
||||
|
||||
__revision__ = "$Id$"
|
||||
__all__ = [ 'new', 'PSS_SigScheme' ]
|
||||
|
||||
from Crypto.Util.py3compat import *
|
||||
if sys.version_info[0] == 2 and sys.version_info[1] == 1:
|
||||
from Crypto.Util.py21compat import *
|
||||
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."""
|
||||
|
||||
def __init__(self, key, mgfunc, saltLen):
|
||||
"""Initialize this PKCS#1 PSS signature scheme object.
|
||||
|
||||
:Parameters:
|
||||
key : an RSA key object
|
||||
If a private half is given, both signature and verification are possible.
|
||||
If a public half is given, only verification is possible.
|
||||
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.
|
||||
saltLen : int
|
||||
Length of the salt, in bytes.
|
||||
"""
|
||||
self._key = key
|
||||
self._saltLen = saltLen
|
||||
self._mgfunc = mgfunc
|
||||
|
||||
def can_sign(self):
|
||||
"""Return True if this cipher object can be used for signing messages."""
|
||||
return self._key.has_private()
|
||||
|
||||
def sign(self, mhash):
|
||||
"""Produce the PKCS#1 PSS signature of a message.
|
||||
|
||||
This function is named ``RSASSA-PSS-SIGN``, and is specified in
|
||||
section 8.1.1 of RFC3447.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash that was carried out over the message. This is an object
|
||||
belonging to the `Crypto.Hash` module.
|
||||
|
||||
:Return: The PSS signature encoded as a string.
|
||||
:Raise ValueError:
|
||||
If the RSA key length is not sufficiently long to deal with the given
|
||||
hash algorithm.
|
||||
:Raise TypeError:
|
||||
If the RSA key has no private half.
|
||||
|
||||
:attention: Modify the salt length and the mask generation function only
|
||||
if you know what you are doing.
|
||||
The receiver must use the same parameters too.
|
||||
"""
|
||||
# TODO: Verify the key is RSA
|
||||
|
||||
randfunc = self._key._randfunc
|
||||
|
||||
# Set defaults for salt length and mask generation function
|
||||
if self._saltLen == None:
|
||||
sLen = mhash.digest_size
|
||||
else:
|
||||
sLen = self._saltLen
|
||||
if self._mgfunc:
|
||||
mgf = self._mgfunc
|
||||
else:
|
||||
mgf = lambda x,y: MGF1(x,y,mhash)
|
||||
|
||||
modBits = Crypto.Util.number.size(self._key.n)
|
||||
|
||||
# See 8.1.1 in RFC3447
|
||||
k = ceil_div(modBits,8) # Convert from bits to bytes
|
||||
# Step 1
|
||||
em = EMSA_PSS_ENCODE(mhash, modBits-1, randfunc, mgf, sLen)
|
||||
# Step 2a (OS2IP) and 2b (RSASP1)
|
||||
m = self._key.decrypt(em)
|
||||
# Step 2c (I2OSP)
|
||||
S = bchr(0x00)*(k-len(m)) + m
|
||||
return S
|
||||
|
||||
def verify(self, mhash, S):
|
||||
"""Verify that a certain PKCS#1 PSS signature is authentic.
|
||||
|
||||
This function checks if the party holding the private half of the given
|
||||
RSA key has really signed the message.
|
||||
|
||||
This function is called ``RSASSA-PSS-VERIFY``, and is specified in section
|
||||
8.1.2 of RFC3447.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash that was carried out over the message. This is an object
|
||||
belonging to the `Crypto.Hash` module.
|
||||
S : string
|
||||
The signature that needs to be validated.
|
||||
|
||||
:Return: True if verification is correct. False otherwise.
|
||||
"""
|
||||
# TODO: Verify the key is RSA
|
||||
|
||||
# Set defaults for salt length and mask generation function
|
||||
if self._saltLen == None:
|
||||
sLen = mhash.digest_size
|
||||
else:
|
||||
sLen = self._saltLen
|
||||
if self._mgfunc:
|
||||
mgf = self._mgfunc
|
||||
else:
|
||||
mgf = lambda x,y: MGF1(x,y,mhash)
|
||||
|
||||
modBits = Crypto.Util.number.size(self._key.n)
|
||||
|
||||
# See 8.1.2 in RFC3447
|
||||
k = ceil_div(modBits,8) # Convert from bits to bytes
|
||||
# Step 1
|
||||
if len(S) != k:
|
||||
return False
|
||||
# Step 2a (O2SIP), 2b (RSAVP1), and partially 2c (I2OSP)
|
||||
# Note that signature must be smaller than the module
|
||||
# but RSA.py won't complain about it.
|
||||
# TODO: Fix RSA object; don't do it here.
|
||||
em = self._key.encrypt(S, 0)[0]
|
||||
# Step 2c
|
||||
emLen = ceil_div(modBits-1,8)
|
||||
em = bchr(0x00)*(emLen-len(em)) + em
|
||||
# Step 3
|
||||
try:
|
||||
result = EMSA_PSS_VERIFY(mhash, em, modBits-1, mgf, sLen)
|
||||
except ValueError:
|
||||
return False
|
||||
# Step 4
|
||||
return result
|
||||
|
||||
def MGF1(mgfSeed, maskLen, hash):
|
||||
"""Mask Generation Function, described in B.2.1"""
|
||||
T = b("")
|
||||
for counter in xrange(ceil_div(maskLen, hash.digest_size)):
|
||||
c = long_to_bytes(counter, 4)
|
||||
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]
|
||||
|
||||
def EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen):
|
||||
"""
|
||||
Implement the ``EMSA-PSS-ENCODE`` function, as defined
|
||||
in PKCS#1 v2.1 (RFC3447, 9.1.1).
|
||||
|
||||
The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` as input,
|
||||
and hash it internally. Here, we expect that the message has already
|
||||
been hashed instead.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash object that holds the digest of the message being signed.
|
||||
emBits : int
|
||||
Maximum length of the final encoding, in bits.
|
||||
randFunc : callable
|
||||
An RNG function that accepts as only parameter an int, and returns
|
||||
a string of random bytes, to be used as salt.
|
||||
mgf : 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.
|
||||
sLen : int
|
||||
Length of the salt, in bytes.
|
||||
|
||||
:Return: An ``emLen`` byte long string that encodes the hash
|
||||
(with ``emLen = \ceil(emBits/8)``).
|
||||
|
||||
:Raise ValueError:
|
||||
When digest or salt length are too big.
|
||||
"""
|
||||
|
||||
emLen = ceil_div(emBits,8)
|
||||
|
||||
# Bitmask of digits that fill up
|
||||
lmask = 0
|
||||
for i in xrange(8*emLen-emBits):
|
||||
lmask = lmask>>1 | 0x80
|
||||
|
||||
# Step 1 and 2 have been already done
|
||||
# Step 3
|
||||
if emLen < mhash.digest_size+sLen+2:
|
||||
raise ValueError("Digest or salt length are too long for given key size.")
|
||||
# Step 4
|
||||
salt = b("")
|
||||
if randFunc and sLen>0:
|
||||
salt = randFunc(sLen)
|
||||
# Step 5 and 6
|
||||
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
|
||||
dbMask = mgf(h.digest(), emLen-mhash.digest_size-1)
|
||||
# Step 10
|
||||
maskedDB = strxor(db,dbMask)
|
||||
# Step 11
|
||||
maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:]
|
||||
# Step 12
|
||||
em = maskedDB + h.digest() + bchr(0xBC)
|
||||
return em
|
||||
|
||||
def EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen):
|
||||
"""
|
||||
Implement the ``EMSA-PSS-VERIFY`` function, as defined
|
||||
in PKCS#1 v2.1 (RFC3447, 9.1.2).
|
||||
|
||||
``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input,
|
||||
and hash it internally. Here, we expect that the message has already
|
||||
been hashed instead.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash object that holds the digest of the message to be verified.
|
||||
em : string
|
||||
The signature to verify, therefore proving that the sender really signed
|
||||
the message that was received.
|
||||
emBits : int
|
||||
Length of the final encoding (em), in bits.
|
||||
mgf : 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.
|
||||
sLen : int
|
||||
Length of the salt, in bytes.
|
||||
|
||||
:Return: 0 if the encoding is consistent, 1 if it is inconsistent.
|
||||
|
||||
:Raise ValueError:
|
||||
When digest or salt length are too big.
|
||||
"""
|
||||
|
||||
emLen = ceil_div(emBits,8)
|
||||
|
||||
# Bitmask of digits that fill up
|
||||
lmask = 0
|
||||
for i in xrange(8*emLen-emBits):
|
||||
lmask = lmask>>1 | 0x80
|
||||
|
||||
# Step 1 and 2 have been already done
|
||||
# Step 3
|
||||
if emLen < mhash.digest_size+sLen+2:
|
||||
return False
|
||||
# Step 4
|
||||
if ord(em[-1:])!=0xBC:
|
||||
return False
|
||||
# Step 5
|
||||
maskedDB = em[:emLen-mhash.digest_size-1]
|
||||
h = em[emLen-mhash.digest_size-1:-1]
|
||||
# Step 6
|
||||
if lmask & bord(em[0]):
|
||||
return False
|
||||
# Step 7
|
||||
dbMask = mgf(h, emLen-mhash.digest_size-1)
|
||||
# Step 8
|
||||
db = strxor(maskedDB, dbMask)
|
||||
# Step 9
|
||||
db = bchr(bord(db[0]) & ~lmask) + db[1:]
|
||||
# Step 10
|
||||
if not db.startswith(bchr(0x00)*(emLen-mhash.digest_size-sLen-2) + bchr(0x01)):
|
||||
return False
|
||||
# Step 11
|
||||
salt = b("")
|
||||
if sLen: salt = db[-sLen:]
|
||||
# Step 12 and 13
|
||||
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
|
||||
return True
|
||||
|
||||
def new(key, mgfunc=None, saltLen=None):
|
||||
"""Return a signature scheme object `PSS_SigScheme` that
|
||||
can be used to perform PKCS#1 PSS signature or verification.
|
||||
|
||||
:Parameters:
|
||||
key : RSA key object
|
||||
The key to use to sign or verify the message. This is a `Crypto.PublicKey.RSA` object.
|
||||
Signing is only possible if *key* is a private RSA key.
|
||||
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.
|
||||
saltLen : int
|
||||
Length of the salt, in bytes. If not specified, it matches the output
|
||||
size of the hash function.
|
||||
|
||||
"""
|
||||
return PSS_SigScheme(key, mgfunc, saltLen)
|
||||
|
328
modules/Crypto/Signature/PKCS1_v1_5.py
Normal file
328
modules/Crypto/Signature/PKCS1_v1_5.py
Normal file
@@ -0,0 +1,328 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Signature/PKCS1-v1_5.py : PKCS#1 v1.5
|
||||
#
|
||||
# ===================================================================
|
||||
# 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.
|
||||
# ===================================================================
|
||||
|
||||
"""
|
||||
RSA digital signature protocol according to PKCS#1 v1.5
|
||||
|
||||
See RFC3447__ or the `original RSA Labs specification`__.
|
||||
|
||||
This scheme is more properly called ``RSASSA-PKCS1-v1_5``.
|
||||
|
||||
For example, a sender may authenticate a message using SHA-1 like
|
||||
this:
|
||||
|
||||
>>> from Crypto.Signature import PKCS1_v1_5
|
||||
>>> from Crypto.Hash import SHA
|
||||
>>> from Crypto.PublicKey import RSA
|
||||
>>>
|
||||
>>> message = 'To be signed'
|
||||
>>> key = RSA.importKey(open('privkey.der').read())
|
||||
>>> h = SHA.new(message)
|
||||
>>> signer = PKCS1_v1_5.new(key)
|
||||
>>> signature = signer.sign(h)
|
||||
|
||||
At the receiver side, verification can be done using the public part of
|
||||
the RSA key:
|
||||
|
||||
>>> key = RSA.importKey(open('pubkey.der').read())
|
||||
>>> h = SHA.new(message)
|
||||
>>> verifier = PKCS1_v1_5.new(key)
|
||||
>>> if verifier.verify(h, signature):
|
||||
>>> print "The signature is authentic."
|
||||
>>> else:
|
||||
>>> print "The signature is not authentic."
|
||||
|
||||
:undocumented: __revision__, __package__
|
||||
|
||||
.. __: http://www.ietf.org/rfc/rfc3447.txt
|
||||
.. __: http://www.rsa.com/rsalabs/node.asp?id=2125
|
||||
"""
|
||||
|
||||
__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, 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:
|
||||
"""This signature scheme can perform PKCS#1 v1.5 RSA signature or verification."""
|
||||
|
||||
def __init__(self, key):
|
||||
"""Initialize this PKCS#1 v1.5 signature scheme object.
|
||||
|
||||
:Parameters:
|
||||
key : an RSA key object
|
||||
If a private half is given, both signature and verification are possible.
|
||||
If a public half is given, only verification is possible.
|
||||
"""
|
||||
self._key = key
|
||||
|
||||
def can_sign(self):
|
||||
"""Return True if this cipher object can be used for signing messages."""
|
||||
return self._key.has_private()
|
||||
|
||||
def sign(self, mhash):
|
||||
"""Produce the PKCS#1 v1.5 signature of a message.
|
||||
|
||||
This function is named ``RSASSA-PKCS1-V1_5-SIGN``, and is specified in
|
||||
section 8.2.1 of RFC3447.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash that was carried out over the message. This is an object
|
||||
belonging to the `Crypto.Hash` module.
|
||||
|
||||
:Return: The signature encoded as a string.
|
||||
:Raise ValueError:
|
||||
If the RSA key length is not sufficiently long to deal with the given
|
||||
hash algorithm.
|
||||
:Raise TypeError:
|
||||
If the RSA key has no private half.
|
||||
"""
|
||||
# TODO: Verify the key is RSA
|
||||
|
||||
# See 8.2.1 in RFC3447
|
||||
modBits = Crypto.Util.number.size(self._key.n)
|
||||
k = ceil_div(modBits,8) # Convert from bits to bytes
|
||||
|
||||
# Step 1
|
||||
em = EMSA_PKCS1_V1_5_ENCODE(mhash, k)
|
||||
# Step 2a (OS2IP) and 2b (RSASP1)
|
||||
m = self._key.decrypt(em)
|
||||
# Step 2c (I2OSP)
|
||||
S = bchr(0x00)*(k-len(m)) + m
|
||||
return S
|
||||
|
||||
def verify(self, mhash, S):
|
||||
"""Verify that a certain PKCS#1 v1.5 signature is authentic.
|
||||
|
||||
This function checks if the party holding the private half of the key
|
||||
really signed the message.
|
||||
|
||||
This function is named ``RSASSA-PKCS1-V1_5-VERIFY``, and is specified in
|
||||
section 8.2.2 of RFC3447.
|
||||
|
||||
:Parameters:
|
||||
mhash : hash object
|
||||
The hash that was carried out over the message. This is an object
|
||||
belonging to the `Crypto.Hash` module.
|
||||
S : string
|
||||
The signature that needs to be validated.
|
||||
|
||||
:Return: True if verification is correct. False otherwise.
|
||||
"""
|
||||
# TODO: Verify the key is RSA
|
||||
|
||||
# See 8.2.2 in RFC3447
|
||||
modBits = Crypto.Util.number.size(self._key.n)
|
||||
k = ceil_div(modBits,8) # Convert from bits to bytes
|
||||
|
||||
# Step 1
|
||||
if len(S) != k:
|
||||
return 0
|
||||
# Step 2a (O2SIP) and 2b (RSAVP1)
|
||||
# Note that signature must be smaller than the module
|
||||
# but RSA.py won't complain about it.
|
||||
# TODO: Fix RSA object; don't do it here.
|
||||
m = self._key.encrypt(S, 0)[0]
|
||||
# Step 2c (I2OSP)
|
||||
em1 = bchr(0x00)*(k-len(m)) + m
|
||||
# Step 3
|
||||
try:
|
||||
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
|
||||
# By comparing the full encodings (as opposed to checking each
|
||||
# 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_with_params or em1==em2_without_params
|
||||
|
||||
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).
|
||||
|
||||
``EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input,
|
||||
and hash it internally. Here, we expect that the message has already
|
||||
been hashed instead.
|
||||
|
||||
:Parameters:
|
||||
hash : hash object
|
||||
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
|
||||
might have length tags in indefinite form, which
|
||||
is not supported in DER. Such encoding cannot be
|
||||
reproduced by this function.
|
||||
|
||||
:Return: An ``emLen`` byte long string that encodes the hash.
|
||||
"""
|
||||
|
||||
# First, build the ASN.1 DER object DigestInfo:
|
||||
#
|
||||
# DigestInfo ::= SEQUENCE {
|
||||
# digestAlgorithm AlgorithmIdentifier,
|
||||
# digest OCTET STRING
|
||||
# }
|
||||
#
|
||||
# where digestAlgorithm identifies the hash function and shall be an
|
||||
# algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms.
|
||||
#
|
||||
# PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= {
|
||||
# { OID id-md2 PARAMETERS NULL }|
|
||||
# { OID id-md5 PARAMETERS NULL }|
|
||||
# { OID id-sha1 PARAMETERS NULL }|
|
||||
# { OID id-sha256 PARAMETERS NULL }|
|
||||
# { OID id-sha384 PARAMETERS NULL }|
|
||||
# { OID id-sha512 PARAMETERS NULL }
|
||||
# }
|
||||
#
|
||||
# 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(),
|
||||
digest.encode()
|
||||
]).encode()
|
||||
|
||||
# We need at least 11 bytes for the remaining data: 3 fixed bytes and
|
||||
# at least 8 bytes of padding).
|
||||
if emLen<len(digestInfo)+11:
|
||||
raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest))
|
||||
PS = bchr(0xFF) * (emLen - len(digestInfo) - 3)
|
||||
return b("\x00\x01") + PS + bchr(0x00) + digestInfo
|
||||
|
||||
def new(key):
|
||||
"""Return a signature scheme object `PKCS115_SigScheme` that
|
||||
can be used to perform PKCS#1 v1.5 signature or verification.
|
||||
|
||||
:Parameters:
|
||||
key : RSA key object
|
||||
The key to use to sign or verify the message. This is a `Crypto.PublicKey.RSA` object.
|
||||
Signing is only possible if *key* is a private RSA 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",
|
||||
|
||||
}
|
||||
|
31
modules/Crypto/Signature/__init__.py
Normal file
31
modules/Crypto/Signature/__init__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- 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.
|
||||
# ===================================================================
|
||||
|
||||
"""Digital signature protocols
|
||||
|
||||
A collection of standardized protocols to carry out digital signatures.
|
||||
|
||||
:undocumented: __revision__, __package__
|
||||
"""
|
||||
|
||||
__all__ = [ 'PKCS1_v1_5', 'PKCS1_PSS' ]
|
||||
__revision__ = "$Id$"
|
||||
|
||||
|
Reference in New Issue
Block a user