FwdLockFile.c revision fdd65a0fc7df2c878cc601e4c0f4021cb264f051
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 <limits.h> 21fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <pthread.h> 22fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <stdlib.h> 23fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <string.h> 24fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <unistd.h> 25fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <openssl/aes.h> 26fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include <openssl/hmac.h> 27fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 28fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include "FwdLockFile.h" 29fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#include "FwdLockGlue.h" 30fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 31fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define TRUE 1 32fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FALSE 0 33fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 34fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define INVALID_OFFSET ((off64_t)-1) 35fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 36fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define INVALID_BLOCK_INDEX ((uint64_t)-1) 37fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 38fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define MAX_NUM_SESSIONS 128 39fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 40fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE AES_BLOCK_SIZE 41fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define KEY_SIZE_IN_BITS (KEY_SIZE * 8) 42fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 43fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define SHA1_HASH_SIZE 20 44fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define SHA1_BLOCK_SIZE 64 45fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 46fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FWD_LOCK_VERSION 0 47fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define FWD_LOCK_SUBFORMAT 0 48fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define USAGE_RESTRICTION_FLAGS 0 49fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define CONTENT_TYPE_LENGTH_POS 7 50fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define TOP_HEADER_SIZE 8 51fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 52fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera#define SIG_CALC_BUFFER_SIZE (16 * SHA1_BLOCK_SIZE) 53fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 54fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 55fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Data type for the per-file state information needed by the decoder. 56fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 57fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheratypedef struct FwdLockFile_Session { 58fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int fileDesc; 59fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char topHeader[TOP_HEADER_SIZE]; 60fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera char *pContentType; 61fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t contentTypeLength; 62fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera void *pEncryptedSessionKey; 63fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t encryptedSessionKeyLength; 64fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char dataSignature[SHA1_HASH_SIZE]; 65fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char headerSignature[SHA1_HASH_SIZE]; 66fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera off64_t dataOffset; 67fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera off64_t filePos; 68fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_KEY encryptionRoundKeys; 69fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_CTX signingContext; 70fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char keyStream[AES_BLOCK_SIZE]; 71fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera uint64_t blockIndex; 72fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} FwdLockFile_Session_t; 73fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 74fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic FwdLockFile_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL }; 75fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 76fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER; 77fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 78fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic const unsigned char topHeaderTemplate[] = 79fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera { 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS }; 80fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 81fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 82fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Acquires an unused file session for the given file descriptor. 83fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 84fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] fileDesc A file descriptor. 85fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 86fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A session ID. 87fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 88fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockFile_AcquireSession(int fileDesc) { 89fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = -1; 90fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc < 0) { 91fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = EBADF; 92fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 93fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int i; 94fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_lock(&sessionAcquisitionMutex); 95fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (i = 0; i < MAX_NUM_SESSIONS; ++i) { 96fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS; 97fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionPtrs[candidateSessionId] == NULL) { 98fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[candidateSessionId] = malloc(sizeof **sessionPtrs); 99fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionPtrs[candidateSessionId] != NULL) { 100fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[candidateSessionId]->fileDesc = fileDesc; 101fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[candidateSessionId]->pContentType = NULL; 102fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[candidateSessionId]->pEncryptedSessionKey = NULL; 103fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionId = candidateSessionId; 104fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 105fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 106fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 107fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 108fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_unlock(&sessionAcquisitionMutex); 109fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (i == MAX_NUM_SESSIONS) { 110fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = ENFILE; 111fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 112fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 113fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return sessionId; 114fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 115fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 116fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 117fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Finds the file session associated to the given file descriptor. 118fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 119fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] fileDesc A file descriptor. 120fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 121fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A session ID. 122fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 123fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockFile_FindSession(int fileDesc) { 124fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = -1; 125fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc < 0) { 126fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = EBADF; 127fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 128fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int i; 129fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_lock(&sessionAcquisitionMutex); 130fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (i = 0; i < MAX_NUM_SESSIONS; ++i) { 131fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS; 132fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionPtrs[candidateSessionId] != NULL && 133fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[candidateSessionId]->fileDesc == fileDesc) { 134fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionId = candidateSessionId; 135fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 136fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 137fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 138fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_unlock(&sessionAcquisitionMutex); 139fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (i == MAX_NUM_SESSIONS) { 140fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = EBADF; 141fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 142fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 143fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return sessionId; 144fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 145fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 146fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 147fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Releases a file session. 148fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 149fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] sessionID A session ID. 150fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 151fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic void FwdLockFile_ReleaseSession(int sessionId) { 152fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_lock(&sessionAcquisitionMutex); 153fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL); 154fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(sessionPtrs[sessionId]->pContentType); 155fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(sessionPtrs[sessionId]->pEncryptedSessionKey); 156fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data. 157fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(sessionPtrs[sessionId]); 158fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionPtrs[sessionId] = NULL; 159fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pthread_mutex_unlock(&sessionAcquisitionMutex); 160fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 161fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 162fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 163fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Derives keys for encryption and signing from the encrypted session key. 164fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 165fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a file session. 166fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 167fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @return A Boolean value indicating whether key derivation was successful. 168fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 169fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic int FwdLockFile_DeriveKeys(FwdLockFile_Session_t * pSession) { 170fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result; 171fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera struct FwdLockFile_DeriveKeys_Data { 172fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_KEY sessionRoundKeys; 173fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char value[KEY_SIZE]; 174fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char key[KEY_SIZE]; 175fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } *pData = malloc(sizeof *pData); 176fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (pData == NULL) { 177fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 178fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 179fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FwdLockGlue_DecryptKey(pSession->pEncryptedSessionKey, 180fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->encryptedSessionKeyLength, pData->key, KEY_SIZE); 181fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (result) { 182fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS, &pData->sessionRoundKeys) != 0) { 183fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 184fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 185fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key. 186fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memset(pData->value, 0, KEY_SIZE); 187fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys); 188fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS, 189fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera &pSession->encryptionRoundKeys) != 0) { 190fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 191fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 192fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key. 193fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ++pData->value[0]; 194fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys); 195fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_CTX_init(&pSession->signingContext); 196fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL); 197fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 198fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 199fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 200fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (!result) { 201fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = ENOSYS; 202fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 203fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memset(pData, 0, sizeof pData); // Zero out key data. 204fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(pData); 205fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 206fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 207fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 208fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 209fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 210fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Calculates the counter, treated as a 16-byte little-endian number, used to generate the keystream 211fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * for the given block. 212fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 213fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] pNonce A reference to the nonce. 214fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] blockIndex The index number of the block. 215fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[out] pCounter A reference to the counter. 216fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 217fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherastatic void FwdLockFile_CalculateCounter(const unsigned char *pNonce, 218fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera uint64_t blockIndex, 219fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char *pCounter) { 220fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char carry = 0; 221fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t i = 0; 222fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (; i < sizeof blockIndex; ++i) { 223fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char part = pNonce[i] + (unsigned char)(blockIndex >> (i * CHAR_BIT)); 224fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pCounter[i] = part + carry; 225fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera carry = (part < pNonce[i] || pCounter[i] < part) ? 1 : 0; 226fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 227fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (; i < AES_BLOCK_SIZE; ++i) { 228fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pCounter[i] = pNonce[i] + carry; 229fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera carry = (pCounter[i] < pNonce[i]) ? 1 : 0; 230fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 231fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 232fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 233fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera/** 234fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * Decrypts the byte at the current file position using AES-128-CTR. In CTR (or "counter") mode, 235fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * encryption and decryption are performed using the same algorithm. 236fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * 237fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in,out] pSession A reference to a file session. 238fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera * @param[in] pByte The byte to decrypt. 239fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera */ 240fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheravoid FwdLockFile_DecryptByte(FwdLockFile_Session_t * pSession, unsigned char *pByte) { 241fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera uint64_t blockIndex = pSession->filePos / AES_BLOCK_SIZE; 242fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera uint64_t blockOffset = pSession->filePos % AES_BLOCK_SIZE; 243fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (blockIndex != pSession->blockIndex) { 244fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // The first 16 bytes of the encrypted session key is used as the nonce. 245fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char counter[AES_BLOCK_SIZE]; 246fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_CalculateCounter(pSession->pEncryptedSessionKey, blockIndex, counter); 247fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera AES_encrypt(counter, pSession->keyStream, &pSession->encryptionRoundKeys); 248fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->blockIndex = blockIndex; 249fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 250fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera *pByte ^= pSession->keyStream[blockOffset]; 251fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 252fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 253fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_attach(int fileDesc) { 254fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_AcquireSession(fileDesc); 255fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId >= 0) { 256fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_Session_t *pSession = sessionPtrs[sessionId]; 257fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int isSuccess = FALSE; 258fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (read(fileDesc, pSession->topHeader, TOP_HEADER_SIZE) == TOP_HEADER_SIZE && 259fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera memcmp(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate) == 0) { 260fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->contentTypeLength = pSession->topHeader[CONTENT_TYPE_LENGTH_POS]; 261fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(pSession->contentTypeLength <= UCHAR_MAX); // Untaint scalar for code checkers. 262fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->pContentType = malloc(pSession->contentTypeLength + 1); 263fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (pSession->pContentType != NULL && 264fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera read(fileDesc, pSession->pContentType, pSession->contentTypeLength) == 265fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (ssize_t)pSession->contentTypeLength) { 266fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->pContentType[pSession->contentTypeLength] = '\0'; 267fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE); 268fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength); 269fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (pSession->pEncryptedSessionKey != NULL && 270fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera read(fileDesc, pSession->pEncryptedSessionKey, 271fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->encryptedSessionKeyLength) == 272fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (ssize_t)pSession->encryptedSessionKeyLength && 273fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera read(fileDesc, pSession->dataSignature, SHA1_HASH_SIZE) == 274fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera SHA1_HASH_SIZE && 275fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera read(fileDesc, pSession->headerSignature, SHA1_HASH_SIZE) == 276fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera SHA1_HASH_SIZE) { 277fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera isSuccess = FwdLockFile_DeriveKeys(pSession); 278fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 279fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 280fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 281fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (isSuccess) { 282fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->dataOffset = pSession->contentTypeLength + 283fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->encryptedSessionKeyLength + TOP_HEADER_SIZE + 2 * SHA1_HASH_SIZE; 284fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->filePos = 0; 285fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->blockIndex = INVALID_BLOCK_INDEX; 286fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 287fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_ReleaseSession(sessionId); 288fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera sessionId = -1; 289fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 290fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 291fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return (sessionId >= 0) ? 0 : -1; 292fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 293fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 294fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_open(const char *pFilename) { 295fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int fileDesc = open(pFilename, O_RDONLY); 296fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (fileDesc >= 0 && FwdLockFile_attach(fileDesc) < 0) { 297fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)close(fileDesc); 298fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera fileDesc = -1; 299fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 300fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return fileDesc; 301fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 302fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 303fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeherassize_t FwdLockFile_read(int fileDesc, void *pBuffer, size_t numBytes) { 304fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ssize_t numBytesRead; 305fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 306fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 307fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera numBytesRead = -1; 308fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 309fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_Session_t *pSession = sessionPtrs[sessionId]; 310fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ssize_t i; 311fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera numBytesRead = read(pSession->fileDesc, pBuffer, numBytes); 312fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera for (i = 0; i < numBytesRead; ++i) { 313fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_DecryptByte(pSession, &((unsigned char *)pBuffer)[i]); 314fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ++pSession->filePos; 315fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 316fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 317fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return numBytesRead; 318fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 319fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 320fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraoff64_t FwdLockFile_lseek(int fileDesc, off64_t offset, int whence) { 321fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera off64_t newFilePos; 322fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 323fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 324fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = INVALID_OFFSET; 325fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 326fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_Session_t *pSession = sessionPtrs[sessionId]; 327fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera switch (whence) { 328fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera case SEEK_SET: 329fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = lseek64(pSession->fileDesc, pSession->dataOffset + offset, whence); 330fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 331fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera case SEEK_CUR: 332fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera case SEEK_END: 333fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = lseek64(pSession->fileDesc, offset, whence); 334fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 335fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera default: 336fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = EINVAL; 337fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = INVALID_OFFSET; 338fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera break; 339fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 340fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (newFilePos != INVALID_OFFSET) { 341fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (newFilePos < pSession->dataOffset) { 342fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // The new file position is illegal for an internal Forward Lock file. Restore the 343fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // original file position. 344fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos, 345fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera SEEK_SET); 346fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera errno = EINVAL; 347fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = INVALID_OFFSET; 348fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 349fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // The return value should be the file position that lseek64() would have returned 350fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera // for the embedded content file. 351fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->filePos = newFilePos - pSession->dataOffset; 352fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera newFilePos = pSession->filePos; 353fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 354fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 355fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 356fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return newFilePos; 357fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 358fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 359fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_detach(int fileDesc) { 360fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 361fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 362fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return -1; 363fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 364fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_CTX_cleanup(&sessionPtrs[sessionId]->signingContext); 365fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_ReleaseSession(sessionId); 366fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return 0; 367fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 368fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 369fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_close(int fileDesc) { 370fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return (FwdLockFile_detach(fileDesc) == 0) ? close(fileDesc) : -1; 371fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 372fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 373fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_CheckDataIntegrity(int fileDesc) { 374fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result; 375fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 376fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 377fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 378fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 379fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera struct FwdLockFile_CheckDataIntegrity_Data { 380fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char signature[SHA1_HASH_SIZE]; 381fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char buffer[SIG_CALC_BUFFER_SIZE]; 382fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } *pData = malloc(sizeof *pData); 383fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (pData == NULL) { 384fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 385fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 386fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_Session_t *pSession = sessionPtrs[sessionId]; 387fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (lseek64(pSession->fileDesc, pSession->dataOffset, SEEK_SET) != 388fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->dataOffset) { 389fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 390fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 391fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera ssize_t numBytesRead; 392fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t signatureSize = SHA1_HASH_SIZE; 393fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera while ((numBytesRead = 394fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) { 395fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead); 396fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 397fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (numBytesRead < 0) { 398fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 399fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 400fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize); 401fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(signatureSize == SHA1_HASH_SIZE); 402fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0; 403fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 404fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL); 405fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos, 406fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera SEEK_SET); 407fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 408fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera free(pData); 409fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 410fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 411fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 412fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 413fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 414fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_CheckHeaderIntegrity(int fileDesc) { 415fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int result; 416fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 417fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 418fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = FALSE; 419fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } else { 420fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera FwdLockFile_Session_t *pSession = sessionPtrs[sessionId]; 421fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera unsigned char signature[SHA1_HASH_SIZE]; 422fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera size_t signatureSize = SHA1_HASH_SIZE; 423fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE); 424fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType, 425fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->contentTypeLength); 426fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey, 427fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera pSession->encryptedSessionKeyLength); 428fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize); 429fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Final(&pSession->signingContext, signature, &signatureSize); 430fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera assert(signatureSize == SHA1_HASH_SIZE); 431fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera result = memcmp(signature, pSession->headerSignature, signatureSize) == 0; 432fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL); 433fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 434fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return result; 435fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 436fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 437fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraint FwdLockFile_CheckIntegrity(int fileDesc) { 438fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return FwdLockFile_CheckHeaderIntegrity(fileDesc) && FwdLockFile_CheckDataIntegrity(fileDesc); 439fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 440fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera 441fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbeheraconst char *FwdLockFile_GetContentType(int fileDesc) { 442fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera int sessionId = FwdLockFile_FindSession(fileDesc); 443fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera if (sessionId < 0) { 444fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return NULL; 445fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera } 446fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera return sessionPtrs[sessionId]->pContentType; 447fdd65a0fc7df2c878cc601e4c0f4021cb264f051Pravat Dalbehera} 448