/*
* Copyright (c) 2005-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 "pkcs7encrypteddataobject.h"
/** The last character in the PKCS7 EncryptedData OID */
const TInt KPkcs7EncryptedData = 6;
EXPORT_C CPKCS7EncryptedDataObject* CPKCS7EncryptedDataObject::NewL(const CPKCS7ContentInfo& aContentInfo)
{
CPKCS7EncryptedDataObject* self = new (ELeave) CPKCS7EncryptedDataObject();
CleanupStack::PushL(self);
self->ConstructL(aContentInfo);
CleanupStack::Pop(self);
return self;
}
CPKCS7EncryptedDataObject::CPKCS7EncryptedDataObject(void)
{
}
CPKCS7EncryptedDataObject::~CPKCS7EncryptedDataObject()
{
delete iEncryptParams;
}
EXPORT_C TInt CPKCS7EncryptedDataObject::Version() const
{
return iVersion;
}
EXPORT_C CPKCS7EncryptedDataObject::TContentType CPKCS7EncryptedDataObject::ContentType() const
{
return iContentType;
}
EXPORT_C const TDesC8& CPKCS7EncryptedDataObject::EncryptedContentInfoData() const
{
return iEncryptedContent;
}
EXPORT_C const CPBEncryptParms& CPKCS7EncryptedDataObject::EncryptParams() const
{
return *iEncryptParams;
}
CPBEncryptParms* CPKCS7EncryptedDataObject::DecodeContentEncryptionAlgorithmL(const TDesC8& aBinaryData) const
{
TASN1DecGeneric seqGen(aBinaryData);
seqGen.InitL();
if (seqGen.Tag() != EASN1Sequence || seqGen.Class() != EUniversal)
{
User::Leave(KErrArgument);
}
TPtrC8 theContent(seqGen.Encoding());
CPBEncryptParms* encryptParams = TASN1DecPKCS5::DecodeDERL(theContent);
return encryptParams;
}
EXPORT_C HBufC8* CPKCS7EncryptedDataObject::DecryptDataL(const TDesC& aPassword) const
{
CPBEncryptElement* encryptElement;
HBufC8* pkcs12Pwd = PKCS12KDF::GeneratePasswordLC(aPassword);
if(iEncryptParams->Kdf() == CPBEncryptParms::EKdfPkcs12)
{
TPtrC8 iv = iEncryptParams->IV();
HBufC8* ivValue = HBufC8::NewMaxLC(iv.Length());
TPtr8 encryptKeyBuf = ivValue->Des();
switch(iEncryptParams->Cipher())
{
case ECipherARC4_128:
case ECipherARC4_40:
{
//derive only key it is unnecessary to derive an IV for RC4
break;
}
case ECipher3DES_CBC:
case ECipher2Key3DES_CBC:
case ECipherRC2_CBC_128_16:
case ECipherRC2_CBC_40_5:
{
PKCS12KDF::DeriveKeyL(encryptKeyBuf, PKCS12KDF::EIDByteIV, *pkcs12Pwd, iEncryptParams->Salt(), iEncryptParams->Iterations());
iEncryptParams->SetIV(encryptKeyBuf);
break;
}
default:
{
User::Leave(KErrNotSupported);
break;
}
}
CleanupStack::PopAndDestroy(ivValue);
// Create the decryptor
encryptElement = CPBEncryptElement::NewLC(*pkcs12Pwd, *iEncryptParams);
}
else
{
TPBPassword password(aPassword);
// Create the decryptor
encryptElement = CPBEncryptElement::NewLC(password.Password(), *iEncryptParams);
}
CPBDecryptor* decryptor = encryptElement->NewDecryptLC();
TPtrC8 encryptedKey(iEncryptedContent);
TUint encryptLength = encryptedKey.Length();
TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength);
if ( maxDecryptLength <= 0 )
{
User::Leave(KErrGeneral);
}
HBufC8* decryptedContent = HBufC8::NewLC(maxDecryptLength);
TPtr8 dcDes(decryptedContent->Des());
decryptor->Process(encryptedKey, dcDes);
CleanupStack::Pop(decryptedContent);
CleanupStack::PopAndDestroy(3, pkcs12Pwd); // pkcs12Pwd, encryptElement, decryptor
return decryptedContent;
}
void CPKCS7EncryptedDataObject::ConstructL(const CPKCS7ContentInfo& aContentInfo)
{
if(aContentInfo.ContentType() != KPkcs7EncryptedData)
{
User::Leave(KErrArgument);
}
// EncryptedData SEQUENCE
TASN1DecGeneric decGen(aContentInfo.ContentData());
decGen.InitL();
if(decGen.Tag() != EASN1Sequence || decGen.Class() != EUniversal)
{
User::Leave(KErrArgument);
}
TASN1DecSequence seq1;
CArrayPtrFlat<TASN1DecGeneric>* EncryptedDataContents = seq1.DecodeDERLC(decGen);
// Both version and encryptedContentInfo should be present
if (EncryptedDataContents->Count() != 2)
{
User::Leave(KErrArgument);
}
// VERSION
// version is the syntax version number. It shall be 0 for this version of the standard
const TASN1DecGeneric* EncryptedDataContentsAt0 = EncryptedDataContents->At(0);
if(EncryptedDataContentsAt0->Tag() != EASN1Integer || EncryptedDataContentsAt0->Class() != EUniversal)
{
User::Leave(KErrArgument);
}
TASN1DecInteger intDecoder;
iVersion = intDecoder.DecodeDERShortL(*EncryptedDataContentsAt0);
if (iVersion != 0)
{
User::Leave(KErrArgument);
}
// ENCRYPTED CONTENT INFO a SEQUENCE
const TASN1DecGeneric* EncryptedDataContentsAt1 = EncryptedDataContents->At(1);
if (EncryptedDataContentsAt1->Tag() != EASN1Sequence || EncryptedDataContentsAt1->Class() != EUniversal)
{
User::Leave(KErrArgument);
}
TASN1DecSequence seq2;
CArrayPtrFlat<TASN1DecGeneric>* EncryptedContentInfo = seq2.DecodeDERLC(*EncryptedDataContentsAt1);
// CONTENT TYPE IDENTIFIED BY AN OBJECT IDENTIFIER
// Gets the oid
TASN1DecObjectIdentifier ContentTypeoidDec;
HBufC* contentType = ContentTypeoidDec.DecodeDERL(*EncryptedContentInfo->At(0));
if(contentType->Compare(KPkcs7DataOID()) == 0)
{
iContentType = EPkcs7Data;
}
else
{
User::Leave(KErrNotSupported);
}
delete contentType;
// CONTENT ENCRYPTION ALGORITHM
// Get the Cipher used and the encoded params in it
iEncryptParams = DecodeContentEncryptionAlgorithmL(EncryptedContentInfo->At(1)->Encoding());
// ENCRYPTED CONTENT
// This is an OPTIONAL field
TInt encryptedContentInfoCount = EncryptedContentInfo->Count();
if(encryptedContentInfoCount == 3)
{
TASN1DecGeneric decOctetString(*EncryptedContentInfo->At(2));
decOctetString.InitL();
iEncryptedContent.Set(decOctetString.GetContentDER());
}
else if(encryptedContentInfoCount > 3 || encryptedContentInfoCount < 2)
{
User::Leave(KErrArgument);
}
else if(encryptedContentInfoCount == 2)
{
iEncryptedContent.Set(KNullDesC8());
}
CleanupStack::PopAndDestroy(2, EncryptedDataContents); //EncryptedDataContents, EncryptedContentInfo
}