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