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