omadrm/drmengine/drmcrypto/src/OmaCrypto.cpp
changeset 0 95b198f216e5
--- /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 <e32std.h>
+#include <asymmetric.h>
+#include <symmetric.h>
+#include <hash.h>
+#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<KKeySize + KMacSize> 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<sizeof(d)> 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<KWrapBlockSize> 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<TUint8*>(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<TUint8*>(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<KWrapBlockSize> 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<TUint8*>(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<KPssSaltLength> salt;
+    TBuf8<SHA1_HASH> 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<KPssSaltLength> salt;
+    TBuf8<SHA1_HASH> 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