os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/dsakeypairgenimpl.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
* DSA Keypair implementation
sl@0
    16
* DSA keypair generation implementation
sl@0
    17
*
sl@0
    18
*/
sl@0
    19
sl@0
    20
sl@0
    21
/**
sl@0
    22
 @file
sl@0
    23
*/
sl@0
    24
sl@0
    25
#include "dsakeypairgenimpl.h"
sl@0
    26
#include "pluginconfig.h"
sl@0
    27
#include "keypair.h"
sl@0
    28
#include "common/inlines.h"    // For TClassSwap
sl@0
    29
#include "mont.h"
sl@0
    30
#include "sha1impl.h"
sl@0
    31
#include <random.h>
sl@0
    32
#include <securityerr.h>
sl@0
    33
sl@0
    34
sl@0
    35
const TUint KShaSize = 20;
sl@0
    36
const TUint KMinPrimeLength = 512;
sl@0
    37
const TUint KMaxPrimeLength = 1024;
sl@0
    38
const TUint KPrimeLengthMultiple = 64;
sl@0
    39
sl@0
    40
using namespace SoftwareCrypto;
sl@0
    41
sl@0
    42
sl@0
    43
/* CDSAPrimeCertificate */
sl@0
    44
sl@0
    45
CDSAPrimeCertificate* CDSAPrimeCertificate::NewL(const TDesC8& aSeed, TUint aCounter)
sl@0
    46
	{
sl@0
    47
	CDSAPrimeCertificate* self = NewLC(aSeed, aCounter);
sl@0
    48
	CleanupStack::Pop();
sl@0
    49
	return self;
sl@0
    50
	}
sl@0
    51
sl@0
    52
CDSAPrimeCertificate* CDSAPrimeCertificate::NewLC(const TDesC8& aSeed, TUint aCounter)
sl@0
    53
	{
sl@0
    54
	CDSAPrimeCertificate* self = new(ELeave) CDSAPrimeCertificate(aCounter);
sl@0
    55
	CleanupStack::PushL(self);
sl@0
    56
	self->ConstructL(aSeed);
sl@0
    57
	return self;
sl@0
    58
	}
sl@0
    59
sl@0
    60
const TDesC8& CDSAPrimeCertificate::Seed() const
sl@0
    61
	{
sl@0
    62
	return *iSeed;
sl@0
    63
	}
sl@0
    64
sl@0
    65
TUint CDSAPrimeCertificate::Counter() const
sl@0
    66
	{
sl@0
    67
	return iCounter;
sl@0
    68
	}
sl@0
    69
sl@0
    70
CDSAPrimeCertificate::~CDSAPrimeCertificate() 
sl@0
    71
	{
sl@0
    72
	delete const_cast<HBufC8*>(iSeed);
sl@0
    73
	}
sl@0
    74
sl@0
    75
void CDSAPrimeCertificate::ConstructL(const TDesC8& aSeed)
sl@0
    76
	{
sl@0
    77
	iSeed = aSeed.AllocL();
sl@0
    78
	}
sl@0
    79
sl@0
    80
CDSAPrimeCertificate::CDSAPrimeCertificate(TUint aCounter) 
sl@0
    81
	: iCounter(aCounter)
sl@0
    82
	{
sl@0
    83
	}
sl@0
    84
sl@0
    85
CDSAPrimeCertificate::CDSAPrimeCertificate() 
sl@0
    86
	{
sl@0
    87
	}
sl@0
    88
sl@0
    89
sl@0
    90
/* CDSAKeyPairGenImpl */
sl@0
    91
CDSAKeyPairGenImpl::CDSAKeyPairGenImpl()
sl@0
    92
	{
sl@0
    93
	}
sl@0
    94
sl@0
    95
CDSAKeyPairGenImpl::~CDSAKeyPairGenImpl()
sl@0
    96
	{
sl@0
    97
	delete iPrimeCertificate;
sl@0
    98
	}
sl@0
    99
sl@0
   100
CDSAKeyPairGenImpl* CDSAKeyPairGenImpl::NewL()
sl@0
   101
	{
sl@0
   102
	CDSAKeyPairGenImpl* self = CDSAKeyPairGenImpl::NewLC();
sl@0
   103
	CleanupStack::Pop(self);
sl@0
   104
	return self;
sl@0
   105
	}
sl@0
   106
sl@0
   107
CDSAKeyPairGenImpl* CDSAKeyPairGenImpl::NewLC()
sl@0
   108
	{
sl@0
   109
	CDSAKeyPairGenImpl* self = new(ELeave) CDSAKeyPairGenImpl();
sl@0
   110
	CleanupStack::PushL(self);
sl@0
   111
	self->ConstructL();
sl@0
   112
	return self;
sl@0
   113
	}
sl@0
   114
sl@0
   115
void CDSAKeyPairGenImpl::ConstructL(void)
sl@0
   116
	{
sl@0
   117
	CKeyPairGenImpl::ConstructL();
sl@0
   118
	}
sl@0
   119
sl@0
   120
CExtendedCharacteristics* CDSAKeyPairGenImpl::CreateExtendedCharacteristicsL()
sl@0
   121
	{
sl@0
   122
	// All Symbian software plug-ins have unlimited concurrency, cannot be reserved
sl@0
   123
	// for exclusive use and are not CERTIFIED to be standards compliant.
sl@0
   124
	return CExtendedCharacteristics::NewL(KMaxTInt, EFalse);
sl@0
   125
	}
sl@0
   126
sl@0
   127
const CExtendedCharacteristics* CDSAKeyPairGenImpl::GetExtendedCharacteristicsL()
sl@0
   128
	{
sl@0
   129
	return CDSAKeyPairGenImpl::CreateExtendedCharacteristicsL();
sl@0
   130
	}
sl@0
   131
sl@0
   132
TUid CDSAKeyPairGenImpl::ImplementationUid() const
sl@0
   133
	{
sl@0
   134
	return KCryptoPluginDsaKeyPairGenUid;
sl@0
   135
	}
sl@0
   136
sl@0
   137
void CDSAKeyPairGenImpl::Reset()
sl@0
   138
	{
sl@0
   139
	// does nothing in this plugin
sl@0
   140
	}
sl@0
   141
sl@0
   142
TBool CDSAKeyPairGenImpl::ValidPrimeLength(TUint aPrimeBits)
sl@0
   143
	{
sl@0
   144
	return (aPrimeBits >= KMinPrimeLength &&
sl@0
   145
			aPrimeBits <= KMaxPrimeLength &&
sl@0
   146
			aPrimeBits % KPrimeLengthMultiple == 0);
sl@0
   147
	}
sl@0
   148
sl@0
   149
TBool CDSAKeyPairGenImpl::GeneratePrimesL(const TDesC8& aSeed,
sl@0
   150
										 TUint& aCounter, 
sl@0
   151
										 RInteger& aP, 
sl@0
   152
										 TUint aL, 
sl@0
   153
										 RInteger& aQ, 
sl@0
   154
										 TBool aUseInputCounter)
sl@0
   155
	{
sl@0
   156
	//This follows the steps in FIPS 186-2 
sl@0
   157
	//See DSS Appendix 2.2
sl@0
   158
	//Note. Step 1 is performed prior to calling GeneratePrimesL, so that this
sl@0
   159
	//routine can be used for both generation and validation.
sl@0
   160
	//Step 1.  Choose an arbitrary sequence of at least 160 bits and call it
sl@0
   161
	//SEED.  Let g be the length of SEED in bits.
sl@0
   162
sl@0
   163
	if(!ValidPrimeLength(aL))
sl@0
   164
		{
sl@0
   165
		User::Leave(KErrNotSupported);
sl@0
   166
		}
sl@0
   167
	
sl@0
   168
	CSHA1Impl* sha1 = CSHA1Impl::NewL();
sl@0
   169
	CleanupStack::PushL(sha1);
sl@0
   170
sl@0
   171
	HBufC8* seedBuf = aSeed.AllocLC();
sl@0
   172
	TPtr8 seed = seedBuf->Des();
sl@0
   173
	TUint gBytes = aSeed.Size();
sl@0
   174
	
sl@0
   175
	//Note that the DSS's g = BytesToBits(gBytes) ie. the number of random bits
sl@0
   176
	//in the seed.  
sl@0
   177
	//This function has made the assumption (for ease of computation) that g%8
sl@0
   178
	//is 0.  Ie the seed is a whole number of random bytes.
sl@0
   179
	TBuf8<KShaSize> U; 
sl@0
   180
	TBuf8<KShaSize> temp; 
sl@0
   181
	const TUint n = (aL-1)/160;
sl@0
   182
	const TUint b = (aL-1)%160;
sl@0
   183
	HBufC8* Wbuf = HBufC8::NewMaxLC((n+1) * KShaSize);
sl@0
   184
	TUint8* W = const_cast<TUint8*>(Wbuf->Ptr());
sl@0
   185
sl@0
   186
	U.Copy(sha1->Final(seed));
sl@0
   187
	
sl@0
   188
	//Step 2. U = SHA-1[SEED] XOR SHA-1[(SEED+1) mod 2^g]
sl@0
   189
	for(TInt i=gBytes - 1, carry=ETrue; i>=0 && carry; i--)
sl@0
   190
		{
sl@0
   191
		//!++(TUint) adds one to the current word which if it overflows to zero
sl@0
   192
		//sets carry to 1 thus letting the loop continue.  It's a poor man's
sl@0
   193
		//multi-word addition.  Swift eh?
sl@0
   194
		carry = !++(seed[i]);
sl@0
   195
		}
sl@0
   196
sl@0
   197
	temp.Copy(sha1->Final(seed));
sl@0
   198
	XorBuf(const_cast<TUint8*>(U.Ptr()), temp.Ptr(), KShaSize);
sl@0
   199
sl@0
   200
	//Step 3. Form q from U by setting the most significant bit (2^159)
sl@0
   201
	//and the least significant bit to 1.
sl@0
   202
	U[0] |= 0x80;
sl@0
   203
	U[KShaSize-1] |= 1;
sl@0
   204
sl@0
   205
	aQ = RInteger::NewL(U);
sl@0
   206
	CleanupStack::PushL(aQ);
sl@0
   207
sl@0
   208
	//Step 4. Use a robust primality testing algo to test if q is prime
sl@0
   209
	//The robust part is the calling codes problem.  This will use whatever
sl@0
   210
	//random number generator you set for the thread.  To attempt FIPS 186-2
sl@0
   211
	//compliance, set a FIPS 186-2 compliant RNG.
sl@0
   212
	if( !aQ.IsPrimeL() )
sl@0
   213
		{
sl@0
   214
		//Step 5. If not exit and get a new seed
sl@0
   215
		CleanupStack::PopAndDestroy(4, sha1);
sl@0
   216
		return EFalse;
sl@0
   217
		}
sl@0
   218
	
sl@0
   219
	TUint counterEnd = aUseInputCounter ? aCounter+1 : 4096;
sl@0
   220
	
sl@0
   221
	//Step 6. Let counter = 0 and offset = 2
sl@0
   222
	//Note 1. that the DSS speaks of SEED + offset + k because they always
sl@0
   223
	//refer to a constant SEED.  We update our seed as we go so the offset
sl@0
   224
	//variable has already been added to seed in the previous iterations.
sl@0
   225
	//Note 2. We've already added 1 to our seed, so the first time through this
sl@0
   226
	//the offset in DSS speak will be 2.
sl@0
   227
	for(TUint counter=0; counter < counterEnd; counter++)
sl@0
   228
		{
sl@0
   229
		//Step 7. For k=0, ..., n let
sl@0
   230
		// Vk = SHA-1[(SEED + offset + k) mod 2^g]
sl@0
   231
		//I'm storing the Vk's inside of a big W buffer.
sl@0
   232
		for(TUint k=0; k<=n; k++)
sl@0
   233
			{
sl@0
   234
			for(TInt i=gBytes-1, carry=ETrue; i>=0 && carry; i--)
sl@0
   235
				{
sl@0
   236
				carry = !++(seed[i]);
sl@0
   237
				}
sl@0
   238
			if(!aUseInputCounter || counter == aCounter)
sl@0
   239
				{
sl@0
   240
				TPtr8 Wptr(W+(n-k)*KShaSize, gBytes);
sl@0
   241
				Wptr.Copy(sha1->Final(seed));
sl@0
   242
				}
sl@0
   243
			}
sl@0
   244
		if(!aUseInputCounter || counter == aCounter)
sl@0
   245
			{
sl@0
   246
			//Step 8. Let W be the integer...  and let X = W + 2^(L-1)
sl@0
   247
			const_cast<TUint8&>((*Wbuf)[KShaSize - 1 - b/8]) |= 0x80;
sl@0
   248
			TPtr8 Wptr(W + KShaSize - 1 - b/8, aL/8, aL/8);
sl@0
   249
			RInteger X = RInteger::NewL(Wptr);
sl@0
   250
			CleanupStack::PushL(X);
sl@0
   251
			//Step 9. Let c = X mod 2q and set p = X - (c-1)
sl@0
   252
			RInteger twoQ = aQ.TimesL(TInteger::Two());
sl@0
   253
			CleanupStack::PushL(twoQ);
sl@0
   254
			RInteger c = X.ModuloL(twoQ);
sl@0
   255
			CleanupStack::PushL(c);
sl@0
   256
			--c;
sl@0
   257
			aP = X.MinusL(c);
sl@0
   258
			CleanupStack::PopAndDestroy(3, &X); //twoQ, c, X
sl@0
   259
			CleanupStack::PushL(aP);
sl@0
   260
			
sl@0
   261
			//Step 10 and 11: if p >= 2^(L-1) and p is prime
sl@0
   262
			if( aP.Bit(aL-1) && aP.IsPrimeL() )
sl@0
   263
				{
sl@0
   264
				aCounter = counter;
sl@0
   265
				CleanupStack::Pop(2, &aQ);
sl@0
   266
				CleanupStack::PopAndDestroy(3, sha1);
sl@0
   267
				return ETrue;
sl@0
   268
				}
sl@0
   269
			CleanupStack::PopAndDestroy(&aP);
sl@0
   270
			}
sl@0
   271
		}
sl@0
   272
	CleanupStack::PopAndDestroy(4, &sha1);
sl@0
   273
	return EFalse;
sl@0
   274
	}
sl@0
   275
sl@0
   276
void CDSAKeyPairGenImpl::GenerateKeyPairL(TInt aKeySize, 
sl@0
   277
										const CCryptoParams& aKeyParameters,
sl@0
   278
										CKeyPair*& aKeyPair)
sl@0
   279
	{
sl@0
   280
	//This is the first step of DSA prime generation.  The remaining steps are
sl@0
   281
	//performed in CDSAParameters::GeneratePrimesL
sl@0
   282
	//Step 1.  Choose an arbitrary sequence of at least 160 bits and call it
sl@0
   283
	//SEED.  Let g be the length of SEED in bits.	
sl@0
   284
	TBuf8<KShaSize> seed(KShaSize);
sl@0
   285
	TUint c;
sl@0
   286
	RInteger p;
sl@0
   287
	RInteger q;
sl@0
   288
	
sl@0
   289
	do 
sl@0
   290
		{
sl@0
   291
	    TRAPD(err, GenerateRandomBytesL(seed));
sl@0
   292
	    if((err != KErrNone) && (err != KErrNotSecure))
sl@0
   293
	        User::Leave(err);
sl@0
   294
		}
sl@0
   295
	while(!GeneratePrimesL(seed, c, p, aKeySize, q));
sl@0
   296
	
sl@0
   297
	//Double PushL will not fail as GeneratePrimesL uses the CleanupStack
sl@0
   298
	//(at least one push and pop ;)
sl@0
   299
	CleanupStack::PushL(p);
sl@0
   300
	CleanupStack::PushL(q);
sl@0
   301
sl@0
   302
	iPrimeCertificate = CDSAPrimeCertificate::NewL(seed, c);
sl@0
   303
	
sl@0
   304
	// aKeyParameters isn't const here anymore
sl@0
   305
	CCryptoParams& paramRef=const_cast<CCryptoParams&>(aKeyParameters);
sl@0
   306
	paramRef.AddL(c, KDsaKeyGenerationCounterUid);
sl@0
   307
	paramRef.AddL(seed, KDsaKeyGenerationSeedUid);
sl@0
   308
	
sl@0
   309
	CMontgomeryStructure* montP = CMontgomeryStructure::NewLC(p);
sl@0
   310
	
sl@0
   311
	--p;
sl@0
   312
sl@0
   313
	// e = (p-1)/q
sl@0
   314
	RInteger e = p.DividedByL(q);
sl@0
   315
	CleanupStack::PushL(e);
sl@0
   316
sl@0
   317
	--p; //now it's p-2 :)
sl@0
   318
sl@0
   319
	RInteger h;
sl@0
   320
	const TInteger* g = 0;
sl@0
   321
	do
sl@0
   322
		{
sl@0
   323
		// find a random h | 1 < h < p-1
sl@0
   324
		h = RInteger::NewRandomL(TInteger::Two(), p);
sl@0
   325
		CleanupStack::PushL(h);
sl@0
   326
		// g = h^e mod p
sl@0
   327
		g = &(montP->ExponentiateL(h, e));
sl@0
   328
		CleanupStack::PopAndDestroy(&h); 
sl@0
   329
		}
sl@0
   330
	while( *g <= TInteger::One() );
sl@0
   331
	CleanupStack::PopAndDestroy(&e);
sl@0
   332
sl@0
   333
	++p; //reincrement p to original value
sl@0
   334
	++p;
sl@0
   335
sl@0
   336
sl@0
   337
	RInteger g1 = RInteger::NewL(*g); //take a copy of montP's g
sl@0
   338
	CleanupStack::PushL(g1);
sl@0
   339
	--q;
sl@0
   340
	// select random x | 0 < x < q
sl@0
   341
	RInteger x = RInteger::NewRandomL(TInteger::One(), q);
sl@0
   342
	CleanupStack::PushL(x);
sl@0
   343
	++q;
sl@0
   344
sl@0
   345
	//
sl@0
   346
	// create the keys parameters
sl@0
   347
	CCryptoParams* privateKeyParameters = CCryptoParams::NewLC();
sl@0
   348
	privateKeyParameters->AddL(p, KDsaKeyParameterPUid);
sl@0
   349
	privateKeyParameters->AddL(q, KDsaKeyParameterQUid);
sl@0
   350
	privateKeyParameters->AddL(g1, KDsaKeyParameterGUid);
sl@0
   351
	privateKeyParameters->AddL(x, KDsaKeyParameterXUid);
sl@0
   352
	TKeyProperty privateKeyProperties = {KDSAKeyPairGeneratorUid, 
sl@0
   353
										 KCryptoPluginDsaKeyPairGenUid,
sl@0
   354
									     KDsaPrivateKeyUid, 
sl@0
   355
									     KNonEmbeddedKeyUid};
sl@0
   356
sl@0
   357
	CCryptoParams* publicKeyParameters = CCryptoParams::NewLC();
sl@0
   358
	publicKeyParameters->AddL(p, KDsaKeyParameterPUid);
sl@0
   359
	publicKeyParameters->AddL(q, KDsaKeyParameterQUid);
sl@0
   360
	publicKeyParameters->AddL(g1, KDsaKeyParameterGUid);
sl@0
   361
	RInteger y = RInteger::NewL(montP->ExponentiateL(*g, x));
sl@0
   362
	CleanupStack::PushL(y);
sl@0
   363
	publicKeyParameters->AddL(y, KDsaKeyParameterYUid);
sl@0
   364
	TKeyProperty publicKeyProperties = {KDSAKeyPairGeneratorUid,
sl@0
   365
										KCryptoPluginDsaKeyPairGenUid, 
sl@0
   366
										KDsaPublicKeyUid,
sl@0
   367
										KNonEmbeddedKeyUid};
sl@0
   368
sl@0
   369
	//
sl@0
   370
	// create the private key
sl@0
   371
	//
sl@0
   372
	CKey* privateKey = CKey::NewL(privateKeyProperties, *privateKeyParameters);
sl@0
   373
	CleanupStack::PushL(privateKey);
sl@0
   374
sl@0
   375
	//
sl@0
   376
	// create the public key
sl@0
   377
	//
sl@0
   378
	CKey* publicKey = CKey::NewL(publicKeyProperties, *publicKeyParameters);
sl@0
   379
	CleanupStack::PushL(publicKey);
sl@0
   380
sl@0
   381
	aKeyPair = CKeyPair::NewL(publicKey, privateKey);
sl@0
   382
sl@0
   383
	//publicKey, publicKeyParameters, y, privateKey, privateKeyParameters, x, g1, montP, q, p
sl@0
   384
	CleanupStack::Pop(2, privateKey);
sl@0
   385
	CleanupStack::PopAndDestroy(8, &p);	
sl@0
   386
	}