os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/dsakeypairgenimpl.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/dsakeypairgenimpl.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,386 @@
     1.4 +/*
     1.5 +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +* All rights reserved.
     1.7 +* This component and the accompanying materials are made available
     1.8 +* under the terms of the License "Eclipse Public License v1.0"
     1.9 +* which accompanies this distribution, and is available
    1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +*
    1.12 +* Initial Contributors:
    1.13 +* Nokia Corporation - initial contribution.
    1.14 +*
    1.15 +* Contributors:
    1.16 +*
    1.17 +* Description: 
    1.18 +* DSA Keypair implementation
    1.19 +* DSA keypair generation implementation
    1.20 +*
    1.21 +*/
    1.22 +
    1.23 +
    1.24 +/**
    1.25 + @file
    1.26 +*/
    1.27 +
    1.28 +#include "dsakeypairgenimpl.h"
    1.29 +#include "pluginconfig.h"
    1.30 +#include "keypair.h"
    1.31 +#include "common/inlines.h"    // For TClassSwap
    1.32 +#include "mont.h"
    1.33 +#include "sha1impl.h"
    1.34 +#include <random.h>
    1.35 +#include <securityerr.h>
    1.36 +
    1.37 +
    1.38 +const TUint KShaSize = 20;
    1.39 +const TUint KMinPrimeLength = 512;
    1.40 +const TUint KMaxPrimeLength = 1024;
    1.41 +const TUint KPrimeLengthMultiple = 64;
    1.42 +
    1.43 +using namespace SoftwareCrypto;
    1.44 +
    1.45 +
    1.46 +/* CDSAPrimeCertificate */
    1.47 +
    1.48 +CDSAPrimeCertificate* CDSAPrimeCertificate::NewL(const TDesC8& aSeed, TUint aCounter)
    1.49 +	{
    1.50 +	CDSAPrimeCertificate* self = NewLC(aSeed, aCounter);
    1.51 +	CleanupStack::Pop();
    1.52 +	return self;
    1.53 +	}
    1.54 +
    1.55 +CDSAPrimeCertificate* CDSAPrimeCertificate::NewLC(const TDesC8& aSeed, TUint aCounter)
    1.56 +	{
    1.57 +	CDSAPrimeCertificate* self = new(ELeave) CDSAPrimeCertificate(aCounter);
    1.58 +	CleanupStack::PushL(self);
    1.59 +	self->ConstructL(aSeed);
    1.60 +	return self;
    1.61 +	}
    1.62 +
    1.63 +const TDesC8& CDSAPrimeCertificate::Seed() const
    1.64 +	{
    1.65 +	return *iSeed;
    1.66 +	}
    1.67 +
    1.68 +TUint CDSAPrimeCertificate::Counter() const
    1.69 +	{
    1.70 +	return iCounter;
    1.71 +	}
    1.72 +
    1.73 +CDSAPrimeCertificate::~CDSAPrimeCertificate() 
    1.74 +	{
    1.75 +	delete const_cast<HBufC8*>(iSeed);
    1.76 +	}
    1.77 +
    1.78 +void CDSAPrimeCertificate::ConstructL(const TDesC8& aSeed)
    1.79 +	{
    1.80 +	iSeed = aSeed.AllocL();
    1.81 +	}
    1.82 +
    1.83 +CDSAPrimeCertificate::CDSAPrimeCertificate(TUint aCounter) 
    1.84 +	: iCounter(aCounter)
    1.85 +	{
    1.86 +	}
    1.87 +
    1.88 +CDSAPrimeCertificate::CDSAPrimeCertificate() 
    1.89 +	{
    1.90 +	}
    1.91 +
    1.92 +
    1.93 +/* CDSAKeyPairGenImpl */
    1.94 +CDSAKeyPairGenImpl::CDSAKeyPairGenImpl()
    1.95 +	{
    1.96 +	}
    1.97 +
    1.98 +CDSAKeyPairGenImpl::~CDSAKeyPairGenImpl()
    1.99 +	{
   1.100 +	delete iPrimeCertificate;
   1.101 +	}
   1.102 +
   1.103 +CDSAKeyPairGenImpl* CDSAKeyPairGenImpl::NewL()
   1.104 +	{
   1.105 +	CDSAKeyPairGenImpl* self = CDSAKeyPairGenImpl::NewLC();
   1.106 +	CleanupStack::Pop(self);
   1.107 +	return self;
   1.108 +	}
   1.109 +
   1.110 +CDSAKeyPairGenImpl* CDSAKeyPairGenImpl::NewLC()
   1.111 +	{
   1.112 +	CDSAKeyPairGenImpl* self = new(ELeave) CDSAKeyPairGenImpl();
   1.113 +	CleanupStack::PushL(self);
   1.114 +	self->ConstructL();
   1.115 +	return self;
   1.116 +	}
   1.117 +
   1.118 +void CDSAKeyPairGenImpl::ConstructL(void)
   1.119 +	{
   1.120 +	CKeyPairGenImpl::ConstructL();
   1.121 +	}
   1.122 +
   1.123 +CExtendedCharacteristics* CDSAKeyPairGenImpl::CreateExtendedCharacteristicsL()
   1.124 +	{
   1.125 +	// All Symbian software plug-ins have unlimited concurrency, cannot be reserved
   1.126 +	// for exclusive use and are not CERTIFIED to be standards compliant.
   1.127 +	return CExtendedCharacteristics::NewL(KMaxTInt, EFalse);
   1.128 +	}
   1.129 +
   1.130 +const CExtendedCharacteristics* CDSAKeyPairGenImpl::GetExtendedCharacteristicsL()
   1.131 +	{
   1.132 +	return CDSAKeyPairGenImpl::CreateExtendedCharacteristicsL();
   1.133 +	}
   1.134 +
   1.135 +TUid CDSAKeyPairGenImpl::ImplementationUid() const
   1.136 +	{
   1.137 +	return KCryptoPluginDsaKeyPairGenUid;
   1.138 +	}
   1.139 +
   1.140 +void CDSAKeyPairGenImpl::Reset()
   1.141 +	{
   1.142 +	// does nothing in this plugin
   1.143 +	}
   1.144 +
   1.145 +TBool CDSAKeyPairGenImpl::ValidPrimeLength(TUint aPrimeBits)
   1.146 +	{
   1.147 +	return (aPrimeBits >= KMinPrimeLength &&
   1.148 +			aPrimeBits <= KMaxPrimeLength &&
   1.149 +			aPrimeBits % KPrimeLengthMultiple == 0);
   1.150 +	}
   1.151 +
   1.152 +TBool CDSAKeyPairGenImpl::GeneratePrimesL(const TDesC8& aSeed,
   1.153 +										 TUint& aCounter, 
   1.154 +										 RInteger& aP, 
   1.155 +										 TUint aL, 
   1.156 +										 RInteger& aQ, 
   1.157 +										 TBool aUseInputCounter)
   1.158 +	{
   1.159 +	//This follows the steps in FIPS 186-2 
   1.160 +	//See DSS Appendix 2.2
   1.161 +	//Note. Step 1 is performed prior to calling GeneratePrimesL, so that this
   1.162 +	//routine can be used for both generation and validation.
   1.163 +	//Step 1.  Choose an arbitrary sequence of at least 160 bits and call it
   1.164 +	//SEED.  Let g be the length of SEED in bits.
   1.165 +
   1.166 +	if(!ValidPrimeLength(aL))
   1.167 +		{
   1.168 +		User::Leave(KErrNotSupported);
   1.169 +		}
   1.170 +	
   1.171 +	CSHA1Impl* sha1 = CSHA1Impl::NewL();
   1.172 +	CleanupStack::PushL(sha1);
   1.173 +
   1.174 +	HBufC8* seedBuf = aSeed.AllocLC();
   1.175 +	TPtr8 seed = seedBuf->Des();
   1.176 +	TUint gBytes = aSeed.Size();
   1.177 +	
   1.178 +	//Note that the DSS's g = BytesToBits(gBytes) ie. the number of random bits
   1.179 +	//in the seed.  
   1.180 +	//This function has made the assumption (for ease of computation) that g%8
   1.181 +	//is 0.  Ie the seed is a whole number of random bytes.
   1.182 +	TBuf8<KShaSize> U; 
   1.183 +	TBuf8<KShaSize> temp; 
   1.184 +	const TUint n = (aL-1)/160;
   1.185 +	const TUint b = (aL-1)%160;
   1.186 +	HBufC8* Wbuf = HBufC8::NewMaxLC((n+1) * KShaSize);
   1.187 +	TUint8* W = const_cast<TUint8*>(Wbuf->Ptr());
   1.188 +
   1.189 +	U.Copy(sha1->Final(seed));
   1.190 +	
   1.191 +	//Step 2. U = SHA-1[SEED] XOR SHA-1[(SEED+1) mod 2^g]
   1.192 +	for(TInt i=gBytes - 1, carry=ETrue; i>=0 && carry; i--)
   1.193 +		{
   1.194 +		//!++(TUint) adds one to the current word which if it overflows to zero
   1.195 +		//sets carry to 1 thus letting the loop continue.  It's a poor man's
   1.196 +		//multi-word addition.  Swift eh?
   1.197 +		carry = !++(seed[i]);
   1.198 +		}
   1.199 +
   1.200 +	temp.Copy(sha1->Final(seed));
   1.201 +	XorBuf(const_cast<TUint8*>(U.Ptr()), temp.Ptr(), KShaSize);
   1.202 +
   1.203 +	//Step 3. Form q from U by setting the most significant bit (2^159)
   1.204 +	//and the least significant bit to 1.
   1.205 +	U[0] |= 0x80;
   1.206 +	U[KShaSize-1] |= 1;
   1.207 +
   1.208 +	aQ = RInteger::NewL(U);
   1.209 +	CleanupStack::PushL(aQ);
   1.210 +
   1.211 +	//Step 4. Use a robust primality testing algo to test if q is prime
   1.212 +	//The robust part is the calling codes problem.  This will use whatever
   1.213 +	//random number generator you set for the thread.  To attempt FIPS 186-2
   1.214 +	//compliance, set a FIPS 186-2 compliant RNG.
   1.215 +	if( !aQ.IsPrimeL() )
   1.216 +		{
   1.217 +		//Step 5. If not exit and get a new seed
   1.218 +		CleanupStack::PopAndDestroy(4, sha1);
   1.219 +		return EFalse;
   1.220 +		}
   1.221 +	
   1.222 +	TUint counterEnd = aUseInputCounter ? aCounter+1 : 4096;
   1.223 +	
   1.224 +	//Step 6. Let counter = 0 and offset = 2
   1.225 +	//Note 1. that the DSS speaks of SEED + offset + k because they always
   1.226 +	//refer to a constant SEED.  We update our seed as we go so the offset
   1.227 +	//variable has already been added to seed in the previous iterations.
   1.228 +	//Note 2. We've already added 1 to our seed, so the first time through this
   1.229 +	//the offset in DSS speak will be 2.
   1.230 +	for(TUint counter=0; counter < counterEnd; counter++)
   1.231 +		{
   1.232 +		//Step 7. For k=0, ..., n let
   1.233 +		// Vk = SHA-1[(SEED + offset + k) mod 2^g]
   1.234 +		//I'm storing the Vk's inside of a big W buffer.
   1.235 +		for(TUint k=0; k<=n; k++)
   1.236 +			{
   1.237 +			for(TInt i=gBytes-1, carry=ETrue; i>=0 && carry; i--)
   1.238 +				{
   1.239 +				carry = !++(seed[i]);
   1.240 +				}
   1.241 +			if(!aUseInputCounter || counter == aCounter)
   1.242 +				{
   1.243 +				TPtr8 Wptr(W+(n-k)*KShaSize, gBytes);
   1.244 +				Wptr.Copy(sha1->Final(seed));
   1.245 +				}
   1.246 +			}
   1.247 +		if(!aUseInputCounter || counter == aCounter)
   1.248 +			{
   1.249 +			//Step 8. Let W be the integer...  and let X = W + 2^(L-1)
   1.250 +			const_cast<TUint8&>((*Wbuf)[KShaSize - 1 - b/8]) |= 0x80;
   1.251 +			TPtr8 Wptr(W + KShaSize - 1 - b/8, aL/8, aL/8);
   1.252 +			RInteger X = RInteger::NewL(Wptr);
   1.253 +			CleanupStack::PushL(X);
   1.254 +			//Step 9. Let c = X mod 2q and set p = X - (c-1)
   1.255 +			RInteger twoQ = aQ.TimesL(TInteger::Two());
   1.256 +			CleanupStack::PushL(twoQ);
   1.257 +			RInteger c = X.ModuloL(twoQ);
   1.258 +			CleanupStack::PushL(c);
   1.259 +			--c;
   1.260 +			aP = X.MinusL(c);
   1.261 +			CleanupStack::PopAndDestroy(3, &X); //twoQ, c, X
   1.262 +			CleanupStack::PushL(aP);
   1.263 +			
   1.264 +			//Step 10 and 11: if p >= 2^(L-1) and p is prime
   1.265 +			if( aP.Bit(aL-1) && aP.IsPrimeL() )
   1.266 +				{
   1.267 +				aCounter = counter;
   1.268 +				CleanupStack::Pop(2, &aQ);
   1.269 +				CleanupStack::PopAndDestroy(3, sha1);
   1.270 +				return ETrue;
   1.271 +				}
   1.272 +			CleanupStack::PopAndDestroy(&aP);
   1.273 +			}
   1.274 +		}
   1.275 +	CleanupStack::PopAndDestroy(4, &sha1);
   1.276 +	return EFalse;
   1.277 +	}
   1.278 +
   1.279 +void CDSAKeyPairGenImpl::GenerateKeyPairL(TInt aKeySize, 
   1.280 +										const CCryptoParams& aKeyParameters,
   1.281 +										CKeyPair*& aKeyPair)
   1.282 +	{
   1.283 +	//This is the first step of DSA prime generation.  The remaining steps are
   1.284 +	//performed in CDSAParameters::GeneratePrimesL
   1.285 +	//Step 1.  Choose an arbitrary sequence of at least 160 bits and call it
   1.286 +	//SEED.  Let g be the length of SEED in bits.	
   1.287 +	TBuf8<KShaSize> seed(KShaSize);
   1.288 +	TUint c;
   1.289 +	RInteger p;
   1.290 +	RInteger q;
   1.291 +	
   1.292 +	do 
   1.293 +		{
   1.294 +	    TRAPD(err, GenerateRandomBytesL(seed));
   1.295 +	    if((err != KErrNone) && (err != KErrNotSecure))
   1.296 +	        User::Leave(err);
   1.297 +		}
   1.298 +	while(!GeneratePrimesL(seed, c, p, aKeySize, q));
   1.299 +	
   1.300 +	//Double PushL will not fail as GeneratePrimesL uses the CleanupStack
   1.301 +	//(at least one push and pop ;)
   1.302 +	CleanupStack::PushL(p);
   1.303 +	CleanupStack::PushL(q);
   1.304 +
   1.305 +	iPrimeCertificate = CDSAPrimeCertificate::NewL(seed, c);
   1.306 +	
   1.307 +	// aKeyParameters isn't const here anymore
   1.308 +	CCryptoParams& paramRef=const_cast<CCryptoParams&>(aKeyParameters);
   1.309 +	paramRef.AddL(c, KDsaKeyGenerationCounterUid);
   1.310 +	paramRef.AddL(seed, KDsaKeyGenerationSeedUid);
   1.311 +	
   1.312 +	CMontgomeryStructure* montP = CMontgomeryStructure::NewLC(p);
   1.313 +	
   1.314 +	--p;
   1.315 +
   1.316 +	// e = (p-1)/q
   1.317 +	RInteger e = p.DividedByL(q);
   1.318 +	CleanupStack::PushL(e);
   1.319 +
   1.320 +	--p; //now it's p-2 :)
   1.321 +
   1.322 +	RInteger h;
   1.323 +	const TInteger* g = 0;
   1.324 +	do
   1.325 +		{
   1.326 +		// find a random h | 1 < h < p-1
   1.327 +		h = RInteger::NewRandomL(TInteger::Two(), p);
   1.328 +		CleanupStack::PushL(h);
   1.329 +		// g = h^e mod p
   1.330 +		g = &(montP->ExponentiateL(h, e));
   1.331 +		CleanupStack::PopAndDestroy(&h); 
   1.332 +		}
   1.333 +	while( *g <= TInteger::One() );
   1.334 +	CleanupStack::PopAndDestroy(&e);
   1.335 +
   1.336 +	++p; //reincrement p to original value
   1.337 +	++p;
   1.338 +
   1.339 +
   1.340 +	RInteger g1 = RInteger::NewL(*g); //take a copy of montP's g
   1.341 +	CleanupStack::PushL(g1);
   1.342 +	--q;
   1.343 +	// select random x | 0 < x < q
   1.344 +	RInteger x = RInteger::NewRandomL(TInteger::One(), q);
   1.345 +	CleanupStack::PushL(x);
   1.346 +	++q;
   1.347 +
   1.348 +	//
   1.349 +	// create the keys parameters
   1.350 +	CCryptoParams* privateKeyParameters = CCryptoParams::NewLC();
   1.351 +	privateKeyParameters->AddL(p, KDsaKeyParameterPUid);
   1.352 +	privateKeyParameters->AddL(q, KDsaKeyParameterQUid);
   1.353 +	privateKeyParameters->AddL(g1, KDsaKeyParameterGUid);
   1.354 +	privateKeyParameters->AddL(x, KDsaKeyParameterXUid);
   1.355 +	TKeyProperty privateKeyProperties = {KDSAKeyPairGeneratorUid, 
   1.356 +										 KCryptoPluginDsaKeyPairGenUid,
   1.357 +									     KDsaPrivateKeyUid, 
   1.358 +									     KNonEmbeddedKeyUid};
   1.359 +
   1.360 +	CCryptoParams* publicKeyParameters = CCryptoParams::NewLC();
   1.361 +	publicKeyParameters->AddL(p, KDsaKeyParameterPUid);
   1.362 +	publicKeyParameters->AddL(q, KDsaKeyParameterQUid);
   1.363 +	publicKeyParameters->AddL(g1, KDsaKeyParameterGUid);
   1.364 +	RInteger y = RInteger::NewL(montP->ExponentiateL(*g, x));
   1.365 +	CleanupStack::PushL(y);
   1.366 +	publicKeyParameters->AddL(y, KDsaKeyParameterYUid);
   1.367 +	TKeyProperty publicKeyProperties = {KDSAKeyPairGeneratorUid,
   1.368 +										KCryptoPluginDsaKeyPairGenUid, 
   1.369 +										KDsaPublicKeyUid,
   1.370 +										KNonEmbeddedKeyUid};
   1.371 +
   1.372 +	//
   1.373 +	// create the private key
   1.374 +	//
   1.375 +	CKey* privateKey = CKey::NewL(privateKeyProperties, *privateKeyParameters);
   1.376 +	CleanupStack::PushL(privateKey);
   1.377 +
   1.378 +	//
   1.379 +	// create the public key
   1.380 +	//
   1.381 +	CKey* publicKey = CKey::NewL(publicKeyProperties, *publicKeyParameters);
   1.382 +	CleanupStack::PushL(publicKey);
   1.383 +
   1.384 +	aKeyPair = CKeyPair::NewL(publicKey, privateKey);
   1.385 +
   1.386 +	//publicKey, publicKeyParameters, y, privateKey, privateKeyParameters, x, g1, montP, q, p
   1.387 +	CleanupStack::Pop(2, privateKey);
   1.388 +	CleanupStack::PopAndDestroy(8, &p);	
   1.389 +	}