Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Side by Side Diff: third_party/google-endpoints/Crypto/Signature/PKCS1_PSS.py

Issue 2666783008: Add google-endpoints to third_party/. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2 #
3 # Signature/PKCS1_PSS.py : PKCS#1 PPS
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 digital signature protocol with appendix according to PKCS#1 PSS.
24
25 See RFC3447__ or the `original RSA Labs specification`__.
26
27 This scheme is more properly called ``RSASSA-PSS``.
28
29 For example, a sender may authenticate a message using SHA-1 and PSS like
30 this:
31
32 >>> from Crypto.Signature import PKCS1_PSS
33 >>> from Crypto.Hash import SHA
34 >>> from Crypto.PublicKey import RSA
35 >>> from Crypto import Random
36 >>>
37 >>> message = 'To be signed'
38 >>> key = RSA.importKey(open('privkey.der').read())
39 >>> h = SHA.new()
40 >>> h.update(message)
41 >>> signer = PKCS1_PSS.new(key)
42 >>> signature = PKCS1_PSS.sign(key)
43
44 At the receiver side, verification can be done like using the public part of
45 the RSA key:
46
47 >>> key = RSA.importKey(open('pubkey.der').read())
48 >>> h = SHA.new()
49 >>> h.update(message)
50 >>> verifier = PKCS1_PSS.new(key)
51 >>> if verifier.verify(h, signature):
52 >>> print "The signature is authentic."
53 >>> else:
54 >>> print "The signature is not authentic."
55
56 :undocumented: __revision__, __package__
57
58 .. __: http://www.ietf.org/rfc/rfc3447.txt
59 .. __: http://www.rsa.com/rsalabs/node.asp?id=2125
60 """
61
62 # Allow nested scopes in Python 2.1
63 # See http://oreilly.com/pub/a/python/2001/04/19/pythonnews.html
64 from __future__ import nested_scopes
65
66 __revision__ = "$Id$"
67 __all__ = [ 'new', 'PSS_SigScheme' ]
68
69 from Crypto.Util.py3compat import *
70 if sys.version_info[0] == 2 and sys.version_info[1] == 1:
71 from Crypto.Util.py21compat import *
72 import Crypto.Util.number
73 from Crypto.Util.number import ceil_shift, ceil_div, long_to_bytes
74 from Crypto.Util.strxor import strxor
75
76 class PSS_SigScheme:
77 """This signature scheme can perform PKCS#1 PSS RSA signature or verificatio n."""
78
79 def __init__(self, key, mgfunc, saltLen):
80 """Initialize this PKCS#1 PSS signature scheme object.
81
82 :Parameters:
83 key : an RSA key object
84 If a private half is given, both signature and verification are possible.
85 If a public half is given, only verification is possible.
86 mgfunc : callable
87 A mask generation function that accepts two parameters: a string to
88 use as seed, and the lenth of the mask to generate, in bytes.
89 saltLen : int
90 Length of the salt, in bytes.
91 """
92 self._key = key
93 self._saltLen = saltLen
94 self._mgfunc = mgfunc
95
96 def can_sign(self):
97 """Return True if this cipher object can be used for signing messages."" "
98 return self._key.has_private()
99
100 def sign(self, mhash):
101 """Produce the PKCS#1 PSS signature of a message.
102
103 This function is named ``RSASSA-PSS-SIGN``, and is specified in
104 section 8.1.1 of RFC3447.
105
106 :Parameters:
107 mhash : hash object
108 The hash that was carried out over the message. This is an objec t
109 belonging to the `Crypto.Hash` module.
110
111 :Return: The PSS signature encoded as a string.
112 :Raise ValueError:
113 If the RSA key length is not sufficiently long to deal with the give n
114 hash algorithm.
115 :Raise TypeError:
116 If the RSA key has no private half.
117
118 :attention: Modify the salt length and the mask generation function only
119 if you know what you are doing.
120 The receiver must use the same parameters too.
121 """
122 # TODO: Verify the key is RSA
123
124 randfunc = self._key._randfunc
125
126 # Set defaults for salt length and mask generation function
127 if self._saltLen == None:
128 sLen = mhash.digest_size
129 else:
130 sLen = self._saltLen
131 if self._mgfunc:
132 mgf = self._mgfunc
133 else:
134 mgf = lambda x,y: MGF1(x,y,mhash)
135
136 modBits = Crypto.Util.number.size(self._key.n)
137
138 # See 8.1.1 in RFC3447
139 k = ceil_div(modBits,8) # Convert from bits to bytes
140 # Step 1
141 em = EMSA_PSS_ENCODE(mhash, modBits-1, randfunc, mgf, sLen)
142 # Step 2a (OS2IP) and 2b (RSASP1)
143 m = self._key.decrypt(em)
144 # Step 2c (I2OSP)
145 S = bchr(0x00)*(k-len(m)) + m
146 return S
147
148 def verify(self, mhash, S):
149 """Verify that a certain PKCS#1 PSS signature is authentic.
150
151 This function checks if the party holding the private half of the given
152 RSA key has really signed the message.
153
154 This function is called ``RSASSA-PSS-VERIFY``, and is specified in secti on
155 8.1.2 of RFC3447.
156
157 :Parameters:
158 mhash : hash object
159 The hash that was carried out over the message. This is an objec t
160 belonging to the `Crypto.Hash` module.
161 S : string
162 The signature that needs to be validated.
163
164 :Return: True if verification is correct. False otherwise.
165 """
166 # TODO: Verify the key is RSA
167
168 # Set defaults for salt length and mask generation function
169 if self._saltLen == None:
170 sLen = mhash.digest_size
171 else:
172 sLen = self._saltLen
173 if self._mgfunc:
174 mgf = self._mgfunc
175 else:
176 mgf = lambda x,y: MGF1(x,y,mhash)
177
178 modBits = Crypto.Util.number.size(self._key.n)
179
180 # See 8.1.2 in RFC3447
181 k = ceil_div(modBits,8) # Convert from bits to bytes
182 # Step 1
183 if len(S) != k:
184 return False
185 # Step 2a (O2SIP), 2b (RSAVP1), and partially 2c (I2OSP)
186 # Note that signature must be smaller than the module
187 # but RSA.py won't complain about it.
188 # TODO: Fix RSA object; don't do it here.
189 em = self._key.encrypt(S, 0)[0]
190 # Step 2c
191 emLen = ceil_div(modBits-1,8)
192 em = bchr(0x00)*(emLen-len(em)) + em
193 # Step 3
194 try:
195 result = EMSA_PSS_VERIFY(mhash, em, modBits-1, mgf, sLen)
196 except ValueError:
197 return False
198 # Step 4
199 return result
200
201 def MGF1(mgfSeed, maskLen, hash):
202 """Mask Generation Function, described in B.2.1"""
203 T = b("")
204 for counter in xrange(ceil_div(maskLen, hash.digest_size)):
205 c = long_to_bytes(counter, 4)
206 T = T + hash.new(mgfSeed + c).digest()
207 assert(len(T)>=maskLen)
208 return T[:maskLen]
209
210 def EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen):
211 """
212 Implement the ``EMSA-PSS-ENCODE`` function, as defined
213 in PKCS#1 v2.1 (RFC3447, 9.1.1).
214
215 The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` as input ,
216 and hash it internally. Here, we expect that the message has already
217 been hashed instead.
218
219 :Parameters:
220 mhash : hash object
221 The hash object that holds the digest of the message being signed.
222 emBits : int
223 Maximum length of the final encoding, in bits.
224 randFunc : callable
225 An RNG function that accepts as only parameter an int, and returns
226 a string of random bytes, to be used as salt.
227 mgf : callable
228 A mask generation function that accepts two parameters: a string to
229 use as seed, and the lenth of the mask to generate, in bytes.
230 sLen : int
231 Length of the salt, in bytes.
232
233 :Return: An ``emLen`` byte long string that encodes the hash
234 (with ``emLen = \ceil(emBits/8)``).
235
236 :Raise ValueError:
237 When digest or salt length are too big.
238 """
239
240 emLen = ceil_div(emBits,8)
241
242 # Bitmask of digits that fill up
243 lmask = 0
244 for i in xrange(8*emLen-emBits):
245 lmask = lmask>>1 | 0x80
246
247 # Step 1 and 2 have been already done
248 # Step 3
249 if emLen < mhash.digest_size+sLen+2:
250 raise ValueError("Digest or salt length are too long for given key size. ")
251 # Step 4
252 salt = b("")
253 if randFunc and sLen>0:
254 salt = randFunc(sLen)
255 # Step 5 and 6
256 h = mhash.new(bchr(0x00)*8 + mhash.digest() + salt)
257 # Step 7 and 8
258 db = bchr(0x00)*(emLen-sLen-mhash.digest_size-2) + bchr(0x01) + salt
259 # Step 9
260 dbMask = mgf(h.digest(), emLen-mhash.digest_size-1)
261 # Step 10
262 maskedDB = strxor(db,dbMask)
263 # Step 11
264 maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:]
265 # Step 12
266 em = maskedDB + h.digest() + bchr(0xBC)
267 return em
268
269 def EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen):
270 """
271 Implement the ``EMSA-PSS-VERIFY`` function, as defined
272 in PKCS#1 v2.1 (RFC3447, 9.1.2).
273
274 ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input,
275 and hash it internally. Here, we expect that the message has already
276 been hashed instead.
277
278 :Parameters:
279 mhash : hash object
280 The hash object that holds the digest of the message to be verified.
281 em : string
282 The signature to verify, therefore proving that the sender really si gned
283 the message that was received.
284 emBits : int
285 Length of the final encoding (em), in bits.
286 mgf : callable
287 A mask generation function that accepts two parameters: a string to
288 use as seed, and the lenth of the mask to generate, in bytes.
289 sLen : int
290 Length of the salt, in bytes.
291
292 :Return: 0 if the encoding is consistent, 1 if it is inconsistent.
293
294 :Raise ValueError:
295 When digest or salt length are too big.
296 """
297
298 emLen = ceil_div(emBits,8)
299
300 # Bitmask of digits that fill up
301 lmask = 0
302 for i in xrange(8*emLen-emBits):
303 lmask = lmask>>1 | 0x80
304
305 # Step 1 and 2 have been already done
306 # Step 3
307 if emLen < mhash.digest_size+sLen+2:
308 return False
309 # Step 4
310 if ord(em[-1:])!=0xBC:
311 return False
312 # Step 5
313 maskedDB = em[:emLen-mhash.digest_size-1]
314 h = em[emLen-mhash.digest_size-1:-1]
315 # Step 6
316 if lmask & bord(em[0]):
317 return False
318 # Step 7
319 dbMask = mgf(h, emLen-mhash.digest_size-1)
320 # Step 8
321 db = strxor(maskedDB, dbMask)
322 # Step 9
323 db = bchr(bord(db[0]) & ~lmask) + db[1:]
324 # Step 10
325 if not db.startswith(bchr(0x00)*(emLen-mhash.digest_size-sLen-2) + bchr(0x01 )):
326 return False
327 # Step 11
328 salt = b("")
329 if sLen: salt = db[-sLen:]
330 # Step 12 and 13
331 hp = mhash.new(bchr(0x00)*8 + mhash.digest() + salt).digest()
332 # Step 14
333 if h!=hp:
334 return False
335 return True
336
337 def new(key, mgfunc=None, saltLen=None):
338 """Return a signature scheme object `PSS_SigScheme` that
339 can be used to perform PKCS#1 PSS signature or verification.
340
341 :Parameters:
342 key : RSA key object
343 The key to use to sign or verify the message. This is a `Crypto.PublicKe y.RSA` object.
344 Signing is only possible if *key* is a private RSA key.
345 mgfunc : callable
346 A mask generation function that accepts two parameters: a string to
347 use as seed, and the lenth of the mask to generate, in bytes.
348 If not specified, the standard MGF1 is used.
349 saltLen : int
350 Length of the salt, in bytes. If not specified, it matches the output
351 size of the hash function.
352
353 """
354 return PSS_SigScheme(key, mgfunc, saltLen)
355
OLDNEW
« no previous file with comments | « third_party/google-endpoints/Crypto/SelfTest/st_common.py ('k') | third_party/google-endpoints/Crypto/Signature/PKCS1_v1_5.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698