--- /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