Symbian
Symbian Developer Library

SYMBIAN OS V9.4

Feedback

[Index] [Previous] [Next]


Creating a HMAC hash value for a large data file (incremental method)

This example demonstrates how a large data file (approximately 100k) is read and processed over several iterations in order to produce an HMAC MD5 hash representation of the file's contents. The key-related classes are defined in keys.h.

#include <f32file.h>
#include <legacyselector.h>
#include <cryptohashapi.h>
#include <keys.h> 

using namespace CryptoSpi;

//Constant integer to store the number of separate blocks into which 
// the large data file is to be incrementally read
const TInt KDataReadBlocks = 20;

//Create and initialise a pointer for the HMAC implementation object
CHash* hmacImpl = NULL;

//If successful, the CreateHashL() method creates a hash implementation 
//object which is assigned to the hmacImpl pointer. Please note that the 
//key can be passed in when constructing the factory object, but for the 
//purpose of demonstration, the CHash::SetKeyL() method is used later.
TRAPD(err,CHashFactory::CreateHashL(hmacImpl,
    KMd5Uid,
    KHashModeUid,
    NULL,
    NULL));

if (hmacImpl && (err == KErrNone))
    {

    //Create a new CCryptoParams object to encapsulate the secret key 
    //string and key type
    CCryptoParams* keyParams = CCryptoParams::NewL();
    CleanupStack::PushL(keyParams);

    //Add the secret key to the CCryptoParams object by calling the 
    //CCryptoParams::AddL() method, passing in the key string and 
    //appropriate key parameter UID
    keyParams->AddL(_L8("12345678"), KHmacKeyParameterUid);

    //Create a key object (CKey) by passing in an instance of TKeyProperty 
    //and the previously created CCryptoParams object containing the secret key.
    TKeyProperty keyProperty;      
    CKey* key=CKey::NewL(keyProperty,*keyParams);
    CleanupStack::PushL(key);

    //Set the key within the HMAC implementation object by calling the 
    //CHash::SetKeyL() method, passing in the appropriate CKey object
    hmacImpl->SetKeyL(*key);

    //Set the operation mode within the HMAC implementation object by calling the 
    //CHash::SetOperationModeL() method, passing in the UID for HMAC mode
    hmacImpl->SetOperationModeL(KHmacModeUid);
                      
    //Having successfully set up the HMAC factory implementation object, the 
    //next stage is to read the file from disk over a number of iterations, 
    //updating the hash message after each read. On the last iteration, the 
    //message is finalised and the complete MD5 hash of the file is returned        
    RFs fsSession;

    //Create a connection to the file server  
    User::LeaveIfError(fsSession.Connect());
                    
    RFile sourceFile;
    CleanupClosePushL(sourceFile);

    //Open the source file passing in the file server session handle, 
    //source file path and file access mode   
    User::LeaveIfError(sourceFile.Open(fsSession, _L("c:\\testdata\\largeData.dat"), EFileRead));
                            
    TInt sourceLength = 0;           //Length of the data file
    TInt readPosition = 0;           //Current position in the data file
    TInt readIncrement = 0;          //Length of a single block of data
    TBool hashComplete = EFalse; //Flag to determine whether the hash is complete
    TPtrC8 hashData;                  //Holds the final hash value
    
    //Retrieve the size of the data file using the RFile::Size() method
    User::LeaveIfError(sourceFile.Size(sourceLength));
                        
    //Calculate the amount of data to read in each increment by dividing the file 
    //size by the number of separate blocks to split the file into
    readIncrement = sourceLength/KDataReadBlocks;
    
    //Each iteration of the loop reads in a new block of data from the current 
    //position within the file into a heap based descriptor. The first parse will see 
    //a call to the Hash() method made to set the initial state of the Hash message. 
    //After that the Update() method will be called until the last iteration in which a 
    //call is made to the Final() method along with the last block of data. As a result, 
    //the resulting HMAC MD5 hashed value is returned within a TPtrC8.    
    do 
        {
        //Create a heap based descriptor allocating enough memory to store a 
        //single block of data
        HBufC8* sourceData = HBufC8::NewL(readIncrement);
        CleanupStack::PushL(sourceData);

        //Create a modifiable pointer descriptor and use the Des() method in order 
        //to read in a new block of data into the heap based descriptor
        TPtr8 sourcePtr = sourceData->Des();
        
        //Read the block from the data file at the current position       
        err = sourceFile.Read(readPosition,sourcePtr,readIncrement);
        
        //Update the current read position within the data file so that the next 
        //iteration is set            
        readPosition += readIncrement;
                            
        if (readPosition == readIncrement)
            {
            //Read in the first block from the data file into the HMAC implementation object
            hmacImpl->Hash(*sourceData);
            }
        else if (readPosition >= sourceLength)
            {
            //Read in the final block, construct the complete HMAC MD5 hash 
            //value and assign it to a TPtrC8 (hashData) 
            hashData.Set(hmacImpl->Final(*sourceData));

            //Set the Boolean flag to break out of the loop
            hashComplete = ETrue;
            }
        else
            {
            //Update the message data within the HMAC object with the new block
            hmacImpl->Update(*sourceData);
            }
        
        //Pop and destroy the heap based descriptor for the next iteration            
        CleanupStack::PopAndDestroy(sourceData);

        }while(hashComplete == EFalse);

    //Cleanup the Source RFile   
    CleanupStack::PopAndDestroy();

    //Close the file server session     
    fsSession.Close();

    //Pop from the cleanup stack and destroy the CKey and CCryptoParams objects
    CleanupStack::PopAndDestroy(key);
    CleanupStack::PopAndDestroy(keyParams);
    }

//Destory the remaining HMAC implementation object
delete hmacImpl;
hmacImpl = NULL;