diff -r 000000000000 -r 164170e6151a devencdiskutils/DevEncCommonUtils/src/DevEncKeyUtils.cpp --- /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 +#include +//#include // for system path literals +#include +#include +#include +#include + +#include +#include + +// -------------------------------------------------------------------------- +// 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 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