omadrm/drmengine/agentv2/src/DcfCache.cpp
changeset 0 95b198f216e5
child 12 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/agentv2/src/DcfCache.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,552 @@
+/*
+* Copyright (c) 2002-2009 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:  Implementation of the DCF cache class
+*
+*/
+
+// INCLUDE FILES
+#include <f32file.h>
+#include <e32base.h>
+#include <symmetric.h>
+#include <rijndael.h>
+#include "DcfCache.h"
+#include "DcfCommon.h"
+#include "DrmRightsClient.h"
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CDcfCache::CDcfCache
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+#ifdef ASYNC_READ
+
+CDcfCache::CDcfCache(
+    RDRMRightsClient& aRightsClient,
+    RFile& aFile,
+    CDcfCommon& aDcf,
+    TInt aPageSize,
+    TInt aPageCount ) :
+CActive( CActive::EPriorityStandard ),
+iFile( aFile ),
+iRightsClient(aRightsClient ),
+iDcf( aDcf ),
+iPageSize( aPageSize ),
+iPageCount( aPageCount ),
+iDecryptionMode( EServerSide ),
+iDes( 0 ),
+iAsyncReadingOngoing( EFalse )
+    {
+    }
+
+#else
+
+CDcfCache::CDcfCache(
+    RDRMRightsClient& aRightsClient,
+    RFile& aFile,
+    CDcfCommon& aDcf,
+    TInt aPageSize,
+    TInt aPageCount ) :
+iFile( aFile ),
+iRightsClient( aRightsClient ),
+iDcf( aDcf ),
+iPageSize( aPageSize ),
+iPageCount( aPageCount ),
+iDecryptionMode( EServerSide )
+    {
+    }
+#endif
+// -----------------------------------------------------------------------------
+// CDcfCache::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::ConstructL()
+    {
+    for ( TInt i = 0; i < iPageCount; i++ )
+        {
+        iPage.AppendL( new ( ELeave ) TUint8[iPageSize] );
+        iPageUsageCount.AppendL( -1 );
+        iPagePosition.AppendL( -1 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CDcfCache* CDcfCache::NewL( RDRMRightsClient& aRightsClient, RFile& aFile,
+    CDcfCommon& aDcf, TInt aPageSize, TInt aPageCount )
+    {
+    CDcfCache* self = new ( ELeave ) CDcfCache( aRightsClient, aFile, aDcf,
+        aPageSize, aPageCount );
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::~CDcfCache
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CDcfCache::~CDcfCache()
+    {
+
+#ifdef ASYNC_READ
+    if ( IsActive() )
+        {
+        if ( iAsyncReadingOngoing )
+            {
+            Cancel();
+            }
+        else
+            {
+            TRequestStatus* status = &iStatus;
+            User::RequestComplete( status, KErrNone );
+            Cancel();
+            }
+        }
+#endif
+
+    iPage.ResetAndDestroy();
+    iPage.Close();
+    iPagePosition.Close();
+    iPageUsageCount.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::Read
+// -----------------------------------------------------------------------------
+//
+TInt CDcfCache::Read( TInt& aPos, TDes8& aDes, TInt aLength )
+    {
+    TInt r = KErrNone;
+
+    // Check that the position is valid and the length is valid
+    if ( aPos < 0 || aLength < 0 )
+        {
+        return KErrArgument;
+        }
+
+    if ( iPageCount > 0 )
+        {
+        TRAP(r, CachedReadL(aPos, aDes, aLength));
+        }
+    else
+        {
+        TRAP(r, UncachedReadL(aPos, aDes, aLength));
+        }
+    if ( r != KErrNone )
+        {
+        RDebug::Printf( "CDcfCache::Read error: %d", r );
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::Read
+// -----------------------------------------------------------------------------
+//
+
+#ifdef ASYNC_READ
+
+TInt CDcfCache::Read( TInt aPos, TDes8& aDes, TInt aLength,
+    TRequestStatus& aStatus )
+    {
+
+    // Check that the position is valid and the length is valid
+    if ( aPos < 0 || aLength < 0 )
+        {
+        return KErrArgument;
+        }
+
+    if ( !IsAdded() )
+        {
+        CActiveScheduler::Add( this );
+        }
+
+    if ( iAsyncReadingOngoing )
+        {
+        return KErrInUse;
+        }
+
+    iError = KErrNone;
+
+    iAsyncReadingOngoing = ETrue;
+
+    iPos = aPos;
+    iLength = aLength;
+    iDes = &aDes;
+    iOperation = EPosRead;
+
+    iAsyncStatus = &aStatus;
+    *iAsyncStatus = KRequestPending;
+
+    TRequestStatus* ownStatus = &iStatus;
+    *ownStatus = KRequestPending;
+
+    SetActive();
+    User::RequestComplete( ownStatus, KErrNone );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::ReadCancel
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::ReadCancel( TRequestStatus& aStatus )
+    {
+    // only cancel if needed
+    TRequestStatus* status( &aStatus );
+    if ( IsActive() && iAsyncStatus == status )
+        {
+        if ( iAsyncReadingOngoing )
+            {
+            Cancel();
+            iAsyncReadingOngoing = EFalse;
+            iAsyncStatus = NULL;
+            User::RequestComplete( status, KErrCancel );
+            }
+        }
+    }
+
+#endif
+
+// -----------------------------------------------------------------------------
+// CDcfCache::CachedReadL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::CachedReadL( TInt& aPos, TDes8& aDes, TInt aLength )
+    {
+    TInt i;
+
+    // Check that the position is valid and the length is valid
+    if ( aPos < 0 || aLength < 0 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    aDes.SetLength( 0 );
+    while ( aLength > 0 )
+        {
+        for ( i = 0; aLength > 0 && i < iPageCount; i++ )
+            {
+            if ( InPage( i, aPos ) )
+                {
+                CopyOut( i, aDes, aPos, aLength );
+                }
+            }
+        if ( i == iPageCount && aLength > 0 )
+            {
+            i = GetFreePage();
+            if ( iDcf.iEncryptionMethod == EMethodAES_128_CBC )
+                {
+                ReadAndDecryptPageL( i, aPos );
+                CopyOut( i, aDes, aPos, aLength );
+                }
+            else
+                {
+                ReadPageL( i, aPos );
+                CopyOut( i, aDes, aPos, aLength );
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::UncachedReadL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::UncachedReadL( TInt& aPos, TDes8& aDes, TInt aLength )
+    {
+    HBufC8* buffer = NULL;
+    TPtr8 ptr( NULL, 0 );
+    TBuf8<KDCFKeySize> iv;
+    TInt pos;
+    TInt length;
+
+    // Check that the position is valid and the length is valid
+    if ( aPos < 0 || aLength < 0 )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    if ( aPos + aLength > iDcf.iPlainTextLength )
+        {
+        if ( aPos < iDcf.iPlainTextLength )
+            {
+            aLength = iDcf.iPlainTextLength - aPos;
+            }
+        else
+            {
+            aLength = 0;
+            }
+        }
+
+    if ( iDcf.iEncryptionMethod == EMethodAES_128_CBC )
+        {
+
+        // Nothing to read:
+        if ( aLength == 0 )
+            {
+            aDes.SetLength( aLength );
+            return;
+            }
+
+        buffer = HBufC8::NewLC( aLength + 2 * KDCFKeySize );
+        ptr.Set( buffer->Des() );
+        pos = ( ( aPos / KDCFKeySize ) * KDCFKeySize ) + iDcf.iOffset;
+        User::LeaveIfError( iFile.Read( pos, iv, KDCFKeySize ) );
+        length = ( ( aLength / KDCFKeySize ) * KDCFKeySize ) + 2
+            * KDCFKeySize;
+        User::LeaveIfError( iFile.Read( ptr, length ) );
+
+        // Make sure we have the correct amount of data
+        if ( ptr.Length() % KDCFKeySize )
+            {
+            length = ( ( ptr.Length() / KDCFKeySize ) * KDCFKeySize );
+            ptr.SetLength( length );
+            }
+
+        // If not enough was read to get any content return an empty descriptor
+        if ( ptr.Length() == 0 )
+            {
+            aDes.SetLength( 0 );
+            CleanupStack::PopAndDestroy( buffer );
+            return;
+            }
+
+        DecryptL( iv, ptr );
+        length = Min( aDes.MaxLength(), ptr.Length() - aPos % KDCFKeySize );
+        aDes.Copy( ptr.Mid( aPos % KDCFKeySize, length ) );
+        if ( aDes.Length() > aLength )
+            {
+            aDes.SetLength( aLength );
+            }
+        CleanupStack::PopAndDestroy( buffer );
+        }
+    else
+        {
+        User::LeaveIfError( iFile.Read( aPos + iDcf.iOffset, aDes, aLength ) );
+        }
+    aPos += aDes.Length();
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::GetFreePage
+// -----------------------------------------------------------------------------
+//
+TInt CDcfCache::GetFreePage()
+    {
+    TInt i;
+    TInt n = -1;
+    TUint c = KMaxTUint32;
+
+    for ( i = 0; i < iPageCount; i++ )
+        {
+        if ( iPageUsageCount[i] == -1 )
+            {
+            n = i;
+            break;
+            }
+        else if ( iPageUsageCount[i] < c )
+            {
+            c = iPageUsageCount[i];
+            n = i;
+            }
+        }
+    return n;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::ReadPageL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::ReadPageL( TInt aPage, TInt aPosition )
+    {
+    TInt pos;
+    TBuf8<KDCFKeySize> iv;
+
+    iPageUsageCount[aPage] = 0;
+    iPagePosition[aPage] = ( aPosition / iPageSize ) * iPageSize;
+    pos = iPagePosition[aPage] + iDcf.iOffset;
+    iFile.Seek( ESeekStart, pos );
+    TPtr8 ptr( iPage[aPage], iPageSize );
+    User::LeaveIfError( iFile.Read( ptr ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::ReadAndDecryptPageL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::ReadAndDecryptPageL( TInt aPage, TInt aPosition )
+    {
+    TInt pos;
+    TBuf8<KDCFKeySize> iv;
+
+    iPageUsageCount[aPage] = 0;
+    iPagePosition[aPage] = ( aPosition / iPageSize ) * iPageSize;
+    pos = iPagePosition[aPage] + iDcf.iOffset;
+    User::LeaveIfError( iFile.Seek( ESeekStart, pos ) );
+    User::LeaveIfError( iFile.Read( iv ) );
+    TPtr8 ptr( iPage[aPage], iPageSize );
+    pos += KDCFKeySize;
+    User::LeaveIfError( iFile.Read( ptr ) );
+    ptr.SetLength( iPageSize );
+    DecryptL( iv, ptr );
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::CopyOut
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::CopyOut( TInt aPage, TDes8& aDes, TInt& aPosition,
+    TInt& aLength )
+    {
+    TInt n;
+    TInt offset;
+
+    aLength = Min( aLength, iDcf.iPlainTextLength - aPosition );
+    aLength = Min( aLength, aDes.MaxLength() - aDes.Length() );
+    offset = aPosition - iPagePosition[aPage];
+    n = Min( aLength, iPageSize - offset );
+    aDes.Append( iPage[aPage] + offset, n );
+    aLength -= n;
+    aPosition += n;
+    iPageUsageCount[aPage]++;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::InPage
+// -----------------------------------------------------------------------------
+//
+TBool CDcfCache::InPage( TInt aPage, TInt aPosition )
+    {
+    return iPagePosition[aPage] != -1 && iPagePosition[aPage] <= aPosition
+        && aPosition < iPagePosition[aPage] + iPageSize ? ETrue : EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::SetKey
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::SetKey( const TDesC8& aKey )
+    {
+    iKey.Copy( aKey );
+    iDecryptionMode = EClientSide;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::DecryptL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::DecryptL( const TDesC8& aIv, TPtr8& aPtr )
+    {
+    if ( iDecryptionMode == EClientSide )
+        {
+        CModeCBCDecryptor* cbc( NULL );
+        CAESDecryptor* aes( CAESDecryptor::NewLC( iKey ) );
+        cbc = CModeCBCDecryptor::NewL( aes, aIv );
+        CleanupStack::Pop( aes );
+        aes = NULL;
+        CleanupStack::PushL( cbc );
+        for ( TInt count = 0; count < aPtr.Length(); count += KDCFKeySize )
+            {
+            TPtr8 d( aPtr.MidTPtr( count, KDCFKeySize ) );
+            cbc->Transform( d );
+            }
+        CleanupStack::PopAndDestroy( cbc );
+        }
+    else
+        {
+        User::LeaveIfError( iRightsClient.Decrypt( aIv, aPtr ) );
+        }
+    }
+
+#ifdef ASYNC_READ
+
+// -----------------------------------------------------------------------------
+// CDcfCache::RunL
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::RunL()
+    {
+
+    switch ( iOperation )
+        {
+        case ENonPosRead:
+            {
+            break;
+            }
+
+        case EPosRead:
+            {
+            ReadAsyncL();
+            iAsyncReadingOngoing = EFalse;
+            User::RequestComplete( iAsyncStatus, KErrNone );
+            iAsyncStatus = NULL;
+            break;
+            }
+
+        default:
+            {
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::DoCancel
+// -----------------------------------------------------------------------------
+//
+void CDcfCache::DoCancel()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::RunError
+// -----------------------------------------------------------------------------
+//
+TInt CDcfCache::RunError( TInt aError )
+    {
+    iError = aError;
+    User::RequestComplete( iAsyncStatus, iError );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CDcfCache::ReadAsyncL
+// -----------------------------------------------------------------------------
+//
+
+void CDcfCache::ReadAsyncL()
+    {
+    if ( iPageCount > 0 )
+        {
+        TRAP(iError, CachedReadL(iPos, *iDes, iLength));
+        }
+    else
+        {
+        TRAP(iError, UncachedReadL(iPos, *iDes, iLength));
+        }
+    }
+#endif //ASYNC_READ
+//  End of File