wmdrm/wmdrmengine/wmdrmserver/server/src/slotdata.cpp
author Pat Downey <patd@symbian.org>
Fri, 12 Feb 2010 14:30:27 +0000
changeset 9 ce0d1c675e43
parent 0 95b198f216e5
permissions -rw-r--r--
Minor update.

/*
* Copyright (c) 2007 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:  WMDRM Server implementation
*
*/


#include <ezlib.h>
#include <e32math.h>
#include <symmetric.h>
#include <bacntf.h>
#include <random.h>

#include "wmdrmkeystorage.h"
#include "slotdata.h"
#include "wmdrmserver.h"
#include "slotdatacache.h"
#include "slotenumeratorcache.h"
#include "wmdrmdb.h"

#define _LOGGING_FILE L"wmdrmserver.txt"

#include "flogger.h"
#include "logfn.h"

#ifdef __WINSCW__
_LIT8( KDummyKey, "0123456789012345" );
#endif

CSlotData* CSlotData::NewL( 
    CWmDrmServer* aServer, 
    const TDesC8& aStore,
    const TDesC8& aNamespace,
    const TDesC8& aHashKey,
    const TDesC8& aUniqueKey )
    {
    LOGFN( "CSlotData::NewL" );
    CSlotData* self = new (ELeave) CSlotData( aServer,
                                              aStore,
                                              aNamespace,
                                              aHashKey,
                                              aUniqueKey );
    return self;
    }

CSlotData::CSlotData( 
    CWmDrmServer* aServer, 
    const TDesC8& aStore,
    const TDesC8& aNamespace,
    const TDesC8& aHashKey,
    const TDesC8& aUniqueKey ) : iServer( aServer ),
                                 iDirty( EFalse ),
                                 iExists( ETrue ),
                                 iReferences( 0 )
    {
    LOGFN( "CSlotData::CSlotData" );
    iStore.Copy( aStore );
    iNamespace.Copy( aNamespace );
    LOG( iNamespace );
    iHashKey.Copy( aHashKey );
    LOG( iHashKey );
    iUniqueKey.Copy( aUniqueKey );
    LOG( iUniqueKey );
    }

CSlotData::~CSlotData()
    {
    LOGFN( "CSlotData::~CSlotData" );
    //FlushL();
    iData.Close();
    }

void CSlotData::CreateL( TInt& aInitialSize )
    {
    LOGFN( "CSlotData::CreateL" );
    LOG2( "Size: %d", aInitialSize );
    LOG1( "*** Create record" );
    if ( aInitialSize > KMaxSlotSize )
        {
        User::Leave( KErrArgument );
        }
	iServer->Db()->CreateRecordL( iStore, iNamespace, iHashKey, iUniqueKey, aInitialSize );
    iData.Close();
    iData.CreateL( aInitialSize );
    iData.SetLength( iData.MaxLength() );
    iData.FillZ();
    iDirty = ETrue;
    iExists = ETrue;
    iOpen = ETrue;
	iServer->EnumeratorCache()->AddEntryL( iStore, iNamespace, iHashKey, iUniqueKey );
    //FlushL();
    }

TInt CSlotData::OpenL( TInt& aCurrentSize )
    {
    TInt r = KErrNone;
    RBuf8 compressedData;
    TUint32 uncompressedSize;
    TPckg<TUint32> pckg( uncompressedSize );
    RBuf8 encryptedData;
    CBufferedDecryptor* decryptor = NULL;
    CModeCBCDecryptor* cbcDecryptor = NULL;
    CAESDecryptor* aesDecryptor = NULL;
    CPaddingPKCS7* padding = NULL;
    TInt size;
    
    LOGFN( "CSlotData::OpenL" );
	LOG3( "Size: %d, data size: %d", aCurrentSize, iData.Length() );
	if ( !IsOpen() )
	    {
	    if ( iExists )
	        {
    	    LOG1( "*** Opening record" );
            TRAP( r, iServer->Db()->ReadRecordL( iStore, iNamespace, iHashKey, iUniqueKey ) );
    	    if ( !r )
    	        {
    	        TBuf8<KAESKeyLength> key;
    	        TBuf8<KAESKeyLength> iv;
                RBuf8 buffer;

                iServer->Db()->GetDataSizeL( size );
                LOG2( "Record size: %d", size );
                if( size <= 0 )
                    {
                    iServer->Db()->DeleteData();
                    iServer->Db()->DeleteRecordL( iStore, iNamespace, iHashKey, iUniqueKey );
                    User::Leave( KErrArgument );
                    }
                    
                encryptedData.CreateL( size - sizeof( TUint32 ) - KAESKeyLength );
                encryptedData.CleanupClosePushL();
                
                compressedData.CreateL( size - sizeof( TUint32 ) - KAESKeyLength );
                compressedData.CleanupClosePushL();
                

                buffer.CreateL( size );
                buffer.CleanupClosePushL();
                iServer->Db()->ReadDataL( buffer );
                //LOGHEX( buffer.Ptr(), buffer.Size() );
                pckg.Copy( buffer.Left( sizeof( TUint32 ) ) );
                LOG2( "Uncompressed size: %d", uncompressedSize );
                iv.Copy( buffer.Mid ( sizeof( TUint32 ), KAESKeyLength ) );
                //LOGHEX( iv.Ptr(), iv.Size () );
                encryptedData.Copy( buffer.Right( size - sizeof( TUint32 ) - KAESKeyLength ) );
                //LOGHEX( encryptedData.Ptr(), encryptedData.Size() );
#ifdef __WINSCW__
                key.Copy( KDummyKey );
#else
                iServer->Cache()->iKeyStorage->GetDeviceSpecificKeyL( key );
#endif
                aesDecryptor = CAESDecryptor::NewL( key );
                CleanupStack::PushL( aesDecryptor );
                
                cbcDecryptor = CModeCBCDecryptor::NewL( aesDecryptor, iv );
                CleanupStack::Pop( aesDecryptor );
                CleanupStack::PushL( cbcDecryptor );
                
                padding = CPaddingPKCS7::NewL( KAESKeyLength );
                CleanupStack::PushL( padding );
                
                decryptor = CBufferedDecryptor::NewL( cbcDecryptor, padding );
                CleanupStack::Pop( 2, cbcDecryptor ); //padding, cbcDecryptor
                CleanupStack::PushL( decryptor );

                decryptor->ProcessFinalL( encryptedData, compressedData );

                iData.Close();
                iData.CreateMaxL( uncompressedSize );
                User::LeaveIfError( uncompress( const_cast<TUint8*>( iData.Ptr() ), &uncompressedSize, 
                                                                     compressedData.Ptr(), compressedData.Size() ) );
                CleanupStack::PopAndDestroy( 4, &encryptedData ); //decryptor, buffer, compressedData, encryptedData
                TRandom::RandomL( key );
                iOpen = ETrue;
                }
            else 
                {
                iExists = EFalse;
                if ( r == KErrPathNotFound )
                    {
                    r = KErrNotFound;
                    }
                }
            }
        else
            {
            r = KErrNotFound;
            }
        }
	else
	    {
	    LOG1( "Record already open" );
	    }
    aCurrentSize = iData.Length();

    return r;
    }

TInt CSlotData::Read( TInt aPosition, TDes8& aBuffer )
    {
    TInt r = KErrNone;
    TInt length;

    LOGFNR( "CSlotData::Read", r );
	if ( IsOpen() )
	    {
	    length = Min( aBuffer.MaxLength(), iData.Length() - aPosition );
	    LOG4( "Read %d bytes from %d, buffer size: %d", length, aPosition, aBuffer.MaxLength() );
        aBuffer.Copy( iData.Mid( aPosition, length ) );
//        LOGHEX( aBuffer.Ptr(), aBuffer.Size() );
        }
    else
        {
        r = KErrNotReady;
        iServer->Cache()->Release( this );
        }
    return r;
    }

TInt CSlotData::WriteL( TInt aPosition, const TDesC8& aBuffer )
    {
    TInt r = KErrNone;

	LOGFNR( "CSlotData::Write", r );
	if ( IsOpen() )
	    {
	    LOG3( "Write %d bytes at %d", aBuffer.Length(), aPosition );
//        LOGHEX( aBuffer.Ptr(), aBuffer.Size() );
	    if ( aBuffer.Length() + aPosition > iData.Length() )
	        {
	        iData.ReAllocL( aBuffer.Length() + aPosition );
	        iData.SetLength( iData.MaxLength() );
	        }
	    iData.Replace( aPosition, aBuffer.Length(), aBuffer );
	    iDirty = ETrue;
	    FlushL();
        }
    else
        {
        r = KErrNotReady;
        iServer->Cache()->Release( this );
        }
    return r;
    }

TInt CSlotData::ResizeL( TInt aNewSize )
    {
    TInt r = KErrNone;

	LOGFNR( "CSlotData::Resize", r );
	if ( IsOpen() )
        {
    	LOG2( "New size: %d", aNewSize );
    	if ( aNewSize > iData.Size() )
    	    {
            iData.ReAllocL( aNewSize );
            }
        iData.SetLength( aNewSize );
        }
    else
        {
        r = KErrNotReady;
        iServer->Cache()->Release( this );
        }
    return r;
    }

TInt CSlotData::DeleteL()
    {
    TInt r = KErrNone;
    
	LOGFNR( "CSlotData::Delete", r );
	iServer->EnumeratorCache()->DeleteEntryL( iStore, iNamespace, iHashKey, iUniqueKey );
	r = iServer->Cache()->Delete( this );
	return r;
    }

TInt CSlotData::Size()
    {
    TInt r;
    
    LOGFNR( "CSlotData::Size", r );
	if ( IsOpen() )
	    {
	    r = iData.Length();
	    }
    else
        {
        r = KErrNotReady;
        iServer->Cache()->Release( this );
        }
	return r;
    }

void CSlotData::Close()
    {
    LOGFN( "CSlotData::Close" );
    iServer->Cache()->Release( this );
    }

void CSlotData::CloseFile()
    {
    LOGFN( "CSlotData::CloseFile" );
    iOpen = EFalse;
    }

void CSlotData::FlushL()
    {
    LOGFN( "CSlotData::FlushL" );
    __UHEAP_MARK;
	if ( IsOpen() && iDirty )
	    {
        TBuf8<KAESKeyLength> iv;
        TBuf8<KAESKeyLength> key;
        TInt size = iData.Size();
        RBuf8 compressedData;
        TUint32 compressedDataLen = size + size / 10 + 12;
        TUint8* compressedDataPtr;
        RBuf8 encryptedData;
        CBufferedEncryptor* encryptor = NULL;
        CModeCBCEncryptor* cbcEncryptor = NULL;
        CAESEncryptor* aesEncryptor = NULL;
        CPaddingPKCS7* padding = NULL;
        RBuf8 buffer;
      
        compressedData.CreateL( compressedDataLen );
        compressedData.CleanupClosePushL();
        compressedDataPtr = const_cast<TUint8*>( compressedData.Ptr() );
        User::LeaveIfError( compress( compressedDataPtr, &compressedDataLen, iData.Ptr(), size ) );
        compressedData.SetLength( compressedDataLen );
        
        encryptedData.CreateL( compressedData.Size() + 2 * KAESKeyLength );
        encryptedData.CleanupClosePushL();

        iv.SetLength( KAESKeyLength );
        TRandom::RandomL( iv );
#ifdef __WINSCW__
        key.Copy( KDummyKey );
#else
        iServer->Cache()->iKeyStorage->GetDeviceSpecificKeyL( key );
#endif
        aesEncryptor = CAESEncryptor::NewL( key );
        CleanupStack::PushL( aesEncryptor );
        
        cbcEncryptor = CModeCBCEncryptor::NewL( aesEncryptor, iv );
        CleanupStack::Pop( aesEncryptor );
        CleanupStack::PushL( cbcEncryptor );
        
        padding = CPaddingPKCS7::NewL( KAESKeyLength );
        CleanupStack::PushL( padding );
        
        encryptor = CBufferedEncryptor::NewL( cbcEncryptor, padding );
        CleanupStack::Pop( 2, cbcEncryptor ); //padding, cbcEncryptor
        CleanupStack::PushL( encryptor );
        
        encryptor->ProcessFinalL( compressedData, encryptedData );
        
        LOG1( "*** Write record" );
        LOG3( "Uncompressed size: %d, compresseded size: %d", size, encryptedData.Size() );
        buffer.CreateL( sizeof( TUint32 ) + iv.Size() + encryptedData.Size() );
        buffer.CleanupClosePushL();
        buffer.Append( TPckgC<TUint32>( size ) );
        buffer.Append( iv );
        buffer.Append( encryptedData );
        //LOGHEX( buffer.Ptr(), buffer.Size() );

        iServer->Db()->WriteDataL( iStore, iNamespace, iHashKey, iUniqueKey, buffer );
        iDirty = EFalse;
        TRandom::RandomL( key );
        CleanupStack::PopAndDestroy( 4, &compressedData ); //buffer, encryptor, encryptedData, compressedData
        }
    __UHEAP_MARKEND;        
    }

TBool CSlotData::IsOpen()
    {
    return iOpen;
    }