cryptoservices/asnpkcs/source/asnpkcs8.cpp
changeset 8 35751d3474b7
parent 0 2c201484c85f
--- a/cryptoservices/asnpkcs/source/asnpkcs8.cpp	Tue Jul 21 01:04:32 2009 +0100
+++ b/cryptoservices/asnpkcs/source/asnpkcs8.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -1,506 +1,506 @@
-/*
-* Copyright (c) 2004-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: 
-*
-*/
-
-
-#include <asn1dec.h>
-#include <x509keys.h>
-#include <x509cert.h>
-#include "asnpkcs.h"
-#include <pbe.h>
-#include <pbedata.h>
-#include <keyidentifierutil.h>
-
-/*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeDERL(const TDesC8& aBinaryData)
-{
-	return (CDecPKCS8Data::NewL(aBinaryData));
-}
-
-/*
-EncryptedPrivateKeyInfo ::= SEQUENCE {
-  encryptionAlgorithm EncryptionAlgorithmIdentifier,
-  encryptedData EncryptedData }
-EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-EncryptedData ::= OCTET STRING
-*/
-
-/*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeEncryptedDERL(const TDesC8& aBinaryData, const TDesC8& aPassword)
-{
-	TASN1DecGeneric seqGen(aBinaryData);
-	seqGen.InitL();
-	if (seqGen.Tag() != EASN1Sequence)
-		{
-		User::Leave(KErrArgument);
-		}
-	
-	TASN1DecSequence dec;
-	CArrayPtrFlat<TASN1DecGeneric>* theData = dec.DecodeDERLC(seqGen);
-	TInt seqIndex = 0;
-	TInt count = theData->Count();
-	if (seqIndex >= count)
-		{
-		User::Leave(KErrArgument);		
-		}
-
-//	Get the first part of the sequence -> PKCS5 data
-	TASN1DecGeneric* pkcs5 = theData->operator[](seqIndex);
-	TPtrC8 theContent(pkcs5->Encoding());	//	expect this to be a sequence
-	CPBEncryptParms* encryptParams = TASN1DecPKCS5::DecodeDERL(theContent);
-	CleanupStack::PushL(encryptParams);
-
-//	Create the decryptor	
-	CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(aPassword, *encryptParams);
-	CPBDecryptor* decryptor = encryptElement->NewDecryptLC();
-//	Decrypt the final part of the sequence -> encrypted PKCS8 object
-	TASN1DecGeneric* pkcs8 = theData->operator[](count-1);
-	if (pkcs8->Tag() != EASN1OctetString)
-		{
-		User::Leave(KErrArgument);
-		}
-	TPtrC8 encryptedKey(pkcs8->GetContentDER());
-	TUint encryptLength = encryptedKey.Length();
-	TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength);
-	if (maxDecryptLength<=0)
-		{
-		User::Leave(KErrGeneral);		
-		}
-	
-	HBufC8* decryptOutput = HBufC8::NewLC(encryptLength);
-	TPtr8 decryptOutputPtr(decryptOutput->Des());
-	decryptOutputPtr.FillZ();
-	decryptor->Process(encryptedKey, decryptOutputPtr);
-			
-	CDecPKCS8Data* pkcs8Data = CDecPKCS8Data::NewL(decryptOutputPtr);
-
-	//	decryptOutput decryptor encryptElement 
-	//	encryptParams theData
-	CleanupStack::PopAndDestroy(5, theData);
-	
-	return (pkcs8Data);
-}
-
-/*
-Sample cleartext pkcs8 data from pkcs8dsa.001:
-
-          SEQUENCE
-30          Tag: Constructed sequence
-81 c8       Length (may be one or more bytes)
-
-            INTEGER
-02            Tag: Integer
-01            Length: 1 byte
-00            Value: 0
-
-            SEQUENCE    
-30            Tag: Constructed sequence
-81 a9         Length (may be one or more bytes)
-
-              OID
-06              Tag: OID
-07              Length: 7 bytes
-2a 86 48 ce 38 04 01
-                Value: dsa (1 2 840 10040 4 1)
-*/
-
-_LIT8(KPKCS8DataVersion0, "\x02\x01\x00");
-_LIT8(KPKCS8DataOIDDSA, "\x06\x07\x2a\x86\x48\xce\x38\x04\x01");
-_LIT8(KPKCS8DataOIDRSA, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01");
-
-/*static*/ EXPORT_C TBool TASN1DecPKCS8::IsPKCS8Data(const TDesC8& aBinaryData)
-	{
-	// We don't decode the data because we may only have the first few bytes -
-	// instead we check the ASN1 by hand.
-
-	ASSERT(aBinaryData.Length() >= KIsPKCS8DataMinLength);
-	TInt pos = 0;
-
-	return
-		IsASN1Sequence(aBinaryData, pos) &&
-		IsExpectedData(aBinaryData, pos, KPKCS8DataVersion0) &&
-		IsASN1Sequence(aBinaryData, pos) &&
-		(IsExpectedData(aBinaryData, pos, KPKCS8DataOIDDSA) ||
-		 IsExpectedData(aBinaryData, pos, KPKCS8DataOIDRSA));
-	}
-
-/*
-Sample encrypted pkcs8 data from encryptPK8rsa1.txt
-
-          SEQUENCE
-30          Tag: Constructed sequence
-82 01 a3    Length (may be one or more bytes)
-
-            SEQUENCE
-30            Tag: Constructed sequence
-3d            Length (may be one or more bytes)
-
-              OID
-06              Tag: OID
-09              Length: 9 bytes
-2a 86 48 86 f7 0d 01 05 0d
-                Value: pkcs5PBES2 (1 2 840 113549 1 5 13)
-
-              SEQUENCE
-30              Tag: Constructed sequence
-30              Length (may be one or more bytes)
-
-                SEQUENCE
-30                Tag: Constructed sequence
-1b                Length (may be one or more bytes)
-
-                  OID
-06                  Tag: OID
-09                  Length: 9 bytes
-2a 86 48 86 f7 0d 01 05 0c
-                    Value: pkcs5PBKDF2 (1 2 840 113549 1 5 12)
-*/
-
-_LIT8(KEncryptedPKCS8DataOIDpkcs5PBES2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0d");
-_LIT8(KEncryptedPKCS8DataOIDpkcs5PBKDF2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c");
-
-EXPORT_C TBool TASN1DecPKCS8::IsEncryptedPKCS8Data(const TDesC8& aBinaryData)
-	{
-	// We don't decode the data because we may only have the first few bytes -
-	// instead we check the ASN1 by hand.
-
-	ASSERT(aBinaryData.Length() >= KIsEncryptedPKCS8DataMinLength);
-	TInt pos = 0;
-
-	return
-		IsASN1Sequence(aBinaryData, pos) &&
-		IsASN1Sequence(aBinaryData, pos) &&
-		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBES2) &&
-		IsASN1Sequence(aBinaryData, pos) &&
-		IsASN1Sequence(aBinaryData, pos) &&
-		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBKDF2);
-	}
-
-/**
- * Determine if the some data represents the start of an ASN1 sequence.  The
- * data is specified by a descriptor and an offset.  If the data matches, the
- * offset is advanced to point to the contents of the sequence.
- */
-TBool TASN1DecPKCS8::IsASN1Sequence(const TDesC8& aBinaryData, TInt& aPos)
-	{
-	// Check we have enough data
-	if ((aPos + 2) >= aBinaryData.Length())
-		{
-		return EFalse;
-		}
-	// Check the outermost sequence is valid
-	if (aBinaryData[aPos++] != 0x30 /* constructed sequence */)
-		{
-		return EFalse;
-		}
-	// Skip sequence length
-	TInt length0 = aBinaryData[aPos++];
-	if (length0 & 0x80)
-		{
-		aPos += length0 & 0x7f;
-		}
-	return ETrue;
-	}
-
-/**
- * Determine if some data starts with an expected string.  The data is specified
- * by a descriptor and an offset.  If the data matches, the offset is advanced
- * to point after the match.
- */
-TBool TASN1DecPKCS8::IsExpectedData(const TDesC8& aBinaryData, TInt& aPos, const TDesC8& aExpectedData)
-	{
-	TInt length = aExpectedData.Length();
-	// Check we have enough data
-	if (aPos + length >= aBinaryData.Length())
-		{
-		return EFalse;
-		}
-	// Check data matches	
-	if (aBinaryData.Mid(aPos, length) != aExpectedData)
-		{
-		return EFalse;
-		}
-	aPos += length;
-	return ETrue;
-	}
-
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-//	PKCS#8 object data representation
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-
-/*static*/ CDecPKCS8Data* CDecPKCS8Data::NewL(const TDesC8& aData)
-{
-	CDecPKCS8Data* me = new (ELeave) CDecPKCS8Data();
-	CleanupStack::PushL(me);
-	me->ConstructL(aData);
-	CleanupStack::Pop(me);
-	return (me);
-}
-
-CDecPKCS8Data::CDecPKCS8Data()
-{}
-
-CDecPKCS8Data::~CDecPKCS8Data()
-{
-	if (iKeyPairData)
-	{
-		iKeyPairData->Release();
-		iKeyPairData = NULL;
-	}
-
-	if (iAttributes)
-	{
-		delete iAttributes;
-		iAttributes = NULL;
-	}
-}
-
-//	Because this is part of construction, don't rely on
-//	cleanup of partially constructed items...
-void CDecPKCS8Data::ConstructL(const TDesC8& aData)
-	{
-	TASN1DecGeneric seqGen(aData);
-	seqGen.InitL();
-	if (seqGen.Tag() != EASN1Sequence)
-		{
-		User::Leave(KErrArgument);
-		}
-
-	TASN1DecSequence seq;
-	CArrayPtrFlat<TASN1DecGeneric>* seqContents = seq.DecodeDERLC(seqGen);
-	if (seqContents->Count() < 3 || seqContents->Count() > 4)
-		{
-		User::Leave(KErrArgument);
-		}
-				
-//	VERSION
-	if (seqContents->At(0)->Tag() != EASN1Integer)
-		{
-		User::Leave(KErrArgument);
-		}
-	TASN1DecInteger intDecoder;
-	iVersion = intDecoder.DecodeDERShortL(*(seqContents->At(0)));
-	if (iVersion!=0)
-		{
-		User::Leave(KErrArgument);
-		}
-	
-//	ALGORITHM
-	CX509AlgorithmIdentifier* algorithm = CX509AlgorithmIdentifier::NewLC(seqContents->At(1)->Encoding());
-	iAlgorithmID = algorithm->Algorithm();
-		
-//	KEY DATA
-	switch (iAlgorithmID)
-		{//	Only support RSA, DSA, DH
-		case ERSA:
-			iKeyPairData = CPKCS8KeyPairRSA::NewL(*(seqContents->At(2)));
-			break;
-			
-		case EDSA:
-			{
-			TPtrC8 params(algorithm->EncodedParams());		
-			iKeyPairData = CPKCS8KeyPairDSA::NewL(params, *(seqContents->At(2)));
-			break;
-			}
-			
-		case EDH: // Currently not supported because no test data is available
-		default:
-			User::Leave(KErrNotSupported);
-			break;
-		}
-
-	CleanupStack::PopAndDestroy(algorithm);
-
-	if (seqContents->Count() == 4)
-		{
-		// I think we should check the tag is zero here, but we're going to be
-		// lenient due to lack of real test data
-		
-		//if (seqContents->At(3)->Tag() != 0) // Implicitly tagged
-		//	{
-		//	User::Leave(KErrArgument);
-		//	}
-		
-		iAttributes = seqContents->At(3)->Encoding().AllocL();
-		}
-
-	CleanupStack::PopAndDestroy(seqContents);
-	}
-
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-//	RSA decoding
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-
-/*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairRSA::NewL(const TASN1DecGeneric& aSource)
-{
-	CPKCS8KeyPairRSA* me = new (ELeave) CPKCS8KeyPairRSA();
-	CleanupStack::PushL(me);
-	me->ConstructL(aSource);
-	CleanupStack::Pop(me);
-
-	return (me);
-}
-
-MPKCS8DecodedKeyPairData::~MPKCS8DecodedKeyPairData()
-	{	
-	}
-
-CPKCS8KeyPairRSA::~CPKCS8KeyPairRSA()
-{
-	delete iPublicKey;
-	delete iPrivateKey;
-}
-
-void CPKCS8KeyPairRSA::Release()
-{
-	delete this;
-}
-
-void CPKCS8KeyPairRSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
-{
-	if (iPublicKey)
-		KeyIdentifierUtil::RSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
-	else
-		User::Leave(KErrNotReady);
-}
-
-TUint CPKCS8KeyPairRSA::KeySize() const
-{
-	if (!iPublicKey)
-	{
-		ASSERT(EFalse);
-		return (0xffffffff);
-	}
-	
-	const TInteger& modulus = iPublicKey->N();
-
-	TUint size = modulus.BitCount();
-	return (size);
-}
-
-void CPKCS8KeyPairRSA::ConstructL(const TASN1DecGeneric& aSource)
-{
-	TPtrC8 theContent(aSource.GetContentDER());
-	TASN1DecRSAKeyPair keyPairDecoder;
-	TInt tempPos = 0;
-	keyPairDecoder.DecodeDERL(theContent, tempPos, iPublicKey, iPrivateKey);
-}
-
-
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-//	DSA decoding
-//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
-
-/*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairDSA::NewL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
-{
-	CPKCS8KeyPairDSA* me = new (ELeave) CPKCS8KeyPairDSA();
-	CleanupStack::PushL(me);
-	me->ConstructL(aParamsData, aSource);
-	CleanupStack::Pop(me);
-
-	return (me);
-}
-
-CPKCS8KeyPairDSA::~CPKCS8KeyPairDSA()
-{
-	delete iPublicKey;
-	delete iPrivateKey;
-}
-
-void CPKCS8KeyPairDSA::Release()
-{
-	delete this;
-}
-
-void CPKCS8KeyPairDSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
-{
-	if (iPublicKey)
-		KeyIdentifierUtil::DSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
-	else
-		User::Leave(KErrNotReady);
-}
-
-TUint CPKCS8KeyPairDSA::KeySize() const
-{
-	if (!iPublicKey)
-	{
-		ASSERT(EFalse);
-		return (0xffffffff);
-	}
-	
-	const TInteger& P = iPublicKey->P();
-
-	TUint size = P.BitCount();
-	return (size);
-}
-
-void CPKCS8KeyPairDSA::ConstructL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
-{
-	TX509KeyFactory keyFactory;
-	CDSAParameters* params = keyFactory.DSAParametersL(aParamsData);
-	CleanupStack::PushL(params);
-
-	RInteger P = RInteger::NewL(params->P());
-	CleanupStack::PushL(P);
-
-	RInteger Q = RInteger::NewL(params->Q());
-	CleanupStack::PushL(Q);
-
-	RInteger G = RInteger::NewL(params->G());
-	CleanupStack::PushL(G);
-
-	if (aSource.Tag() != EASN1OctetString)
-		{
-		User::Leave(KErrArgument);
-		}
-	TASN1DecOctetString  octetDecoder;
-	HBufC8* wrapped = octetDecoder.DecodeDERL(aSource);
-	CleanupStack::PushL(wrapped);	
-
-	TASN1DecGeneric integer(*wrapped);
-	integer.InitL();
-	if (integer.Tag() != EASN1Integer)
-		{
-		User::Leave(KErrArgument);
-		}		
-	TASN1DecInteger decInt;
-	RInteger X = decInt.DecodeDERLongL(integer);
-	CleanupStack::PopAndDestroy(wrapped);
-	CleanupStack::PushL(X);
-			
-	RInteger P1 = RInteger::NewL(params->P());
-	CleanupStack::PushL(P1);
-	
-	RInteger Q1 = RInteger::NewL(params->Q());
-	CleanupStack::PushL(Q1);
-	
-	RInteger G1 = RInteger::NewL(params->G());
-	CleanupStack::PushL(G1);
-
-	RInteger Y = TInteger::ModularExponentiateL(G, X, P);
-	CleanupStack::PushL(Y);
-
-	iPublicKey = CDSAPublicKey::NewL(P1, Q1, G1, Y);
-
-	// Now have to pop everything owned by iPublicKey otherwise it will be
-	// deleted twice if the CDSAPrivateKey::NewL leaves
-
-	CleanupStack::Pop(4, &P1);	// now owned by iPublicKey
-	
-	iPrivateKey = CDSAPrivateKey::NewL(P, Q, G, X);
-
-	CleanupStack::Pop(4, &P);	// now owned by iPrivateKey
-		
-	CleanupStack::PopAndDestroy(params);
-}
+/*
+* Copyright (c) 2004-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: 
+*
+*/
+
+
+#include <asn1dec.h>
+#include <x509keys.h>
+#include <x509cert.h>
+#include "asnpkcs.h"
+#include <pbe.h>
+#include <pbedata.h>
+#include <keyidentifierutil.h>
+
+/*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeDERL(const TDesC8& aBinaryData)
+{
+	return (CDecPKCS8Data::NewL(aBinaryData));
+}
+
+/*
+EncryptedPrivateKeyInfo ::= SEQUENCE {
+  encryptionAlgorithm EncryptionAlgorithmIdentifier,
+  encryptedData EncryptedData }
+EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+EncryptedData ::= OCTET STRING
+*/
+
+/*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeEncryptedDERL(const TDesC8& aBinaryData, const TDesC8& aPassword)
+{
+	TASN1DecGeneric seqGen(aBinaryData);
+	seqGen.InitL();
+	if (seqGen.Tag() != EASN1Sequence)
+		{
+		User::Leave(KErrArgument);
+		}
+	
+	TASN1DecSequence dec;
+	CArrayPtrFlat<TASN1DecGeneric>* theData = dec.DecodeDERLC(seqGen);
+	TInt seqIndex = 0;
+	TInt count = theData->Count();
+	if (seqIndex >= count)
+		{
+		User::Leave(KErrArgument);		
+		}
+
+//	Get the first part of the sequence -> PKCS5 data
+	TASN1DecGeneric* pkcs5 = theData->operator[](seqIndex);
+	TPtrC8 theContent(pkcs5->Encoding());	//	expect this to be a sequence
+	CPBEncryptParms* encryptParams = TASN1DecPKCS5::DecodeDERL(theContent);
+	CleanupStack::PushL(encryptParams);
+
+//	Create the decryptor	
+	CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(aPassword, *encryptParams);
+	CPBDecryptor* decryptor = encryptElement->NewDecryptLC();
+//	Decrypt the final part of the sequence -> encrypted PKCS8 object
+	TASN1DecGeneric* pkcs8 = theData->operator[](count-1);
+	if (pkcs8->Tag() != EASN1OctetString)
+		{
+		User::Leave(KErrArgument);
+		}
+	TPtrC8 encryptedKey(pkcs8->GetContentDER());
+	TUint encryptLength = encryptedKey.Length();
+	TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength);
+	if (maxDecryptLength<=0)
+		{
+		User::Leave(KErrGeneral);		
+		}
+	
+	HBufC8* decryptOutput = HBufC8::NewLC(encryptLength);
+	TPtr8 decryptOutputPtr(decryptOutput->Des());
+	decryptOutputPtr.FillZ();
+	decryptor->Process(encryptedKey, decryptOutputPtr);
+			
+	CDecPKCS8Data* pkcs8Data = CDecPKCS8Data::NewL(decryptOutputPtr);
+
+	//	decryptOutput decryptor encryptElement 
+	//	encryptParams theData
+	CleanupStack::PopAndDestroy(5, theData);
+	
+	return (pkcs8Data);
+}
+
+/*
+Sample cleartext pkcs8 data from pkcs8dsa.001:
+
+          SEQUENCE
+30          Tag: Constructed sequence
+81 c8       Length (may be one or more bytes)
+
+            INTEGER
+02            Tag: Integer
+01            Length: 1 byte
+00            Value: 0
+
+            SEQUENCE    
+30            Tag: Constructed sequence
+81 a9         Length (may be one or more bytes)
+
+              OID
+06              Tag: OID
+07              Length: 7 bytes
+2a 86 48 ce 38 04 01
+                Value: dsa (1 2 840 10040 4 1)
+*/
+
+_LIT8(KPKCS8DataVersion0, "\x02\x01\x00");
+_LIT8(KPKCS8DataOIDDSA, "\x06\x07\x2a\x86\x48\xce\x38\x04\x01");
+_LIT8(KPKCS8DataOIDRSA, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01");
+
+/*static*/ EXPORT_C TBool TASN1DecPKCS8::IsPKCS8Data(const TDesC8& aBinaryData)
+	{
+	// We don't decode the data because we may only have the first few bytes -
+	// instead we check the ASN1 by hand.
+
+	ASSERT(aBinaryData.Length() >= KIsPKCS8DataMinLength);
+	TInt pos = 0;
+
+	return
+		IsASN1Sequence(aBinaryData, pos) &&
+		IsExpectedData(aBinaryData, pos, KPKCS8DataVersion0) &&
+		IsASN1Sequence(aBinaryData, pos) &&
+		(IsExpectedData(aBinaryData, pos, KPKCS8DataOIDDSA) ||
+		 IsExpectedData(aBinaryData, pos, KPKCS8DataOIDRSA));
+	}
+
+/*
+Sample encrypted pkcs8 data from encryptPK8rsa1.txt
+
+          SEQUENCE
+30          Tag: Constructed sequence
+82 01 a3    Length (may be one or more bytes)
+
+            SEQUENCE
+30            Tag: Constructed sequence
+3d            Length (may be one or more bytes)
+
+              OID
+06              Tag: OID
+09              Length: 9 bytes
+2a 86 48 86 f7 0d 01 05 0d
+                Value: pkcs5PBES2 (1 2 840 113549 1 5 13)
+
+              SEQUENCE
+30              Tag: Constructed sequence
+30              Length (may be one or more bytes)
+
+                SEQUENCE
+30                Tag: Constructed sequence
+1b                Length (may be one or more bytes)
+
+                  OID
+06                  Tag: OID
+09                  Length: 9 bytes
+2a 86 48 86 f7 0d 01 05 0c
+                    Value: pkcs5PBKDF2 (1 2 840 113549 1 5 12)
+*/
+
+_LIT8(KEncryptedPKCS8DataOIDpkcs5PBES2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0d");
+_LIT8(KEncryptedPKCS8DataOIDpkcs5PBKDF2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c");
+
+EXPORT_C TBool TASN1DecPKCS8::IsEncryptedPKCS8Data(const TDesC8& aBinaryData)
+	{
+	// We don't decode the data because we may only have the first few bytes -
+	// instead we check the ASN1 by hand.
+
+	ASSERT(aBinaryData.Length() >= KIsEncryptedPKCS8DataMinLength);
+	TInt pos = 0;
+
+	return
+		IsASN1Sequence(aBinaryData, pos) &&
+		IsASN1Sequence(aBinaryData, pos) &&
+		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBES2) &&
+		IsASN1Sequence(aBinaryData, pos) &&
+		IsASN1Sequence(aBinaryData, pos) &&
+		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBKDF2);
+	}
+
+/**
+ * Determine if the some data represents the start of an ASN1 sequence.  The
+ * data is specified by a descriptor and an offset.  If the data matches, the
+ * offset is advanced to point to the contents of the sequence.
+ */
+TBool TASN1DecPKCS8::IsASN1Sequence(const TDesC8& aBinaryData, TInt& aPos)
+	{
+	// Check we have enough data
+	if ((aPos + 2) >= aBinaryData.Length())
+		{
+		return EFalse;
+		}
+	// Check the outermost sequence is valid
+	if (aBinaryData[aPos++] != 0x30 /* constructed sequence */)
+		{
+		return EFalse;
+		}
+	// Skip sequence length
+	TInt length0 = aBinaryData[aPos++];
+	if (length0 & 0x80)
+		{
+		aPos += length0 & 0x7f;
+		}
+	return ETrue;
+	}
+
+/**
+ * Determine if some data starts with an expected string.  The data is specified
+ * by a descriptor and an offset.  If the data matches, the offset is advanced
+ * to point after the match.
+ */
+TBool TASN1DecPKCS8::IsExpectedData(const TDesC8& aBinaryData, TInt& aPos, const TDesC8& aExpectedData)
+	{
+	TInt length = aExpectedData.Length();
+	// Check we have enough data
+	if (aPos + length >= aBinaryData.Length())
+		{
+		return EFalse;
+		}
+	// Check data matches	
+	if (aBinaryData.Mid(aPos, length) != aExpectedData)
+		{
+		return EFalse;
+		}
+	aPos += length;
+	return ETrue;
+	}
+
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+//	PKCS#8 object data representation
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+
+/*static*/ CDecPKCS8Data* CDecPKCS8Data::NewL(const TDesC8& aData)
+{
+	CDecPKCS8Data* me = new (ELeave) CDecPKCS8Data();
+	CleanupStack::PushL(me);
+	me->ConstructL(aData);
+	CleanupStack::Pop(me);
+	return (me);
+}
+
+CDecPKCS8Data::CDecPKCS8Data()
+{}
+
+CDecPKCS8Data::~CDecPKCS8Data()
+{
+	if (iKeyPairData)
+	{
+		iKeyPairData->Release();
+		iKeyPairData = NULL;
+	}
+
+	if (iAttributes)
+	{
+		delete iAttributes;
+		iAttributes = NULL;
+	}
+}
+
+//	Because this is part of construction, don't rely on
+//	cleanup of partially constructed items...
+void CDecPKCS8Data::ConstructL(const TDesC8& aData)
+	{
+	TASN1DecGeneric seqGen(aData);
+	seqGen.InitL();
+	if (seqGen.Tag() != EASN1Sequence)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	TASN1DecSequence seq;
+	CArrayPtrFlat<TASN1DecGeneric>* seqContents = seq.DecodeDERLC(seqGen);
+	if (seqContents->Count() < 3 || seqContents->Count() > 4)
+		{
+		User::Leave(KErrArgument);
+		}
+				
+//	VERSION
+	if (seqContents->At(0)->Tag() != EASN1Integer)
+		{
+		User::Leave(KErrArgument);
+		}
+	TASN1DecInteger intDecoder;
+	iVersion = intDecoder.DecodeDERShortL(*(seqContents->At(0)));
+	if (iVersion!=0)
+		{
+		User::Leave(KErrArgument);
+		}
+	
+//	ALGORITHM
+	CX509AlgorithmIdentifier* algorithm = CX509AlgorithmIdentifier::NewLC(seqContents->At(1)->Encoding());
+	iAlgorithmID = algorithm->Algorithm();
+		
+//	KEY DATA
+	switch (iAlgorithmID)
+		{//	Only support RSA, DSA, DH
+		case ERSA:
+			iKeyPairData = CPKCS8KeyPairRSA::NewL(*(seqContents->At(2)));
+			break;
+			
+		case EDSA:
+			{
+			TPtrC8 params(algorithm->EncodedParams());		
+			iKeyPairData = CPKCS8KeyPairDSA::NewL(params, *(seqContents->At(2)));
+			break;
+			}
+			
+		case EDH: // Currently not supported because no test data is available
+		default:
+			User::Leave(KErrNotSupported);
+			break;
+		}
+
+	CleanupStack::PopAndDestroy(algorithm);
+
+	if (seqContents->Count() == 4)
+		{
+		// I think we should check the tag is zero here, but we're going to be
+		// lenient due to lack of real test data
+		
+		//if (seqContents->At(3)->Tag() != 0) // Implicitly tagged
+		//	{
+		//	User::Leave(KErrArgument);
+		//	}
+		
+		iAttributes = seqContents->At(3)->Encoding().AllocL();
+		}
+
+	CleanupStack::PopAndDestroy(seqContents);
+	}
+
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+//	RSA decoding
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+
+/*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairRSA::NewL(const TASN1DecGeneric& aSource)
+{
+	CPKCS8KeyPairRSA* me = new (ELeave) CPKCS8KeyPairRSA();
+	CleanupStack::PushL(me);
+	me->ConstructL(aSource);
+	CleanupStack::Pop(me);
+
+	return (me);
+}
+
+MPKCS8DecodedKeyPairData::~MPKCS8DecodedKeyPairData()
+	{	
+	}
+
+CPKCS8KeyPairRSA::~CPKCS8KeyPairRSA()
+{
+	delete iPublicKey;
+	delete iPrivateKey;
+}
+
+void CPKCS8KeyPairRSA::Release()
+{
+	delete this;
+}
+
+void CPKCS8KeyPairRSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
+{
+	if (iPublicKey)
+		KeyIdentifierUtil::RSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
+	else
+		User::Leave(KErrNotReady);
+}
+
+TUint CPKCS8KeyPairRSA::KeySize() const
+{
+	if (!iPublicKey)
+	{
+		ASSERT(EFalse);
+		return (0xffffffff);
+	}
+	
+	const TInteger& modulus = iPublicKey->N();
+
+	TUint size = modulus.BitCount();
+	return (size);
+}
+
+void CPKCS8KeyPairRSA::ConstructL(const TASN1DecGeneric& aSource)
+{
+	TPtrC8 theContent(aSource.GetContentDER());
+	TASN1DecRSAKeyPair keyPairDecoder;
+	TInt tempPos = 0;
+	keyPairDecoder.DecodeDERL(theContent, tempPos, iPublicKey, iPrivateKey);
+}
+
+
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+//	DSA decoding
+//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
+
+/*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairDSA::NewL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
+{
+	CPKCS8KeyPairDSA* me = new (ELeave) CPKCS8KeyPairDSA();
+	CleanupStack::PushL(me);
+	me->ConstructL(aParamsData, aSource);
+	CleanupStack::Pop(me);
+
+	return (me);
+}
+
+CPKCS8KeyPairDSA::~CPKCS8KeyPairDSA()
+{
+	delete iPublicKey;
+	delete iPrivateKey;
+}
+
+void CPKCS8KeyPairDSA::Release()
+{
+	delete this;
+}
+
+void CPKCS8KeyPairDSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
+{
+	if (iPublicKey)
+		KeyIdentifierUtil::DSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
+	else
+		User::Leave(KErrNotReady);
+}
+
+TUint CPKCS8KeyPairDSA::KeySize() const
+{
+	if (!iPublicKey)
+	{
+		ASSERT(EFalse);
+		return (0xffffffff);
+	}
+	
+	const TInteger& P = iPublicKey->P();
+
+	TUint size = P.BitCount();
+	return (size);
+}
+
+void CPKCS8KeyPairDSA::ConstructL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
+{
+	TX509KeyFactory keyFactory;
+	CDSAParameters* params = keyFactory.DSAParametersL(aParamsData);
+	CleanupStack::PushL(params);
+
+	RInteger P = RInteger::NewL(params->P());
+	CleanupStack::PushL(P);
+
+	RInteger Q = RInteger::NewL(params->Q());
+	CleanupStack::PushL(Q);
+
+	RInteger G = RInteger::NewL(params->G());
+	CleanupStack::PushL(G);
+
+	if (aSource.Tag() != EASN1OctetString)
+		{
+		User::Leave(KErrArgument);
+		}
+	TASN1DecOctetString  octetDecoder;
+	HBufC8* wrapped = octetDecoder.DecodeDERL(aSource);
+	CleanupStack::PushL(wrapped);	
+
+	TASN1DecGeneric integer(*wrapped);
+	integer.InitL();
+	if (integer.Tag() != EASN1Integer)
+		{
+		User::Leave(KErrArgument);
+		}		
+	TASN1DecInteger decInt;
+	RInteger X = decInt.DecodeDERLongL(integer);
+	CleanupStack::PopAndDestroy(wrapped);
+	CleanupStack::PushL(X);
+			
+	RInteger P1 = RInteger::NewL(params->P());
+	CleanupStack::PushL(P1);
+	
+	RInteger Q1 = RInteger::NewL(params->Q());
+	CleanupStack::PushL(Q1);
+	
+	RInteger G1 = RInteger::NewL(params->G());
+	CleanupStack::PushL(G1);
+
+	RInteger Y = TInteger::ModularExponentiateL(G, X, P);
+	CleanupStack::PushL(Y);
+
+	iPublicKey = CDSAPublicKey::NewL(P1, Q1, G1, Y);
+
+	// Now have to pop everything owned by iPublicKey otherwise it will be
+	// deleted twice if the CDSAPrivateKey::NewL leaves
+
+	CleanupStack::Pop(4, &P1);	// now owned by iPublicKey
+	
+	iPrivateKey = CDSAPrivateKey::NewL(P, Q, G, X);
+
+	CleanupStack::Pop(4, &P);	// now owned by iPrivateKey
+		
+	CleanupStack::PopAndDestroy(params);
+}