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