devencdiskutils/DevEncCommonUtils/src/DevEncKeyUtils.cpp
changeset 0 164170e6151a
child 9 a005fc61b02a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/devencdiskutils/DevEncCommonUtils/src/DevEncKeyUtils.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,609 @@
+/*
+* 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:  Implementation of CDevEncKeyUtils
+*
+*/
+
+
+// INCLUDE FILES
+
+// Class includes
+#include "DevEncDef.h"
+#include "DevEncKeyUtils.h"
+#include "DevEncLog.h"
+#include "DevEncUids.hrh"
+
+#include <pbe.h>
+#include <pbedata.h>
+//#include <PathInfo.h> // for system path literals
+#include <pkcs5kdf.h>
+#include <s32file.h>
+#include <s32mem.h>
+#include <imcvcodc.h>
+
+#include <DevEncEngineConstants.h>
+#include <DevEncEngineBase.h>
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::Connect()
+//
+// --------------------------------------------------------------------------
+EXPORT_C TInt CDevEncKeyUtils::Connect()
+    {
+    TRAPD( err, LoadDevEncEngineL() );
+    return err;
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::Connect()
+//
+// --------------------------------------------------------------------------
+EXPORT_C void CDevEncKeyUtils::Close()
+    {
+    UnloadDevEncEngine();
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::CDevEncKeyUtils()
+//
+// --------------------------------------------------------------------------
+EXPORT_C CDevEncKeyUtils::CDevEncKeyUtils(): iConnect( EFalse )
+    {
+    // No implementation necessary
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::CDevEncKeyUtils()
+//
+// --------------------------------------------------------------------------
+CDevEncKeyUtils::~CDevEncKeyUtils()
+    {
+    
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::CreateSetKey()
+//
+// --------------------------------------------------------------------------
+EXPORT_C void CDevEncKeyUtils::CreateSetKey( TRequestStatus& aStatus,
+                                             HBufC8*& aResult,
+                                             const TDesC8& aPassword,
+                                             const TInt aLength ) const
+    {
+    TInt error( KErrNone );
+    if ( ! ProcessHasCapability( ECapabilityDiskAdmin ) )
+        {
+        DFLOG( "Process does not have DiskAdmin capability" );
+        error = KErrAccessDenied;
+        }
+    else if ( aPassword.Length() > KMaxPasswordLength ||
+              aPassword.Length() < KMinPasswordLength )
+        {
+        DFLOG( "CDevEncKeyUtils::CreateSetKey Invalid password length" );
+        error = KErrArgument;
+        }
+    else if ( aLength > KEncryptionKeyLength )
+        {
+        DFLOG( "CDevEncKeyUtils::CreateSetKey Invalid key length" );
+        error = KErrArgument;
+        }
+    else
+        {
+        TRAP( error, DoCreateSetKeyL( aResult, aPassword, aLength ) );
+        DFLOG2( "CDevEncKeyUtils::CreateSetKey result %d", error );
+        }
+    TRequestStatus* statusPtr = &aStatus;
+    User::RequestComplete( statusPtr, error );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::CreateSetKey()
+//
+// --------------------------------------------------------------------------
+EXPORT_C void CDevEncKeyUtils::CreateSetKey( TRequestStatus& aStatus,
+                                             const TInt aLength ) const
+    {
+    TInt error( KErrNone );
+
+    HBufC8* password( NULL );
+
+    if ( ! ProcessHasCapability( ECapabilityDiskAdmin ) )
+        {
+        DFLOG( "Process does not have DiskAdmin capability" );
+        error = KErrAccessDenied;
+        }
+    if ( aLength > KEncryptionKeyLength )
+        {
+        DFLOG( "CDevEncKeyUtils::CreateSetKey Invalid key length" );
+        error = KErrArgument;
+        }
+
+    if ( !error )
+        {
+        TRAP( error, password = HBufC8::NewL( KMaxPasswordLength ) );
+        if ( error )
+            {
+            DFLOG2( "Pwd buf alloc error %d", error );
+            }
+        }
+
+    if ( !error )
+        {
+        // Get some random password
+        TPtr8 passwordPtr = password->Des();
+        passwordPtr.SetLength( KMaxPasswordLength );
+        if( iConnect )
+            {
+            iDevEncEngine->RandomDataGet( passwordPtr, KMaxPasswordLength );
+            }
+        
+        DFLOG( "Random password allocated" );
+        
+        TRAP( error, DoCreateSetKeyL( *password,
+                                      aLength ) );
+        DFLOG2( "CDevEncKeyUtils::CreateSetKey result %d", error );
+        }
+
+    // Cleanup on demand
+    if ( password )
+        {
+        delete password;
+        }
+    
+    TRequestStatus* statusPtr = &aStatus;
+    User::RequestComplete( statusPtr, error );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::DoCreateSetKey()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::DoCreateSetKeyL( const TDesC8& aPassword,
+                                       TInt aLength ) const
+    {
+    DFLOG2( ">>CDevEncKeyUtils::DoCreateSetKeyL, length %d", aLength );
+
+    // Get some random key data
+    HBufC8* clearKey = HBufC8::NewLC( aLength );
+    TPtr8 clearKeyPtr = clearKey->Des();
+    clearKeyPtr.SetLength( aLength );
+
+    if( iConnect )
+        {
+        iDevEncEngine->RandomDataGet( clearKeyPtr, KMaxPasswordLength );
+        }
+    
+    // if supply KDF, must also supply salt len and iteration count
+    CPBEncryptElement* encryption = CPBEncryptElement::NewLC( aPassword,
+                                                              ECipherDES_CBC );
+    CPBEncryptor* encryptor = encryption->NewEncryptLC();
+
+    HBufC8* ciphertextTemp = HBufC8::NewLC( encryptor->MaxFinalOutputLength( clearKey->Length() ) ); 
+    TPtr8 ciphertext = ciphertextTemp->Des();   
+    encryptor->ProcessFinalL( *clearKey, ciphertext );
+
+    // ENCRYPTION DONE
+
+    DFLOG( "DoCreateSetKeyL, Key in plaintext:" );
+    RDebug::RawPrint( clearKeyPtr );
+    DFLOG( "DoCreateSetKeyL, Key in ciphertext:" );
+    RDebug::RawPrint( ciphertext );
+    DFLOG( "DoCreateSetKeyL, Password:" );
+    RDebug::RawPrint( aPassword );
+    
+    if( iConnect )
+        {
+        // Take the new key in use
+        iDevEncEngine->TakeKeyInUseL( *clearKey );
+        }
+    
+    // Destroy the evidence
+    CleanupStack::PopAndDestroy( ciphertextTemp );
+    CleanupStack::PopAndDestroy( encryptor );
+    CleanupStack::PopAndDestroy( encryption );
+    CleanupStack::PopAndDestroy( clearKey );
+    };
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::DoCreateSetKey()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::DoCreateSetKeyL( HBufC8*& aResult,
+                                       const TDesC8& aPassword,
+                                       TInt aLength ) const
+    {
+    DFLOG2( ">>CDevEncKeyUtils::DoCreateSetKeyL, length %d", aLength );
+
+    // Get some random key data
+    HBufC8* clearKey = HBufC8::NewLC( aLength );
+    TPtr8 clearKeyPtr = clearKey->Des();
+    clearKeyPtr.SetLength( aLength );
+    
+    if( iConnect )
+        {
+        iDevEncEngine->RandomDataGet( clearKeyPtr, KMaxPasswordLength );
+        }
+    
+    // if supply KDF, must also supply salt len and iteration count
+    CPBEncryptElement* encryption = CPBEncryptElement::NewLC( aPassword,
+                                                              ECipherDES_CBC );
+    CPBEncryptor* encryptor = encryption->NewEncryptLC();
+
+    HBufC8* ciphertextTemp = HBufC8::NewLC( encryptor->MaxFinalOutputLength( clearKey->Length() ) ); 
+    TPtr8 ciphertext = ciphertextTemp->Des();   
+    encryptor->ProcessFinalL( *clearKey, ciphertext );
+
+    // ENCRYPTION DONE
+
+    DFLOG( "DoCreateSetKeyL, Key in plaintext:" );
+    RDebug::RawPrint( clearKeyPtr );
+    DFLOG( "DoCreateSetKeyL, Key in ciphertext:" );
+    RDebug::RawPrint( ciphertext );
+    DFLOG( "DoCreateSetKeyL, Password:" );
+    RDebug::RawPrint( aPassword );
+    
+    if( iConnect )
+        {
+        // Take the new key in use
+        iDevEncEngine->TakeKeyInUseL( *clearKey );
+        }
+
+    // If we got this far, the operation was successful.
+    // Give the caller a copy of the encrypted key
+    // Externalize the key data and ciphertext
+    HBufC8* result = HBufC8::NewLC( ciphertext.Length() +
+                                   KMaxPasswordLength +
+                                   50 // should be enough for encryption data
+                                   );
+    TPtr8 resultPtr = result->Des();
+    ExternalizeKeyL( encryption, ciphertext, resultPtr );
+    
+    // Encode key to base64 before returning it
+    aResult = HBufC8::NewL( resultPtr.Length()*4/3+3 );
+    TPtr8 returnPtr = aResult->Des();
+    returnPtr.SetLength( 0 );
+    TImCodecB64 b64codec;
+    b64codec.Initialise();
+    b64codec.Encode( *result, returnPtr );
+    
+    // Destroy the evidence
+    CleanupStack::PopAndDestroy( result );
+    CleanupStack::PopAndDestroy( ciphertextTemp );
+    CleanupStack::PopAndDestroy( encryptor );
+    CleanupStack::PopAndDestroy( encryption );
+    CleanupStack::PopAndDestroy( clearKey );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::SetKey()
+//
+// --------------------------------------------------------------------------
+EXPORT_C void CDevEncKeyUtils::SetKey( TRequestStatus& aStatus,
+                                       const TDesC8& aPkcs5Key,
+                                       const TDesC8& aPassword ) const
+    {
+    TInt error( KErrNone );
+
+    if ( ! ProcessHasCapability( ECapabilityDiskAdmin ) )
+        {
+        DFLOG( "Process does not have DiskAdmin capability" );
+        error = KErrAccessDenied;
+        }
+    else
+        {
+        TRAP( error, DoSetKeyL( aPkcs5Key, aPassword ) );
+        DFLOG2( "CDevEncKeyUtils::SetKey result %d", error );
+        }
+    TRequestStatus* statusPtr = &aStatus;
+    User::RequestComplete( statusPtr, error );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::DoSetKey()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::DoSetKeyL( const TDesC8& aPkcs5Key,
+                                 const TDesC8& aPassword ) const
+    {
+    // Decode the base64 encoded key
+    HBufC8* decodedKey = HBufC8::NewLC( aPkcs5Key.Length()*3/4 );
+    TPtr8 keyPtr = decodedKey->Des();
+    keyPtr.SetLength( 0 );
+    TImCodecB64 b64codec;
+    b64codec.Initialise();
+    b64codec.Decode( aPkcs5Key, keyPtr );
+
+    // Read the parameters and ciphertext from the input
+    CPBEncryptElement* encryption( NULL );
+    HBufC8* ciphertext( NULL );
+    InternalizeKeyL( encryption, aPassword, ciphertext, *decodedKey );
+    CleanupStack::PopAndDestroy( decodedKey );
+    CleanupStack::PushL( encryption );
+    CleanupStack::PushL( ciphertext );
+
+    // Decrypt and take key in use
+    CPBDecryptor* decryptor = encryption->NewDecryptLC();
+    HBufC8* plaintextTemp =
+        HBufC8::NewLC( decryptor->MaxOutputLength( (*ciphertext).Size() ) ); 
+    TPtr8 plaintext = plaintextTemp->Des(); 
+    decryptor->Process( *ciphertext, plaintext );
+
+    Pkcs5RemovePadding( plaintext );
+    
+    if( iConnect )
+        {
+        // Take the new key in use
+        iDevEncEngine->TakeKeyInUseL( plaintext );
+        }
+
+    DFLOG( "DoSetKeyL, Key in plaintext:" );
+    RDebug::RawPrint( plaintext );
+    DFLOG( "DoSetKeyL, Key in ciphertext:" );
+    RDebug::RawPrint( *ciphertext );
+    DFLOG( "DoSetKeyL, Password:" );
+    RDebug::RawPrint( aPassword );
+
+    
+    CleanupStack::PopAndDestroy( plaintextTemp );
+    CleanupStack::PopAndDestroy( decryptor );
+    CleanupStack::PopAndDestroy( ciphertext );
+    CleanupStack::PopAndDestroy( encryption );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::ResetKey()
+//
+// --------------------------------------------------------------------------
+EXPORT_C void CDevEncKeyUtils::ResetKey( TRequestStatus& aStatus ) const
+    {
+    TInt error( KErrNone );
+
+    if ( ! ProcessHasCapability( ECapabilityDiskAdmin ) )
+        {
+        DFLOG( "Process does not have DiskAdmin capability" );
+        error = KErrAccessDenied;
+        }
+    else
+        {
+        TBuf8<KEncryptionKeyLength> nullKey;
+        nullKey.FillZ( KEncryptionKeyLength );
+        TRAP( error, 
+        	  if( iConnect )
+                  {
+        		  // Take the new key in use
+        		  iDevEncEngine->TakeKeyInUseL( nullKey );
+        		  }  
+        	);
+        DFLOG2( "CDevEncKeyUtils::TakeKeyInUseL result %d", error );
+        }
+    TRequestStatus* statusPtr = &aStatus;
+    User::RequestComplete( statusPtr, error );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::GetNewFileStoreL()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::GetNewFileStoreL( RFs& aFs,
+                                        TDes& aFileName,
+                                        CFileStore*& aStore ) const
+    {
+    // Leaves with KErrAlreadyExists if file exists from before
+    aStore = CPermanentFileStore::CreateL( aFs,
+                                           aFileName,
+                                           EFileRead | EFileWrite );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::SaveKeyL()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::SaveKeyL( CFileStore* aStore,
+                                const CPBEncryptElement* aElement,
+                                const TDesC8& aCiphertext ) const
+    {
+    RStoreWriteStream write;
+    
+    aStore->SetTypeL( aStore->Layout() );
+    
+    //write the encryption data to a new stream
+    write.CreateLC( *aStore );
+    aElement->EncryptionData().ExternalizeL( write );
+    write.CommitL();
+    CleanupStack::PopAndDestroy(); //CreateLC()
+
+    //write the cyphertext to a new stream
+    write.CreateLC( *aStore );
+    write << aCiphertext;
+    write.CommitL();
+    CleanupStack::PopAndDestroy(); //CreateLC()
+
+    aStore->Commit();
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::LoadKeyLC()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::LoadKeyLC( RFs& aFs,
+                                 const TFileName& aFileName,
+                                 CPBEncryptionData*& aData,
+                                 HBufC8*& aCiphertext ) const
+    {
+    //prepare to read the streams back in, creating a new TPBEncryptionData
+    RStoreReadStream read;
+    // open the next PFS
+    CFileStore *store = CPermanentFileStore::OpenLC( aFs,
+                                                 aFileName,
+                                                 EFileRead );
+    TStreamId dataStreamId( 1 ); // we know it was the first stream written
+    read.OpenLC( *store, dataStreamId );
+//    CleanupStack::Pop();
+    //read in Encryption data
+    aData = CPBEncryptionData::NewL( read );
+    CleanupStack::Pop(); // read
+    read.Close();
+    CleanupStack::PushL( aData );
+
+    //read in ciphertext key
+    TStreamId cipherId( 2 ); // we know it was the second stream written
+    read.OpenLC( *store, cipherId );
+    CleanupStack::Pop();
+    aCiphertext = HBufC8::NewL( read, 10000 ); //some large number
+    read.Close();
+
+    CleanupStack::Pop( aData );
+    CleanupStack::PopAndDestroy( store );
+    CleanupStack::PushL( aData );
+    CleanupStack::PushL( aCiphertext );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::ExternalizeKeyL()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::ExternalizeKeyL( const CPBEncryptElement* aElement,
+                                       const TDesC8& aCiphertext,
+                                       //HBufC8*& aResult ) const
+                                       TDes8& aResult ) const
+    {
+    RDesWriteStream write;
+    write.Open( aResult );
+    write.PushL();
+    aElement->EncryptionData().ExternalizeL( write );
+    write << aCiphertext;
+    write.CommitL();
+    write.Pop();
+    write.Close();
+    DFLOG( "CDevEncKeyUtils::ExternalizeKeyL done" );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::InternalizeKeyL()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::InternalizeKeyL( CPBEncryptElement*& aElement,
+                                       const TDesC8& aPassword,
+                                       HBufC8*& aCiphertext,
+                                       const TDesC8& aSource ) const
+    {
+    RDesReadStream read;
+    read.Open( aSource );
+    read.PushL();
+    CPBEncryptionData* data = CPBEncryptionData::NewLC( read );
+    aElement = CPBEncryptElement::NewLC( *data, aPassword );
+    aCiphertext = HBufC8::NewL( aSource.Length() );
+    TPtr8 cipherTextPtr = aCiphertext->Des();
+    read >> cipherTextPtr;
+    CleanupStack::Pop( aElement );
+    CleanupStack::Pop( data );
+    read.Pop();
+    read.Close();
+    DFLOG( "CDevEncKeyUtils::InternalizeKeyL done" );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::Pkcs5RemovePadding()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::Pkcs5RemovePadding( TPtr8& aInput ) const
+    {
+    // From RFC 2898:
+    //    The padding string PS consists of 8-(||M|| mod 8) octets
+    //    each with value 8-(||M|| mod 8). The padding string PS will
+    //    satisfy one of the following statements:
+    //
+    //            PS = 01, if ||M|| mod 8 = 7 ;
+    //            PS = 02 02, if ||M|| mod 8 = 6 ;
+    //            ...
+    //            PS = 08 08 08 08 08 08 08 08, if ||M|| mod 8 = 0.
+    // So the last byte shows how much padding there is
+    DFLOG( "CDevEncKeyUtils::Pkcs5RemovePadding" );
+    TInt paddingBytes = aInput[ aInput.Length() - 1 ];
+    
+    if ( paddingBytes <= 0 ||
+         paddingBytes > 8  ||
+         paddingBytes > aInput.Length() )
+        {
+        return;
+        }
+
+    TInt delPos( aInput.Length() - paddingBytes - 1 );
+    TInt delLen( aInput.Length() - delPos );
+    aInput.Delete( delPos, delLen );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::ProcessHasCapability()
+//
+// --------------------------------------------------------------------------
+TBool CDevEncKeyUtils::ProcessHasCapability( TCapability aCapability ) const
+    {
+    RProcess process;
+    return process.HasCapability( aCapability );
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::LoadDevEncEngineL()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::LoadDevEncEngineL()
+    {
+    FLOG(" CDevEncKeyUtils::LoadDevEncEngineL >> ");
+    
+    if (!iDevEncEngine)
+        {
+         iConnect = EFalse;
+         TInt err = iLibrary.Load(KEncryptionDll);
+         if (err != KErrNone)
+             {
+             FLOG2("Error in finding the library... %d", err);
+             if (err == KErrNotFound)
+                 err = KErrNotSupported;
+             User::Leave(err);
+             }
+         TLibraryFunction entry = iLibrary.Lookup(1);
+         
+         if (!entry)
+             {
+             FLOG("Error in loading the library...");
+             User::Leave(KErrBadLibraryEntryPoint);
+             }
+         iDevEncEngine = (CDevEncEngineBase *) entry();
+         iConnect = ETrue;
+        }
+    FLOG(" CDevEncKeyUtils::LoadDevEncEngineL << ");
+    }
+
+// --------------------------------------------------------------------------
+// CDevEncKeyUtils::UnloadDevEncEngine()
+//
+// --------------------------------------------------------------------------
+void CDevEncKeyUtils::UnloadDevEncEngine()
+    {
+    FLOG(" CDevEncKeyUtils::UnloadDevEncEngineL >> ");
+    
+    if (iDevEncEngine)
+        {
+        iDevEncEngine->Close();
+        delete iDevEncEngine;
+        iDevEncEngine = NULL;
+        iLibrary.Close();
+        }
+    iConnect = EFalse;
+    
+    FLOG(" CDevEncKeyUtils::UnloadDevEncEngineL << ");
+    }
+
+// End of file