diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/drmcrypto/src/OmaCrypto.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/drmcrypto/src/OmaCrypto.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,635 @@ +/* +* Copyright (c) 2002-2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: OMA DRM 2.x Crypto Algorithms +* +*/ + + + +// INCLUDE FILES +#include +#include +#include +#include +#include "OmaCrypto.h" +#include "DrmKeyStorage.h" + +#ifdef _DEBUG +#define LOGGING +#endif + +#ifdef LOGGING +_LIT(KLogDir, "DRM"); +_LIT(KLogName, "Crypto.log"); +#include "flogger.h" +#define LOG(string) \ + RFileLogger::Write(KLogDir, KLogName, \ + EFileLoggingModeAppend, string); +#define LOGHEX(buffer) \ + RFileLogger::HexDump(KLogDir, KLogName, \ + EFileLoggingModeAppend, _S(""), _S(""), \ + buffer.Ptr(), buffer.Length()); +#define LOGFMT(string, value) \ + RFileLogger::WriteFormat(KLogDir, KLogName, \ + EFileLoggingModeAppend, string, value); +#else +#define LOG +#define LOGHEX +#define LOGFMT +#endif + +// LOCAL CONSTANTS AND MACROS + +_LIT8(KWrapIv, "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6"); + +// LOCAL FUNCTION PROTOTYPES +LOCAL_C void DeleteObject( TAny* aObject ); + +// FORWARD DECLARATIONS + +// ============================= LOCAL FUNCTIONS =============================== + +// ---------------------------------------------------------------------------- +// DeleteObject +// Deletes the file by TFileName presented by aHandle +// ---------------------------------------------------------------------------- +// +LOCAL_C void DeleteObject( TAny* aObject ) + { + __ASSERT_DEBUG( aObject, User::Panic( _L( "DeleteObject" ), KErrArgument ) ); + MDrmKeyStorage* object = reinterpret_cast< MDrmKeyStorage* >( aObject ); + delete object; + object = NULL; + } + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void OmaCrypto::WriteUint32ToBlock( + TUint32 aInt, + TDes8& aBlock, + TInt aOffset) + { + aBlock[aOffset] = (aInt & 0xff000000) >> 24; + aBlock[aOffset + 1] = (aInt & 0x00ff0000) >> 16; + aBlock[aOffset + 2] = (aInt & 0x0000ff00) >> 8; + aBlock[aOffset + 3] = (aInt & 0x000000ff); + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::RsaDecryptL( + MDrmKeyStorage* aKeyStorage, + const TDesC8& aInput) + { + return aKeyStorage->RsaDecryptL(aInput); + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::RsaEncryptL( + CRSAPublicKey* aKey, + const TDesC8& aInput) + { + RInteger result; + RInteger input; + HBufC8* output; + + input = OS2IPL(aInput); + CleanupClosePushL(input); + result = TInteger::ModularExponentiateL(input, aKey->E(), aKey->N()); + CleanupClosePushL(result); + output = I2OSPL(result); + +#ifdef LOGGING + HBufC8* buffer = NULL; + LOG(_L8("RsaEncryptL")); + LOG(_L8("Input")); + LOGHEX(aInput); + buffer = aKey->E().BufferLC(); + LOG(_L8("E")); + LOGHEX((*buffer)); + CleanupStack::PopAndDestroy(buffer); + buffer = aKey->N().BufferLC(); + LOG(_L8("N")); + LOGHEX((*buffer)); + CleanupStack::PopAndDestroy(buffer); + LOG(_L8("Result")); + LOGHEX((*output)); +#endif + + CleanupStack::PopAndDestroy(2); // result, input + return output; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::RsaVerifyL( + CRSAPublicKey* aKey, + const TDesC8& aInput) + { + RInteger result; + RInteger input; + HBufC8* output; + + input = OS2IPL(aInput); + CleanupClosePushL(input); + result = TInteger::ModularExponentiateL(input, aKey->E(), aKey->N()); + CleanupClosePushL(result); + output = I2OSPL(result); + CleanupStack::PopAndDestroy(2); // result, input + return output; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::RsaKemKwsEncryptL( + CRSAPublicKey* aKey, + const TDesC8& aRek, + const TDesC8& aMac) + { + HBufC8* C1 = NULL; + HBufC8* C2 = NULL; + HBufC8* C; + TPtr8 c(0, 0); + TBuf8<128> Z; + TBuf8 keyAndMac; + HBufC8* kek = NULL; + const TUint8 KFirstBitMask( 0x7f ); + + Z.SetLength(128); + MDrmKeyStorage* storage = DrmKeyStorageNewL(); + TCleanupItem storageCleanup( DeleteObject, storage ); + CleanupStack::PushL(storageCleanup); + storage->RandomDataGetL(Z,Z.Size()); + CleanupStack::PopAndDestroy( storage ); + + Z[0] &= KFirstBitMask; + +#ifdef LOGGING + LOG(_L("RsaKemKwsEncryptL")); + LOG(_L("random Z")); + LOGHEX(Z); +#endif + C1 = RsaEncryptL(aKey, Z); + CleanupStack::PushL(C1); + kek = KdfL(Z, KNullDesC8, KKeySize); + CleanupStack::PushL(kek); + keyAndMac.Copy(aMac); + keyAndMac.Append(aRek); + C2 = AesWrapL(*kek, keyAndMac); + CleanupStack::PushL(C2); + C = HBufC8::NewL(C1->Length() + C2->Length()); + c.Set(C->Des()); + c.Copy(*C1); + c.Append(*C2); + +#ifdef LOGGING + LOG(_L("RsaKemKwsEncryptL")); + LOG(_L("Z")); + LOGHEX(Z); + LOG(_L("C1")); + LOGHEX((*C1)); + LOG(_L("C2")); + LOGHEX((*C2)); +#endif + + CleanupStack::PopAndDestroy(3); // C2, kek, C1 + return C; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C void OmaCrypto::RsaKemKwsDecryptL( + MDrmKeyStorage* aKeyStorage, + const TDesC8& aInput, + TDes8& aRek, + TDes8& aMac) + { + HBufC8* C1 = NULL; + HBufC8* C2 = NULL; + HBufC8* Z = NULL; + HBufC8* keyAndMac = NULL; + HBufC8* kek = NULL; + + C1 = aInput.Left(aInput.Length() - KWrappedKeySize).AllocL(); + CleanupStack::PushL(C1); + C2 = aInput.Right(KWrappedKeySize).AllocL(); + CleanupStack::PushL(C2); + Z = aKeyStorage->RsaDecryptL(*C1); + CleanupStack::PushL(Z); + kek = KdfL(*Z, KNullDesC8, KKeySize); + CleanupStack::PushL(kek); + keyAndMac = AesUnwrapL(*kek, *C2); + aMac.Copy(keyAndMac->Left(KKeySize)); + aRek.Copy(keyAndMac->Right(KMacSize)); + +#ifdef LOGGING + LOG(_L("RsaKemKwsDecryptL")); + LOG(_L("Z")); + LOGHEX((*Z)); + LOG(_L("C1")); + LOGHEX((*C1)); + LOG(_L("C2")); + LOGHEX((*C2)); + LOG(_L("REK + MAC")); + LOGHEX((*keyAndMac)); + LOG(_L("KEK")); + LOGHEX((*kek)); +#endif + + delete keyAndMac; + CleanupStack::PopAndDestroy(4); // kek, Z, C2, C1 + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::KdfL( + const TDesC8& aInput, + const TDesC8& aOtherData, + TInt aKLen) + { + TUint32 d; + CSHA1* h = NULL; + TBuf8 c; + HBufC8* t = NULL; + HBufC8* r = NULL; + TPtr8 T(0, 0); + + h = CSHA1::NewL(); + CleanupStack::PushL(h); + t = HBufC8::NewL(aKLen + SHA1_HASH); + CleanupStack::PushL(t); + T.Set(t->Des()); + c.SetLength(sizeof(d)); + d = 1; + do + { + WriteUint32ToBlock(d, c, 0); + h->Hash(aInput); + h->Hash(c); + if (aOtherData.Length() > 0) + { + h->Hash(aOtherData); + } + T.Append(h->Final()); + d++; + } + while (d < SHA1_HASH / aKLen); + r = t->Left(aKLen).AllocL(); + CleanupStack::PopAndDestroy(2); // Tbuf, h + return r; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::I2OSPL( + RInteger& aInt) + { + HBufC8* r = aInt.BufferLC(); + CleanupStack::Pop(r); + return r; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C RInteger OmaCrypto::OS2IPL( + const TDesC8& aOctetStream) + { + RInteger r; + TInt i; + + r = RInteger::NewL(0); + for (i = 0; i < aOctetStream.Length(); i++) + { + r *= 256; + r += aOctetStream[i]; + } + return r; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::AesWrapL( + const TDesC8& aKey, + const TDesC8& aInput) + { + HBufC8* ret = NULL; + TBuf8 A; + TBuf8<2 * KWrapBlockSize> B; + TInt i; + TInt j; + TPtr8 R(0, 0); + TPtr8 Rn(0, 0); + TInt t; + TInt n; + CAESEncryptor* e; + + e = CAESEncryptor::NewL(aKey); + User::LeaveIfNull(e); + CleanupStack::PushL(e); + n = aInput.Length() / KWrapBlockSize; + ret = HBufC8::NewMax((n + 1) * KWrapBlockSize); + User::LeaveIfNull(ret); + R.Set(ret->Des()); + A.Copy(KWrapIv); + R.Copy(A); + R.Append(aInput); + for (j = 0; j <= 5; j++) + { + for (i = 1; i <= n; i++) + { + t = (n * j) + i; + Rn.Set(const_cast(R.Ptr()) + KWrapBlockSize * i, + KWrapBlockSize, KWrapBlockSize); + B.Copy(A); + B.Append(Rn); + e->Transform(B); + A.Copy(B.Left(KWrapBlockSize)); + A[KWrapBlockSize - 1] ^= t; + Rn.Copy(B.Right(KWrapBlockSize)); + } + } + Rn.Set(const_cast(R.Ptr()), KWrapBlockSize, KWrapBlockSize); + Rn.Copy(A); + CleanupStack::PopAndDestroy(); // e + return ret; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::AesUnwrapL( + const TDesC8& aKey, + const TDesC8& aInput) + { + HBufC8* ret = NULL; + TBuf8 A; + TBuf8<2 * KWrapBlockSize> B; + TInt i; + TInt j; + TPtr8 R(0, 0); + TPtr8 Rn(0, 0); + TInt t; + TInt n; + CAESDecryptor* d; + + d = CAESDecryptor::NewL(aKey); + User::LeaveIfNull(d); + CleanupStack::PushL(d); + n = (aInput.Length() / KWrapBlockSize) - 1; + ret = HBufC8::NewMax((n + 1) * KWrapBlockSize); + User::LeaveIfNull(ret); + R.Set(ret->Des()); + A.Copy(aInput.Left(KWrapBlockSize)); + R.Copy(aInput); + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + t = (n * j) + i; + Rn.Set(const_cast(R.Ptr()) + KWrapBlockSize * i, + KWrapBlockSize, KWrapBlockSize); + A[KWrapBlockSize - 1] ^= t; + B.Copy(A); + B.Append(Rn); + d->Transform(B); + A.Copy(B.Left(KWrapBlockSize)); + Rn.Copy(B.Right(KWrapBlockSize)); + } + } + R.Delete(0, KWrapBlockSize); + CleanupStack::PopAndDestroy(); // e + +#ifdef LOGGING + LOG(_L("OmaCrypto::AesUnwrapL")); + LOG(_L("Key:")); + LOGHEX(aKey); + LOG(_L("Input:")); + LOGHEX(aInput); + LOG(_L("Ret:")); + LOGHEX((*ret)); +#endif + + return ret; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::Mgf1L( + const TDesC8& aMfgSeed, + TInt aMaskLen) + { + TUint32 c; + CSHA1* h = NULL; + TBuf8<4> counter; + HBufC8* t = NULL; + TPtr8 T(0, 0); + TInt n; + + n = aMaskLen / SHA1_HASH + (aMaskLen % SHA1_HASH ? 1 : 0); + h = CSHA1::NewL(); + CleanupStack::PushL(h); + t = HBufC8::NewL(aMaskLen + 2 * SHA1_HASH + 1); + CleanupStack::PushL(t); + T.Set(t->Des()); + counter.SetLength(4); + c = 0; + do + { + WriteUint32ToBlock(c, counter, 0); + h->Hash(aMfgSeed); + h->Hash(counter); + T.Append(h->Final()); + c++; + } + while (c < n); + T.SetLength(aMaskLen); + CleanupStack::Pop(); // t + CleanupStack::PopAndDestroy(); // h + return t; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto::RsaPssSignHashL +// Sign a hash (not a message!) using RSASSA-PSS. +// NOTE: The implementation is only correct for a private key modulus divisible +// by eight! +// ----------------------------------------------------------------------------- +// +EXPORT_C HBufC8* OmaCrypto::RsaPssSignHashL( + MDrmKeyStorage* aKeyStorage, + const TDesC8& aMHash) + { + CSHA1* hasher = NULL; + HBufC8* em = NULL; + HBufC8* S = NULL; + TPtr8 EM(0, 0); + TInt modBits; + TInt emLen; + TBuf8 salt; + TBuf8 H; + _LIT8(KMNullVector, "\0\0\0\0\0\0\0\0"); + HBufC8* db = NULL; + TPtr8 DB(0, 0); + HBufC8* dbMask = NULL; + TInt i; + + modBits = aKeyStorage->ModulusSize(); + + if( modBits < 0) + { + User::LeaveIfError( modBits ); + } + emLen = modBits / 8; + hasher = CSHA1::NewL(); + CleanupStack::PushL(hasher); + + salt.SetLength(KPssSaltLength); + + aKeyStorage->RandomDataGetL(salt,salt.Size()); + +#ifdef LOGGING + LOG(_L("RsaKemKwsEncryptL")); + LOG(_L("salt")); + LOGHEX(salt); +#endif + + hasher->Hash(KMNullVector); + hasher->Hash(aMHash); + hasher->Hash(salt); + H.Copy(hasher->Final()); + + db = HBufC8::NewL(emLen - SHA1_HASH - 1); + CleanupStack::PushL(db); + DB.Set(db->Des()); + DB.FillZ(emLen - KPssSaltLength - SHA1_HASH - 2); + DB.Append(0x01); + DB.Append(salt); + + dbMask = Mgf1L(H, emLen - SHA1_HASH - 1); + CleanupStack::PushL(dbMask); + + for (i = 0; i < emLen - SHA1_HASH - 1; i++) + { + DB[i] = DB[i] ^ (*dbMask)[i]; + } + + em = HBufC8::NewL(emLen); + CleanupStack::PushL(em); + EM.Set(em->Des()); + EM.Copy(DB); + EM[0] &= 0x7f; + EM.Append(H); + EM.Append(0xbc); + S = aKeyStorage->RsaSignL(EM); + + CleanupStack::PopAndDestroy(4); // em, dbMask, db, hasher + return S; + } + +// ----------------------------------------------------------------------------- +// OmaCrypto:: +// +// ----------------------------------------------------------------------------- +// +EXPORT_C TBool OmaCrypto::RsaPssVerifyHashL( + CRSAPublicKey* aKey, + const TDesC8& aSignature, + const TDesC8& aMHash) + { + TBool r = EFalse; + CSHA1* hasher = NULL; + HBufC8* EM = NULL; + TInt emLen; + TBuf8 salt; + TBuf8 H; + _LIT8(KMNullVector, "\0\0\0\0\0\0\0\0"); + HBufC8* db = NULL; + TPtr8 DB(0, 0); + HBufC8* dbMask = NULL; + TInt i; + + EM = RsaVerifyL(aKey, aSignature); + CleanupStack::PushL(EM); + emLen = EM->Size(); + + hasher = CSHA1::NewL(); + CleanupStack::PushL(hasher); + + db = EM->Left(emLen - SHA1_HASH - 1).AllocL(); + CleanupStack::PushL(db); + DB.Set(db->Des()); + H.Copy(EM->Mid(emLen - SHA1_HASH - 1, SHA1_HASH)); + + dbMask = Mgf1L(H, emLen - SHA1_HASH - 1); + CleanupStack::PushL(dbMask); + + for (i = 0; i < emLen - SHA1_HASH - 1; i++) + { + DB[i] = DB[i] ^ (*dbMask)[i]; + } + + salt.Copy(DB.Right(KPssSaltLength)); + + hasher->Hash(KMNullVector); + hasher->Hash(aMHash); + hasher->Hash(salt); + if (hasher->Final().Compare(H) == 0) + { + r = ETrue; + } + + CleanupStack::PopAndDestroy(4); // dbMask, db, hasher, EM + return r; + } + +// End of File