OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # Signature/PKCS1-v1_5.py : PKCS#1 v1.5 |
| 4 # |
| 5 # =================================================================== |
| 6 # The contents of this file are dedicated to the public domain. To |
| 7 # the extent that dedication to the public domain is not available, |
| 8 # everyone is granted a worldwide, perpetual, royalty-free, |
| 9 # non-exclusive license to exercise all rights associated with the |
| 10 # contents of this file for any purpose whatsoever. |
| 11 # No rights are reserved. |
| 12 # |
| 13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 14 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 15 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 16 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 17 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 18 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 19 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 20 # SOFTWARE. |
| 21 # =================================================================== |
| 22 |
| 23 """ |
| 24 RSA digital signature protocol according to PKCS#1 v1.5 |
| 25 |
| 26 See RFC3447__ or the `original RSA Labs specification`__. |
| 27 |
| 28 This scheme is more properly called ``RSASSA-PKCS1-v1_5``. |
| 29 |
| 30 For example, a sender may authenticate a message using SHA-1 like |
| 31 this: |
| 32 |
| 33 >>> from Crypto.Signature import PKCS1_v1_5 |
| 34 >>> from Crypto.Hash import SHA |
| 35 >>> from Crypto.PublicKey import RSA |
| 36 >>> |
| 37 >>> message = 'To be signed' |
| 38 >>> key = RSA.importKey(open('privkey.der').read()) |
| 39 >>> h = SHA.new(message) |
| 40 >>> signer = PKCS1_v1_5.new(key) |
| 41 >>> signature = signer.sign(h) |
| 42 |
| 43 At the receiver side, verification can be done using the public part of |
| 44 the RSA key: |
| 45 |
| 46 >>> key = RSA.importKey(open('pubkey.der').read()) |
| 47 >>> h = SHA.new(message) |
| 48 >>> verifier = PKCS1_v1_5.new(key) |
| 49 >>> if verifier.verify(h, signature): |
| 50 >>> print "The signature is authentic." |
| 51 >>> else: |
| 52 >>> print "The signature is not authentic." |
| 53 |
| 54 :undocumented: __revision__, __package__ |
| 55 |
| 56 .. __: http://www.ietf.org/rfc/rfc3447.txt |
| 57 .. __: http://www.rsa.com/rsalabs/node.asp?id=2125 |
| 58 """ |
| 59 |
| 60 __revision__ = "$Id$" |
| 61 __all__ = [ 'new', 'PKCS115_SigScheme' ] |
| 62 |
| 63 import Crypto.Util.number |
| 64 from Crypto.Util.number import ceil_div |
| 65 from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString |
| 66 from Crypto.Util.py3compat import * |
| 67 |
| 68 class PKCS115_SigScheme: |
| 69 """This signature scheme can perform PKCS#1 v1.5 RSA signature or verificati
on.""" |
| 70 |
| 71 def __init__(self, key): |
| 72 """Initialize this PKCS#1 v1.5 signature scheme object. |
| 73 |
| 74 :Parameters: |
| 75 key : an RSA key object |
| 76 If a private half is given, both signature and verification are possib
le. |
| 77 If a public half is given, only verification is possible. |
| 78 """ |
| 79 self._key = key |
| 80 |
| 81 def can_sign(self): |
| 82 """Return True if this cipher object can be used for signing messages.""
" |
| 83 return self._key.has_private() |
| 84 |
| 85 def sign(self, mhash): |
| 86 """Produce the PKCS#1 v1.5 signature of a message. |
| 87 |
| 88 This function is named ``RSASSA-PKCS1-V1_5-SIGN``, and is specified in |
| 89 section 8.2.1 of RFC3447. |
| 90 |
| 91 :Parameters: |
| 92 mhash : hash object |
| 93 The hash that was carried out over the message. This is an objec
t |
| 94 belonging to the `Crypto.Hash` module. |
| 95 |
| 96 :Return: The signature encoded as a string. |
| 97 :Raise ValueError: |
| 98 If the RSA key length is not sufficiently long to deal with the give
n |
| 99 hash algorithm. |
| 100 :Raise TypeError: |
| 101 If the RSA key has no private half. |
| 102 """ |
| 103 # TODO: Verify the key is RSA |
| 104 |
| 105 # See 8.2.1 in RFC3447 |
| 106 modBits = Crypto.Util.number.size(self._key.n) |
| 107 k = ceil_div(modBits,8) # Convert from bits to bytes |
| 108 |
| 109 # Step 1 |
| 110 em = EMSA_PKCS1_V1_5_ENCODE(mhash, k) |
| 111 # Step 2a (OS2IP) and 2b (RSASP1) |
| 112 m = self._key.decrypt(em) |
| 113 # Step 2c (I2OSP) |
| 114 S = bchr(0x00)*(k-len(m)) + m |
| 115 return S |
| 116 |
| 117 def verify(self, mhash, S): |
| 118 """Verify that a certain PKCS#1 v1.5 signature is authentic. |
| 119 |
| 120 This function checks if the party holding the private half of the key |
| 121 really signed the message. |
| 122 |
| 123 This function is named ``RSASSA-PKCS1-V1_5-VERIFY``, and is specified in |
| 124 section 8.2.2 of RFC3447. |
| 125 |
| 126 :Parameters: |
| 127 mhash : hash object |
| 128 The hash that was carried out over the message. This is an objec
t |
| 129 belonging to the `Crypto.Hash` module. |
| 130 S : string |
| 131 The signature that needs to be validated. |
| 132 |
| 133 :Return: True if verification is correct. False otherwise. |
| 134 """ |
| 135 # TODO: Verify the key is RSA |
| 136 |
| 137 # See 8.2.2 in RFC3447 |
| 138 modBits = Crypto.Util.number.size(self._key.n) |
| 139 k = ceil_div(modBits,8) # Convert from bits to bytes |
| 140 |
| 141 # Step 1 |
| 142 if len(S) != k: |
| 143 return 0 |
| 144 # Step 2a (O2SIP) and 2b (RSAVP1) |
| 145 # Note that signature must be smaller than the module |
| 146 # but RSA.py won't complain about it. |
| 147 # TODO: Fix RSA object; don't do it here. |
| 148 m = self._key.encrypt(S, 0)[0] |
| 149 # Step 2c (I2OSP) |
| 150 em1 = bchr(0x00)*(k-len(m)) + m |
| 151 # Step 3 |
| 152 try: |
| 153 em2 = EMSA_PKCS1_V1_5_ENCODE(mhash, k) |
| 154 except ValueError: |
| 155 return 0 |
| 156 # Step 4 |
| 157 # By comparing the full encodings (as opposed to checking each |
| 158 # of its components one at a time) we avoid attacks to the padding |
| 159 # scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptogr
aphy@metzdowd.com/msg06537). |
| 160 # |
| 161 return em1==em2 |
| 162 |
| 163 def EMSA_PKCS1_V1_5_ENCODE(hash, emLen): |
| 164 """ |
| 165 Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined |
| 166 in PKCS#1 v2.1 (RFC3447, 9.2). |
| 167 |
| 168 ``EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, |
| 169 and hash it internally. Here, we expect that the message has already |
| 170 been hashed instead. |
| 171 |
| 172 :Parameters: |
| 173 hash : hash object |
| 174 The hash object that holds the digest of the message being signed. |
| 175 emLen : int |
| 176 The length the final encoding must have, in bytes. |
| 177 |
| 178 :attention: the early standard (RFC2313) stated that ``DigestInfo`` |
| 179 had to be BER-encoded. This means that old signatures |
| 180 might have length tags in indefinite form, which |
| 181 is not supported in DER. Such encoding cannot be |
| 182 reproduced by this function. |
| 183 |
| 184 :attention: the same standard defined ``DigestAlgorithm`` to be |
| 185 of ``AlgorithmIdentifier`` type, where the PARAMETERS |
| 186 item is optional. Encodings for ``MD2/4/5`` without |
| 187 ``PARAMETERS`` cannot be reproduced by this function. |
| 188 |
| 189 :Return: An ``emLen`` byte long string that encodes the hash. |
| 190 """ |
| 191 |
| 192 # First, build the ASN.1 DER object DigestInfo: |
| 193 # |
| 194 # DigestInfo ::= SEQUENCE { |
| 195 # digestAlgorithm AlgorithmIdentifier, |
| 196 # digest OCTET STRING |
| 197 # } |
| 198 # |
| 199 # where digestAlgorithm identifies the hash function and shall be an |
| 200 # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. |
| 201 # |
| 202 # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { |
| 203 # { OID id-md2 PARAMETERS NULL }| |
| 204 # { OID id-md5 PARAMETERS NULL }| |
| 205 # { OID id-sha1 PARAMETERS NULL }| |
| 206 # { OID id-sha256 PARAMETERS NULL }| |
| 207 # { OID id-sha384 PARAMETERS NULL }| |
| 208 # { OID id-sha512 PARAMETERS NULL } |
| 209 # } |
| 210 # |
| 211 digestAlgo = DerSequence([hash.oid, DerNull().encode()]) |
| 212 digest = DerOctetString(hash.digest()) |
| 213 digestInfo = DerSequence([ |
| 214 digestAlgo.encode(), |
| 215 digest.encode() |
| 216 ]).encode() |
| 217 |
| 218 # We need at least 11 bytes for the remaining data: 3 fixed bytes and |
| 219 # at least 8 bytes of padding). |
| 220 if emLen<len(digestInfo)+11: |
| 221 raise ValueError("Selected hash algorith has a too long digest (%d bytes
)." % len(digest)) |
| 222 PS = bchr(0xFF) * (emLen - len(digestInfo) - 3) |
| 223 return b("\x00\x01") + PS + bchr(0x00) + digestInfo |
| 224 |
| 225 def new(key): |
| 226 """Return a signature scheme object `PKCS115_SigScheme` that |
| 227 can be used to perform PKCS#1 v1.5 signature or verification. |
| 228 |
| 229 :Parameters: |
| 230 key : RSA key object |
| 231 The key to use to sign or verify the message. This is a `Crypto.PublicKey.
RSA` object. |
| 232 Signing is only possible if *key* is a private RSA key. |
| 233 |
| 234 """ |
| 235 return PKCS115_SigScheme(key) |
| 236 |
OLD | NEW |