1fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/* 2fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Copyright (C) 2010 The Android Open Source Project 3fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 4fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Licensed under the Apache License, Version 2.0 (the "License"); 5fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * you may not use this file except in compliance with the License. 6fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * You may obtain a copy of the License at 7fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 8fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * http://www.apache.org/licenses/LICENSE-2.0 9fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 10fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Unless required by applicable law or agreed to in writing, software 11fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * distributed under the License is distributed on an "AS IS" BASIS, 12fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * See the License for the specific language governing permissions and 14fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * limitations under the License. 15fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 16fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 17fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <assert.h> 18fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <errno.h> 19fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <fcntl.h> 20fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <pthread.h> 21fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <stdlib.h> 22fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <string.h> 23fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <sys/stat.h> 24fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <unistd.h> 25fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <openssl/aes.h> 26fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 27fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include "FwdLockGlue.h" 28fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 29fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define TRUE 1 30fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FALSE 0 31fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 32fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE 16 33fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE_IN_BITS (KEY_SIZE * 8) 34fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 35fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int isInitialized = FALSE; 36fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 37fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const char strKeyFilename[] = "/data/drm/fwdlock/kek.dat"; 38fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 39fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic AES_KEY encryptionRoundKeys; 40fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic AES_KEY decryptionRoundKeys; 41fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 42fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 43fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Creates all directories along the fully qualified path of the given file. 44fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 45fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] path A reference to the fully qualified path of a file. 46fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] mode The access mode to use for the directories being created. 47fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 48fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the operation was successful. 49fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 50fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockGlue_CreateDirectories(const char *path, mode_t mode) { 51fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result = TRUE; 52fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t partialPathLength = strlen(path); 53fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera char *partialPath = malloc(partialPathLength + 1); 54fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (partialPath == NULL) { 55fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 56fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 57fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t i; 58fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (i = 0; i < partialPathLength; ++i) { 59fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (path[i] == '/' && i > 0) { 60fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera partialPath[i] = '\0'; 61fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (mkdir(partialPath, mode) != 0 && errno != EEXIST) { 62fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 63fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 64fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 65fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 66fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera partialPath[i] = path[i]; 67fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 68fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(partialPath); 69fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 70fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 71fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 72fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 73fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 74fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Initializes the round keys used for encryption and decryption of session keys. First creates a 75fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * device-unique key-encryption key if none exists yet. 76fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 77fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic void FwdLockGlue_InitializeRoundKeys() { 78fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char keyEncryptionKey[KEY_SIZE]; 79fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int fileDesc = open(strKeyFilename, O_RDONLY); 80fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc >= 0) { 81fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (read(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) { 82fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera isInitialized = TRUE; 83fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 84fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)close(fileDesc); 85fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else if (errno == ENOENT && 86fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockGlue_GetRandomNumber(keyEncryptionKey, KEY_SIZE) && 87fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockGlue_CreateDirectories(strKeyFilename, S_IRWXU)) { 88fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera fileDesc = open(strKeyFilename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR); 89fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc >= 0) { 90fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (write(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) { 91fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera isInitialized = TRUE; 92fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 93fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)close(fileDesc); 94fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 95fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 96fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (isInitialized) { 97fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (AES_set_encrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &encryptionRoundKeys) != 0 || 98fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_set_decrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &decryptionRoundKeys) != 0) { 99fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera isInitialized = FALSE; 100fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 101fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 102fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memset(keyEncryptionKey, 0, KEY_SIZE); // Zero out key data. 103fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 104fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 105fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 106fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Validates the padding of a decrypted key. 107fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 108fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] pData A reference to the buffer containing the decrypted key and padding. 109fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] decryptedKeyLength The length in bytes of the decrypted key. 110fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 111fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether the padding was valid. 112fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 113fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockGlue_ValidatePadding(const unsigned char *pData, size_t decryptedKeyLength) { 114fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t i; 115fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t padding = AES_BLOCK_SIZE - (decryptedKeyLength % AES_BLOCK_SIZE); 116fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pData += decryptedKeyLength; 117fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (i = 0; i < padding; ++i) { 118fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if ((size_t)*pData != padding) { 119fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return FALSE; 120fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 121fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ++pData; 122fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 123fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return TRUE; 124fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 125fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 126fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockGlue_GetRandomNumber(void *pBuffer, size_t numBytes) { 127fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // Generate 'cryptographically secure' random bytes by reading them from "/dev/urandom" (the 128fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // non-blocking version of "/dev/random"). 129fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ssize_t numBytesRead = 0; 130fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int fileDesc = open("/dev/urandom", O_RDONLY); 131fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc >= 0) { 132fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera numBytesRead = read(fileDesc, pBuffer, numBytes); 133fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)close(fileDesc); 134fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 135fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return numBytesRead >= 0 && (size_t)numBytesRead == numBytes; 136fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 137fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 138fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockGlue_InitializeKeyEncryption() { 139fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera static pthread_once_t once = PTHREAD_ONCE_INIT; 140fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_once(&once, FwdLockGlue_InitializeRoundKeys); 141fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return isInitialized; 142fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 143fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 144fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherasize_t FwdLockGlue_GetEncryptedKeyLength(size_t plaintextKeyLength) { 145fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return ((plaintextKeyLength / AES_BLOCK_SIZE) + 2) * AES_BLOCK_SIZE; 146fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 147fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 148fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockGlue_EncryptKey(const void *pPlaintextKey, 149fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t plaintextKeyLength, 150fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera void *pEncryptedKey, 151fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t encryptedKeyLength) { 152fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result = FALSE; 153fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(plaintextKeyLength)); 154fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (FwdLockGlue_InitializeKeyEncryption()) { 155fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char initVector[AES_BLOCK_SIZE]; 156fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (FwdLockGlue_GetRandomNumber(initVector, AES_BLOCK_SIZE)) { 157fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t padding = AES_BLOCK_SIZE - (plaintextKeyLength % AES_BLOCK_SIZE); 158fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE; 159fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcpy(pEncryptedKey, pPlaintextKey, plaintextKeyLength); 160fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memset((unsigned char *)pEncryptedKey + plaintextKeyLength, (int)padding, padding); 161fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcpy((unsigned char *)pEncryptedKey + dataLength, initVector, AES_BLOCK_SIZE); 162fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_cbc_encrypt(pEncryptedKey, pEncryptedKey, dataLength, &encryptionRoundKeys, 163fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera initVector, AES_ENCRYPT); 164fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = TRUE; 165fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 166fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 167fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 168fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 169fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 170fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockGlue_DecryptKey(const void *pEncryptedKey, 171fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t encryptedKeyLength, 172fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera void *pDecryptedKey, 173fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t decryptedKeyLength) { 174fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result = FALSE; 175fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(decryptedKeyLength)); 176fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (FwdLockGlue_InitializeKeyEncryption()) { 177fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE; 178fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char *pData = malloc(dataLength); 179fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (pData != NULL) { 180fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char initVector[AES_BLOCK_SIZE]; 181fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcpy(pData, pEncryptedKey, dataLength); 182fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcpy(initVector, (const unsigned char *)pEncryptedKey + dataLength, AES_BLOCK_SIZE); 183fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_cbc_encrypt(pData, pData, dataLength, &decryptionRoundKeys, initVector, 184fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_DECRYPT); 185fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcpy(pDecryptedKey, pData, decryptedKeyLength); 186fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FwdLockGlue_ValidatePadding(pData, decryptedKeyLength); 187fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(pData); 188fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 189fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 190fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 191fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 192