|
1 /* |
|
2 * Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <asymmetrickeys.h> |
|
20 #include <bigint.h> |
|
21 #include <random.h> |
|
22 #include <hash.h> |
|
23 #include "../common/inlines.h" |
|
24 #include "../bigint/mont.h" |
|
25 #include "dsakeypairshim.h" |
|
26 |
|
27 const TUint SHASIZE = 20; |
|
28 const TUint KMinPrimeLength = 512; |
|
29 const TUint KMaxPrimeLength = 1024; |
|
30 const TUint KPrimeLengthMultiple = 64; |
|
31 |
|
32 /* CDSAParameters */ |
|
33 |
|
34 EXPORT_C const TInteger& CDSAParameters::P(void) const |
|
35 { |
|
36 return iP; |
|
37 } |
|
38 |
|
39 EXPORT_C const TInteger& CDSAParameters::Q(void) const |
|
40 { |
|
41 return iQ; |
|
42 } |
|
43 |
|
44 EXPORT_C const TInteger& CDSAParameters::G(void) const |
|
45 { |
|
46 return iG; |
|
47 } |
|
48 |
|
49 EXPORT_C CDSAParameters::~CDSAParameters(void) |
|
50 { |
|
51 iP.Close(); |
|
52 iQ.Close(); |
|
53 iG.Close(); |
|
54 } |
|
55 |
|
56 EXPORT_C CDSAParameters* CDSAParameters::NewL(RInteger& aP, RInteger& aQ, |
|
57 RInteger& aG) |
|
58 { |
|
59 CDSAParameters* me = new (ELeave) CDSAParameters(aP, aQ, aG); |
|
60 return (me); |
|
61 } |
|
62 |
|
63 EXPORT_C TBool CDSAParameters::ValidatePrimesL(const CDSAPrimeCertificate& aCert) |
|
64 const |
|
65 { |
|
66 TBool result = EFalse; |
|
67 RInteger p; |
|
68 RInteger q; |
|
69 //Regenerate primes using aCert's seed and counter |
|
70 TUint counter = aCert.Counter(); |
|
71 if(!CDSAParameters::GeneratePrimesL(aCert.Seed(), counter, p, |
|
72 P().BitCount(), q, ETrue)) |
|
73 { |
|
74 return result; |
|
75 } |
|
76 //this doesn't leave, no need to push p and q |
|
77 if(p == P() && q == Q() && counter == aCert.Counter()) |
|
78 { |
|
79 result = ETrue; |
|
80 } |
|
81 p.Close(); |
|
82 q.Close(); |
|
83 return result; |
|
84 } |
|
85 |
|
86 EXPORT_C TBool CDSAParameters::ValidPrimeLength(TUint aPrimeBits) |
|
87 { |
|
88 return (aPrimeBits >= KMinPrimeLength && |
|
89 aPrimeBits <= KMaxPrimeLength && |
|
90 aPrimeBits % KPrimeLengthMultiple == 0); |
|
91 } |
|
92 |
|
93 EXPORT_C CDSAParameters::CDSAParameters(RInteger& aP, RInteger& aQ, |
|
94 RInteger& aG) : iP(aP), iQ(aQ), iG(aG) |
|
95 { |
|
96 } |
|
97 |
|
98 EXPORT_C CDSAParameters::CDSAParameters(void) |
|
99 { |
|
100 } |
|
101 |
|
102 TBool CDSAParameters::GeneratePrimesL(const TDesC8& aSeed, TUint& aCounter, |
|
103 RInteger& aP, TUint aL, RInteger& aQ, TBool aUseInputCounter) |
|
104 { |
|
105 //This follows the steps in FIPS 186-2 |
|
106 //See DSS Appendix 2.2 |
|
107 //Note. Step 1 is performed prior to calling GeneratePrimesL, so that this |
|
108 //routine can be used for both generation and validation. |
|
109 //Step 1. Choose an arbitrary sequence of at least 160 bits and call it |
|
110 //SEED. Let g be the length of SEED in bits. |
|
111 |
|
112 if(!CDSAParameters::ValidPrimeLength(aL)) |
|
113 { |
|
114 User::Leave(KErrNotSupported); |
|
115 } |
|
116 |
|
117 CSHA1* sha1 = CSHA1::NewL(); |
|
118 CleanupStack::PushL(sha1); |
|
119 |
|
120 HBufC8* seedBuf = aSeed.AllocLC(); |
|
121 TPtr8 seed = seedBuf->Des(); |
|
122 TUint gBytes = aSeed.Size(); |
|
123 //Note that the DSS's g = BytesToBits(gBytes) ie. the number of random bits |
|
124 //in the seed. |
|
125 //This function has made the assumption (for ease of computation) that g%8 |
|
126 //is 0. Ie the seed is a whole number of random bytes. |
|
127 TBuf8<SHASIZE> U; |
|
128 TBuf8<SHASIZE> temp; |
|
129 const TUint n = (aL-1)/160; |
|
130 const TUint b = (aL-1)%160; |
|
131 HBufC8* Wbuf = HBufC8::NewMaxLC((n+1) * SHASIZE); |
|
132 TUint8* W = const_cast<TUint8*>(Wbuf->Ptr()); |
|
133 |
|
134 U.Copy(sha1->Final(seed)); |
|
135 |
|
136 //Step 2. U = SHA-1[SEED] XOR SHA-1[(SEED+1) mod 2^g] |
|
137 for(TInt i=gBytes - 1, carry=ETrue; i>=0 && carry; i--) |
|
138 { |
|
139 //!++(TUint) adds one to the current word which if it overflows to zero |
|
140 //sets carry to 1 thus letting the loop continue. It's a poor man's |
|
141 //multi-word addition. Swift eh? |
|
142 carry = !++(seed[i]); |
|
143 } |
|
144 |
|
145 temp.Copy(sha1->Final(seed)); |
|
146 XorBuf(const_cast<TUint8*>(U.Ptr()), temp.Ptr(), SHASIZE); |
|
147 |
|
148 //Step 3. Form q from U by setting the most significant bit (2^159) |
|
149 //and the least significant bit to 1. |
|
150 U[0] |= 0x80; |
|
151 U[SHASIZE-1] |= 1; |
|
152 |
|
153 aQ = RInteger::NewL(U); |
|
154 CleanupStack::PushL(aQ); |
|
155 |
|
156 //Step 4. Use a robust primality testing algo to test if q is prime |
|
157 //The robust part is the calling codes problem. This will use whatever |
|
158 //random number generator you set for the thread. To attempt FIPS 186-2 |
|
159 //compliance, set a FIPS 186-2 compliant RNG. |
|
160 if( !aQ.IsPrimeL() ) |
|
161 { |
|
162 //Step 5. If not exit and get a new seed |
|
163 CleanupStack::PopAndDestroy(&aQ); |
|
164 CleanupStack::PopAndDestroy(Wbuf); |
|
165 CleanupStack::PopAndDestroy(seedBuf); |
|
166 CleanupStack::PopAndDestroy(sha1); |
|
167 return EFalse; |
|
168 } |
|
169 |
|
170 TUint counterEnd = aUseInputCounter ? aCounter+1 : 4096; |
|
171 |
|
172 //Step 6. Let counter = 0 and offset = 2 |
|
173 //Note 1. that the DSS speaks of SEED + offset + k because they always |
|
174 //refer to a constant SEED. We update our seed as we go so the offset |
|
175 //variable has already been added to seed in the previous iterations. |
|
176 //Note 2. We've already added 1 to our seed, so the first time through this |
|
177 //the offset in DSS speak will be 2. |
|
178 for(TUint counter=0; counter < counterEnd; counter++) |
|
179 { |
|
180 //Step 7. For k=0, ..., n let |
|
181 // Vk = SHA-1[(SEED + offset + k) mod 2^g] |
|
182 //I'm storing the Vk's inside of a big W buffer. |
|
183 for(TUint k=0; k<=n; k++) |
|
184 { |
|
185 for(TInt i=gBytes-1, carry=ETrue; i>=0 && carry; i--) |
|
186 { |
|
187 carry = !++(seed[i]); |
|
188 } |
|
189 if(!aUseInputCounter || counter == aCounter) |
|
190 { |
|
191 TPtr8 Wptr(W+(n-k)*SHASIZE, gBytes); |
|
192 Wptr.Copy(sha1->Final(seed)); |
|
193 } |
|
194 } |
|
195 if(!aUseInputCounter || counter == aCounter) |
|
196 { |
|
197 //Step 8. Let W be the integer... and let X = W + 2^(L-1) |
|
198 const_cast<TUint8&>((*Wbuf)[SHASIZE - 1 - b/8]) |= 0x80; |
|
199 TPtr8 Wptr(W + SHASIZE - 1 - b/8, aL/8, aL/8); |
|
200 RInteger X = RInteger::NewL(Wptr); |
|
201 CleanupStack::PushL(X); |
|
202 //Step 9. Let c = X mod 2q and set p = X - (c-1) |
|
203 RInteger twoQ = aQ.TimesL(TInteger::Two()); |
|
204 CleanupStack::PushL(twoQ); |
|
205 RInteger c = X.ModuloL(twoQ); |
|
206 CleanupStack::PushL(c); |
|
207 --c; |
|
208 aP = X.MinusL(c); |
|
209 CleanupStack::PopAndDestroy(3, &X); //twoQ, c, X |
|
210 CleanupStack::PushL(aP); |
|
211 |
|
212 //Step 10 and 11: if p >= 2^(L-1) and p is prime |
|
213 if( aP.Bit(aL-1) && aP.IsPrimeL() ) |
|
214 { |
|
215 aCounter = counter; |
|
216 CleanupStack::Pop(&aP); |
|
217 CleanupStack::Pop(&aQ); |
|
218 CleanupStack::PopAndDestroy(Wbuf); |
|
219 CleanupStack::PopAndDestroy(seedBuf); |
|
220 CleanupStack::PopAndDestroy(sha1); |
|
221 return ETrue; |
|
222 } |
|
223 CleanupStack::PopAndDestroy(&aP); |
|
224 } |
|
225 } |
|
226 CleanupStack::PopAndDestroy(&aQ); |
|
227 CleanupStack::PopAndDestroy(Wbuf); |
|
228 CleanupStack::PopAndDestroy(seedBuf); |
|
229 CleanupStack::PopAndDestroy(sha1); |
|
230 return EFalse; |
|
231 } |
|
232 |
|
233 /* CDSAPublicKey */ |
|
234 |
|
235 EXPORT_C CDSAPublicKey* CDSAPublicKey::NewL(RInteger& aP, RInteger& aQ, |
|
236 RInteger& aG, RInteger& aY) |
|
237 { |
|
238 CDSAPublicKey* self = new(ELeave) CDSAPublicKey(aP, aQ, aG, aY); |
|
239 return self; |
|
240 } |
|
241 |
|
242 EXPORT_C CDSAPublicKey* CDSAPublicKey::NewLC(RInteger& aP, RInteger& aQ, |
|
243 RInteger& aG, RInteger& aY) |
|
244 { |
|
245 CDSAPublicKey* self = NewL(aP, aQ, aG, aY); |
|
246 CleanupStack::PushL(self); |
|
247 return self; |
|
248 } |
|
249 |
|
250 EXPORT_C const TInteger& CDSAPublicKey::Y(void) const |
|
251 { |
|
252 return iY; |
|
253 } |
|
254 |
|
255 EXPORT_C CDSAPublicKey::CDSAPublicKey(void) |
|
256 { |
|
257 } |
|
258 |
|
259 EXPORT_C CDSAPublicKey::CDSAPublicKey(RInteger& aP, RInteger& aQ, RInteger& aG, |
|
260 RInteger& aY) : CDSAParameters(aP, aQ, aG), iY(aY) |
|
261 { |
|
262 } |
|
263 |
|
264 EXPORT_C CDSAPublicKey::~CDSAPublicKey(void) |
|
265 { |
|
266 iY.Close(); |
|
267 } |
|
268 |
|
269 /* CDSAPrivateKey */ |
|
270 |
|
271 EXPORT_C CDSAPrivateKey* CDSAPrivateKey::NewL(RInteger& aP, RInteger& aQ, |
|
272 RInteger& aG, RInteger& aX) |
|
273 { |
|
274 CDSAPrivateKey* self = new(ELeave) CDSAPrivateKey(aP, aQ, aG, aX); |
|
275 return self; |
|
276 } |
|
277 |
|
278 EXPORT_C CDSAPrivateKey* CDSAPrivateKey::NewLC(RInteger& aP, RInteger& aQ, |
|
279 RInteger& aG, RInteger& aX) |
|
280 { |
|
281 CDSAPrivateKey* self = NewL(aP, aQ, aG, aX); |
|
282 CleanupStack::PushL(self); |
|
283 return self; |
|
284 } |
|
285 |
|
286 EXPORT_C const TInteger& CDSAPrivateKey::X(void) const |
|
287 { |
|
288 return iX; |
|
289 } |
|
290 |
|
291 EXPORT_C CDSAPrivateKey::CDSAPrivateKey(RInteger& aP, RInteger& aQ, RInteger& aG, |
|
292 RInteger& aX) : CDSAParameters(aP, aQ, aG), iX(aX) |
|
293 { |
|
294 } |
|
295 |
|
296 EXPORT_C CDSAPrivateKey::~CDSAPrivateKey(void) |
|
297 { |
|
298 iX.Close(); |
|
299 } |
|
300 |
|
301 /* CDSAKeyPair */ |
|
302 |
|
303 EXPORT_C CDSAKeyPair* CDSAKeyPair::NewL(TUint aKeyBits) |
|
304 { |
|
305 CDSAKeyPairShim* self = CDSAKeyPairShim::NewLC(aKeyBits); |
|
306 CleanupStack::Pop(); |
|
307 return self; |
|
308 } |
|
309 |
|
310 EXPORT_C CDSAKeyPair* CDSAKeyPair::NewLC(TUint aKeyBits) |
|
311 { |
|
312 CDSAKeyPairShim* self = CDSAKeyPairShim::NewLC(aKeyBits); |
|
313 return self; |
|
314 } |
|
315 |
|
316 EXPORT_C const CDSAPublicKey& CDSAKeyPair::PublicKey(void) const |
|
317 { |
|
318 return *iPublic; |
|
319 } |
|
320 |
|
321 EXPORT_C const CDSAPrivateKey& CDSAKeyPair::PrivateKey(void) const |
|
322 { |
|
323 return *iPrivate; |
|
324 } |
|
325 |
|
326 EXPORT_C CDSAKeyPair::~CDSAKeyPair(void) |
|
327 { |
|
328 delete iPublic; |
|
329 delete iPrivate; |
|
330 delete iPrimeCertificate; |
|
331 } |
|
332 |
|
333 EXPORT_C CDSAKeyPair::CDSAKeyPair(void) |
|
334 { |
|
335 } |
|
336 |
|
337 EXPORT_C const CDSAPrimeCertificate& CDSAKeyPair::PrimeCertificate(void) const |
|
338 { |
|
339 return *iPrimeCertificate; |
|
340 } |
|
341 |
|
342 /* CDSAPrimeCertificate */ |
|
343 |
|
344 EXPORT_C CDSAPrimeCertificate* CDSAPrimeCertificate::NewL(const TDesC8& aSeed, |
|
345 TUint aCounter) |
|
346 { |
|
347 CDSAPrimeCertificate* self = NewLC(aSeed, aCounter); |
|
348 CleanupStack::Pop(); |
|
349 return self; |
|
350 } |
|
351 |
|
352 EXPORT_C CDSAPrimeCertificate* CDSAPrimeCertificate::NewLC(const TDesC8& aSeed, |
|
353 TUint aCounter) |
|
354 { |
|
355 CDSAPrimeCertificate* self = new(ELeave) CDSAPrimeCertificate(aCounter); |
|
356 CleanupStack::PushL(self); |
|
357 self->ConstructL(aSeed); |
|
358 return self; |
|
359 } |
|
360 |
|
361 EXPORT_C const TDesC8& CDSAPrimeCertificate::Seed(void) const |
|
362 { |
|
363 return *iSeed; |
|
364 } |
|
365 |
|
366 EXPORT_C TUint CDSAPrimeCertificate::Counter(void) const |
|
367 { |
|
368 return iCounter; |
|
369 } |
|
370 |
|
371 EXPORT_C CDSAPrimeCertificate::~CDSAPrimeCertificate(void) |
|
372 { |
|
373 delete const_cast<HBufC8*>(iSeed); |
|
374 } |
|
375 |
|
376 void CDSAPrimeCertificate::ConstructL(const TDesC8& aSeed) |
|
377 { |
|
378 iSeed = aSeed.AllocL(); |
|
379 } |
|
380 |
|
381 EXPORT_C CDSAPrimeCertificate::CDSAPrimeCertificate(TUint aCounter) |
|
382 : iCounter(aCounter) |
|
383 { |
|
384 } |
|
385 |
|
386 // Over taken by shim version. so, exclude it from coverage. |
|
387 #ifdef _BullseyeCoverage |
|
388 #pragma suppress_warnings on |
|
389 #pragma BullseyeCoverage off |
|
390 #pragma suppress_warnings off |
|
391 #endif |
|
392 void CDSAKeyPair::ConstructL(TUint /*aPBits*/) |
|
393 { |
|
394 } |
|
395 |
|
396 // Unused exported and protected method can be excluded from coverage. |
|
397 EXPORT_C CDSAPrimeCertificate::CDSAPrimeCertificate(void) |
|
398 { |
|
399 } |
|
400 |
|
401 EXPORT_C CDSAPrivateKey::CDSAPrivateKey(void) |
|
402 { |
|
403 } |