/*
* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* RSA Keypair implementation
* RSA keypair generation implementation
*
*/
/**
@file
*/
#include "rsakeypairgenimpl.h"
#include "pluginconfig.h"
#include "keypair.h"
#include <cryptospi/cryptospidef.h>
#include "common/inlines.h" // For TClassSwap
using namespace SoftwareCrypto;
/* CRSAKeyPairGenImpl */
CRSAKeyPairGenImpl::CRSAKeyPairGenImpl()
{
}
CRSAKeyPairGenImpl::~CRSAKeyPairGenImpl()
{
}
CRSAKeyPairGenImpl* CRSAKeyPairGenImpl::NewL(void)
{
CRSAKeyPairGenImpl* self = CRSAKeyPairGenImpl::NewLC();
CleanupStack::Pop(self);
return self;
}
CRSAKeyPairGenImpl* CRSAKeyPairGenImpl::NewLC(void)
{
CRSAKeyPairGenImpl* self = new(ELeave) CRSAKeyPairGenImpl();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
void CRSAKeyPairGenImpl::ConstructL(void)
{
CKeyPairGenImpl::ConstructL();
}
CExtendedCharacteristics* CRSAKeyPairGenImpl::CreateExtendedCharacteristicsL()
{
// All Symbian software plug-ins have unlimited concurrency, cannot be reserved
// for exclusive use and are not CERTIFIED to be standards compliant.
return CExtendedCharacteristics::NewL(KMaxTInt, EFalse);
}
const CExtendedCharacteristics* CRSAKeyPairGenImpl::GetExtendedCharacteristicsL()
{
return CRSAKeyPairGenImpl::CreateExtendedCharacteristicsL();
}
TUid CRSAKeyPairGenImpl::ImplementationUid() const
{
return KCryptoPluginRsaKeyPairGenUid;
}
void CRSAKeyPairGenImpl::Reset()
{
// does nothing in this plugin
}
void CRSAKeyPairGenImpl::GenerateKeyPairL(TInt aKeySize, const CCryptoParams& aKeyParameters, CKeyPair*& aKeyPair)
{
/*
* extract e
*/
const TInt aKeyType = aKeyParameters.GetTIntL(KRsaKeyTypeUid);
const TInt aPublicExponent = aKeyParameters.GetTIntL(KRsaKeyParameterEUid);
RInteger e = RInteger::NewL(aPublicExponent);
CleanupStack::PushL(e);
/*
* calculate p, q, n & d
*/
RInteger p;
RInteger q;
//these make sure n is a least aKeySize long
TInt pbits=(aKeySize+1)/2;
TInt qbits=aKeySize-pbits;
//generate a prime p such that GCD(e,p-1) == 1
for (;;)
{
p = RInteger::NewPrimeL(pbits,TInteger::ETop2BitsSet);
CleanupStack::PushL(p);
--p;
RInteger gcd = e.GCDL(p);
if( gcd == 1 )
{
++p;
gcd.Close();
//p is still on cleanup stack
break;
}
CleanupStack::PopAndDestroy(&p);
gcd.Close();
}
//generate a prime q such that GCD(e,q-1) == 1 && (p != q)
for (;;)
{
q = RInteger::NewPrimeL(qbits,TInteger::ETop2BitsSet);
CleanupStack::PushL(q);
--q;
RInteger gcd = e.GCDL(q);
if( gcd == 1 )
{
++q;
if( p != q )
{
gcd.Close();
//q is still on cleanup stack
break;
}
}
CleanupStack::PopAndDestroy(&q);
gcd.Close();
}
//make sure p > q
if ( p < q)
{
TClassSwap(p,q);
}
//calculate n = p * q
RInteger n = p.TimesL(q);
CleanupStack::PushL(n);
--p;
--q;
//temp = (p-1)(q-1)
RInteger temp = p.TimesL(q);
CleanupStack::PushL(temp);
//e * d = 1 mod ((p-1)(q-1))
//d = e^(-1) mod ((p-1)(q-1))
RInteger d = e.InverseModL(temp);
CleanupStack::PopAndDestroy(&temp); //temp
CleanupStack::PushL(d);
/*
* create private key depending on aKeyType
*/
CCryptoParams* privateKeyParameters = CCryptoParams::NewLC();
privateKeyParameters->AddL(n, KRsaKeyParameterNUid);
TKeyProperty* privateKeyProperties = NULL;
TKeyProperty privateKeyProperties_RsaPrivateKeyCRT = {KRSAKeyPairGeneratorUid, KCryptoPluginRsaKeyPairGenUid,
KRsaPrivateKeyCRTUid, KNonEmbeddedKeyUid };
TKeyProperty privateKeyProperties_RsaPrivateKeyStandard = {KRSAKeyPairGeneratorUid, KCryptoPluginRsaKeyPairGenUid,
KRsaPrivateKeyStandardUid, KNonEmbeddedKeyUid };
CCryptoParams*publicKeyParameters = CCryptoParams::NewLC();
publicKeyParameters->AddL(n, KRsaKeyParameterNUid);
publicKeyParameters->AddL(e, KRsaKeyParameterEUid);
TKeyProperty publicKeyProperties = {KRSAKeyPairGeneratorUid, KCryptoPluginRsaKeyPairGenUid,
KRsaPublicKeyUid, KNonEmbeddedKeyUid };
if (aKeyType == KRsaPrivateKeyCRT) // cleanup stack contains e, p, q, n, d and privateKeyParameters
{
/*
* calculate dP, dQ and qInv
*/
//calculate dP = d mod (p-1)
RInteger dP = d.ModuloL(p); //p is still p-1
CleanupStack::PushL(dP);
privateKeyParameters->AddL(dP, KRsaKeyParameterDPUid);
CleanupStack::PopAndDestroy(&dP);
//calculate dQ = d mod (q-1)
RInteger dQ = d.ModuloL(q); //q is still q-1
CleanupStack::PushL(dQ);
privateKeyParameters->AddL(dQ, KRsaKeyParameterDQUid);
CleanupStack::PopAndDestroy(&dQ);
++p;
++q;
//calculate inverse of qInv = q^(-1)mod(p)
RInteger qInv = q.InverseModL(p);
CleanupStack::PushL(qInv);
privateKeyParameters->AddL(qInv, KRsaKeyParameterQInvUid);
CleanupStack::PopAndDestroy(&qInv);
privateKeyParameters->AddL(p, KRsaKeyParameterPUid);
privateKeyParameters->AddL(q, KRsaKeyParameterQUid);
privateKeyProperties = &privateKeyProperties_RsaPrivateKeyCRT;
}
else if (aKeyType == KRsaPrivateKeyStandard)
{
privateKeyParameters->AddL(d, KRsaKeyParameterDUid);
privateKeyProperties = &privateKeyProperties_RsaPrivateKeyStandard;
}
else
{
User::Leave(KErrNotSupported);
}
// cleanup stack contains e, p, q, n, d and privateKeyParameters
CKey* privateKey = CKey::NewL(*privateKeyProperties, *privateKeyParameters);
CleanupStack::PushL(privateKey);
/*
* create public key
*/
CKey* publicKey = CKey::NewL(publicKeyProperties, *publicKeyParameters);
CleanupStack::PushL(publicKey);
/*
* create the key pair
*/
aKeyPair = CKeyPair::NewL(publicKey, privateKey);
CleanupStack::Pop(2, privateKey); //privateKey and publicKey
CleanupStack::PopAndDestroy(7, &e); //e, p, q, n, d, privateKeyParameters and publicKeyParameters
}