OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # |
| 3 # Cipher/PKCS1_OAEP.py : PKCS#1 OAEP |
| 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 """RSA encryption protocol according to PKCS#1 OAEP |
| 24 |
| 25 See RFC3447__ or the `original RSA Labs specification`__ . |
| 26 |
| 27 This scheme is more properly called ``RSAES-OAEP``. |
| 28 |
| 29 As an example, a sender may encrypt a message in this way: |
| 30 |
| 31 >>> from Crypto.Cipher import PKCS1_OAEP |
| 32 >>> from Crypto.PublicKey import RSA |
| 33 >>> |
| 34 >>> message = 'To be encrypted' |
| 35 >>> key = RSA.importKey(open('pubkey.der').read()) |
| 36 >>> cipher = PKCS1_OAEP.new(key) |
| 37 >>> ciphertext = cipher.encrypt(message) |
| 38 |
| 39 At the receiver side, decryption can be done using the private part of |
| 40 the RSA key: |
| 41 |
| 42 >>> key = RSA.importKey(open('privkey.der').read()) |
| 43 >>> cipher = PKCS1_OAP.new(key) |
| 44 >>> message = cipher.decrypt(ciphertext) |
| 45 |
| 46 :undocumented: __revision__, __package__ |
| 47 |
| 48 .. __: http://www.ietf.org/rfc/rfc3447.txt |
| 49 .. __: http://www.rsa.com/rsalabs/node.asp?id=2125. |
| 50 """ |
| 51 |
| 52 from __future__ import nested_scopes |
| 53 |
| 54 __revision__ = "$Id$" |
| 55 __all__ = [ 'new', 'PKCS1OAEP_Cipher' ] |
| 56 |
| 57 import Crypto.Signature.PKCS1_PSS |
| 58 import Crypto.Hash.SHA |
| 59 |
| 60 from Crypto.Util.py3compat import * |
| 61 import Crypto.Util.number |
| 62 from Crypto.Util.number import ceil_div |
| 63 from Crypto.Util.strxor import strxor |
| 64 |
| 65 class PKCS1OAEP_Cipher: |
| 66 """This cipher can perform PKCS#1 v1.5 OAEP encryption or decryption.""" |
| 67 |
| 68 def __init__(self, key, hashAlgo, mgfunc, label): |
| 69 """Initialize this PKCS#1 OAEP cipher object. |
| 70 |
| 71 :Parameters: |
| 72 key : an RSA key object |
| 73 If a private half is given, both encryption and decryption are possibl
e. |
| 74 If a public half is given, only encryption is possible. |
| 75 hashAlgo : hash object |
| 76 The hash function to use. This can be a module under `Crypto.Has
h` |
| 77 or an existing hash object created from any of such modules. If
not specified, |
| 78 `Crypto.Hash.SHA` (that is, SHA-1) is used. |
| 79 mgfunc : callable |
| 80 A mask generation function that accepts two parameters: a string
to |
| 81 use as seed, and the lenth of the mask to generate, in bytes. |
| 82 If not specified, the standard MGF1 is used (a safe choice). |
| 83 label : string |
| 84 A label to apply to this particular encryption. If not specified
, |
| 85 an empty string is used. Specifying a label does not improve |
| 86 security. |
| 87 |
| 88 :attention: Modify the mask generation function only if you know what yo
u are doing. |
| 89 Sender and receiver must use the same one. |
| 90 """ |
| 91 self._key = key |
| 92 |
| 93 if hashAlgo: |
| 94 self._hashObj = hashAlgo |
| 95 else: |
| 96 self._hashObj = Crypto.Hash.SHA |
| 97 |
| 98 if mgfunc: |
| 99 self._mgf = mgfunc |
| 100 else: |
| 101 self._mgf = lambda x,y: Crypto.Signature.PKCS1_PSS.MGF1(x,y,self._ha
shObj) |
| 102 |
| 103 self._label = label |
| 104 |
| 105 def can_encrypt(self): |
| 106 """Return True/1 if this cipher object can be used for encryption.""" |
| 107 return self._key.can_encrypt() |
| 108 |
| 109 def can_decrypt(self): |
| 110 """Return True/1 if this cipher object can be used for decryption.""" |
| 111 return self._key.can_decrypt() |
| 112 |
| 113 def encrypt(self, message): |
| 114 """Produce the PKCS#1 OAEP encryption of a message. |
| 115 |
| 116 This function is named ``RSAES-OAEP-ENCRYPT``, and is specified in |
| 117 section 7.1.1 of RFC3447. |
| 118 |
| 119 :Parameters: |
| 120 message : string |
| 121 The message to encrypt, also known as plaintext. It can be of |
| 122 variable length, but not longer than the RSA modulus (in bytes) |
| 123 minus 2, minus twice the hash output size. |
| 124 |
| 125 :Return: A string, the ciphertext in which the message is encrypted. |
| 126 It is as long as the RSA modulus (in bytes). |
| 127 :Raise ValueError: |
| 128 If the RSA key length is not sufficiently long to deal with the give
n |
| 129 message. |
| 130 """ |
| 131 # TODO: Verify the key is RSA |
| 132 |
| 133 randFunc = self._key._randfunc |
| 134 |
| 135 # See 7.1.1 in RFC3447 |
| 136 modBits = Crypto.Util.number.size(self._key.n) |
| 137 k = ceil_div(modBits,8) # Convert from bits to bytes |
| 138 hLen = self._hashObj.digest_size |
| 139 mLen = len(message) |
| 140 |
| 141 # Step 1b |
| 142 ps_len = k-mLen-2*hLen-2 |
| 143 if ps_len<0: |
| 144 raise ValueError("Plaintext is too long.") |
| 145 # Step 2a |
| 146 lHash = self._hashObj.new(self._label).digest() |
| 147 # Step 2b |
| 148 ps = bchr(0x00)*ps_len |
| 149 # Step 2c |
| 150 db = lHash + ps + bchr(0x01) + message |
| 151 # Step 2d |
| 152 ros = randFunc(hLen) |
| 153 # Step 2e |
| 154 dbMask = self._mgf(ros, k-hLen-1) |
| 155 # Step 2f |
| 156 maskedDB = strxor(db, dbMask) |
| 157 # Step 2g |
| 158 seedMask = self._mgf(maskedDB, hLen) |
| 159 # Step 2h |
| 160 maskedSeed = strxor(ros, seedMask) |
| 161 # Step 2i |
| 162 em = bchr(0x00) + maskedSeed + maskedDB |
| 163 # Step 3a (OS2IP), step 3b (RSAEP), part of step 3c (I2OSP) |
| 164 m = self._key.encrypt(em, 0)[0] |
| 165 # Complete step 3c (I2OSP) |
| 166 c = bchr(0x00)*(k-len(m)) + m |
| 167 return c |
| 168 |
| 169 def decrypt(self, ct): |
| 170 """Decrypt a PKCS#1 OAEP ciphertext. |
| 171 |
| 172 This function is named ``RSAES-OAEP-DECRYPT``, and is specified in |
| 173 section 7.1.2 of RFC3447. |
| 174 |
| 175 :Parameters: |
| 176 ct : string |
| 177 The ciphertext that contains the message to recover. |
| 178 |
| 179 :Return: A string, the original message. |
| 180 :Raise ValueError: |
| 181 If the ciphertext length is incorrect, or if the decryption does not |
| 182 succeed. |
| 183 :Raise TypeError: |
| 184 If the RSA key has no private half. |
| 185 """ |
| 186 # TODO: Verify the key is RSA |
| 187 |
| 188 # See 7.1.2 in RFC3447 |
| 189 modBits = Crypto.Util.number.size(self._key.n) |
| 190 k = ceil_div(modBits,8) # Convert from bits to bytes |
| 191 hLen = self._hashObj.digest_size |
| 192 |
| 193 # Step 1b and 1c |
| 194 if len(ct) != k or k<hLen+2: |
| 195 raise ValueError("Ciphertext with incorrect length.") |
| 196 # Step 2a (O2SIP), 2b (RSADP), and part of 2c (I2OSP) |
| 197 m = self._key.decrypt(ct) |
| 198 # Complete step 2c (I2OSP) |
| 199 em = bchr(0x00)*(k-len(m)) + m |
| 200 # Step 3a |
| 201 lHash = self._hashObj.new(self._label).digest() |
| 202 # Step 3b |
| 203 y = em[0] |
| 204 # y must be 0, but we MUST NOT check it here in order not to |
| 205 # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) |
| 206 maskedSeed = em[1:hLen+1] |
| 207 maskedDB = em[hLen+1:] |
| 208 # Step 3c |
| 209 seedMask = self._mgf(maskedDB, hLen) |
| 210 # Step 3d |
| 211 seed = strxor(maskedSeed, seedMask) |
| 212 # Step 3e |
| 213 dbMask = self._mgf(seed, k-hLen-1) |
| 214 # Step 3f |
| 215 db = strxor(maskedDB, dbMask) |
| 216 # Step 3g |
| 217 valid = 1 |
| 218 one = db[hLen:].find(bchr(0x01)) |
| 219 lHash1 = db[:hLen] |
| 220 if lHash1!=lHash: |
| 221 valid = 0 |
| 222 if one<0: |
| 223 valid = 0 |
| 224 if bord(y)!=0: |
| 225 valid = 0 |
| 226 if not valid: |
| 227 raise ValueError("Incorrect decryption.") |
| 228 # Step 4 |
| 229 return db[hLen+one+1:] |
| 230 |
| 231 def new(key, hashAlgo=None, mgfunc=None, label=b('')): |
| 232 """Return a cipher object `PKCS1OAEP_Cipher` that can be used to perform PKC
S#1 OAEP encryption or decryption. |
| 233 |
| 234 :Parameters: |
| 235 key : RSA key object |
| 236 The key to use to encrypt or decrypt the message. This is a `Crypto.Public
Key.RSA` object. |
| 237 Decryption is only possible if *key* is a private RSA key. |
| 238 hashAlgo : hash object |
| 239 The hash function to use. This can be a module under `Crypto.Hash` |
| 240 or an existing hash object created from any of such modules. If not specif
ied, |
| 241 `Crypto.Hash.SHA` (that is, SHA-1) is used. |
| 242 mgfunc : callable |
| 243 A mask generation function that accepts two parameters: a string to |
| 244 use as seed, and the lenth of the mask to generate, in bytes. |
| 245 If not specified, the standard MGF1 is used (a safe choice). |
| 246 label : string |
| 247 A label to apply to this particular encryption. If not specified, |
| 248 an empty string is used. Specifying a label does not improve |
| 249 security. |
| 250 |
| 251 :attention: Modify the mask generation function only if you know what you ar
e doing. |
| 252 Sender and receiver must use the same one. |
| 253 """ |
| 254 return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label) |
| 255 |
OLD | NEW |