File: detect_encryption.c

package info (click to toggle)
sleuthkit 4.12.1%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,608 kB
  • sloc: ansic: 143,795; cpp: 52,225; java: 37,892; xml: 2,416; python: 1,076; perl: 874; makefile: 439; sh: 184
file content (309 lines) | stat: -rw-r--r-- 9,979 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
** The Sleuth Kit
**
** Copyright (c) 2021 Basis Technology Corp.  All rights reserved
** Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
**
** This software is distributed under the Common Public License 1.0
**
*/

#include "detect_encryption.h"

// Scans the buffer and returns 1 if the given signature is found, 0 otherwise.
// Looks for the signature starting at each byte from startingOffset to endingOffset.
int
detectSignature(const char * signature, size_t signatureLen, size_t startingOffset, size_t endingOffset, const char * buf, size_t bufLen) {

    for (size_t offset = startingOffset; offset <= endingOffset; offset++) {
        if (offset + signatureLen >= bufLen) {
            return 0;
        }

        if (memcmp(signature, buf + offset, signatureLen) == 0) {
            return 1;
        }
    }
    return 0;
}

// Returns 1 if LUKS signature is found, 0 otherwise
int
detectLUKS(const char * buf, size_t len) {
    const char * signature = "LUKS\xba\xbe";
    return detectSignature(signature, strlen(signature), 0, 0, buf, len);
}

// Returns 1 if BitLocker signature is found, 0 otherwise
int
detectBitLocker(const char * buf, size_t len) {

    // Look for the signature near the beginning of the buffer
    const char * signature = "-FVE-FS-";
    return detectSignature(signature, strlen(signature), 0, 16, buf, len);
}

// Returns 1 if FileVault signature is found, 0 otherwise
int
detectFileVault(const char * buf, size_t len) {
    const char * signature = "encrdsa";
    return detectSignature(signature, strlen(signature), 0, 0, buf, len);
}

// Returns 1 if Check Point signature is found, 0 otherwise
int
detectCheckPoint(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer
    const char * signature = "Protect";
    return detectSignature(signature, strlen(signature), 80, 100, buf, len);
}

// Returns 1 if McAfee Safeboot signature is found, 0 otherwise
int
detectMcAfee(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer. Check two capitalizations.
    const char * signature = "Safeboot";
    const char * altSignature = "SafeBoot";
    return (detectSignature(signature, strlen(signature), 0, 32, buf, len)
        | detectSignature(altSignature, strlen(altSignature), 0, 32, buf, len));
}

// Returns 1 if Guardian Edge signature is found, 0 otherwise
int
detectGuardianEdge(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer
    const char * signature = "PCGM";
    return detectSignature(signature, strlen(signature), 0, 32, buf, len);
}

// Returns 1 if Sophos Safeguard signature is found, 0 otherwise
int
detectSophos(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer
    const char * signature = "SGM400";
    const char * altSignature = "SGE400";
    return (detectSignature(signature, strlen(signature), 110, 150, buf, len)
        | detectSignature(altSignature, strlen(altSignature), 110, 150, buf, len));
}

// Returns 1 if WinMagic SecureDoc signature is found, 0 otherwise
int
detectWinMagic(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer
    const char * signature = "WMSD";
    return detectSignature(signature, strlen(signature), 236, 256, buf, len);
}

// Returns 1 if Symantec PGP signature is found, 0 otherwise
int
detectSymantecPGP(const char * buf, size_t len) {
    // Look for the signature near the beginning of the buffer
    const char * signature = "\xeb\x48\x90PGPGUARD";
    return detectSignature(signature, strlen(signature), 0, 32, buf, len);
}

// Returns the entropy of the beginning of the image.
double
calculateEntropy(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) {

    // Initialize frequency counts
    int byteCounts[256];
    for (int i = 0; i < 256; i++) {
        byteCounts[i] = 0;
    }

    // Read in blocks of 65536 bytes, skipping the first one that is more likely to contain header data.
    size_t bufLen = 65536;
    char buf[65536];
    size_t bytesRead = 0;
    for (uint64_t i = 1; i < 100; i++) {
        if ((i + 1) * bufLen > (uint64_t)img_info->size - offset) {
            break;
        }

        if (tsk_img_read(img_info, offset + i * bufLen, buf, bufLen) != (ssize_t) bufLen) {
            break;
        }

        for (size_t j = 0; j < bufLen; j++) {
            unsigned char b = buf[j] & 0xff;
            byteCounts[b]++;
        }
        bytesRead += bufLen;
    }

    // Calculate entropy
    double entropy = 0.0;
    double log2 = log(2);
    for (int i = 0; i < 256; i++) {
        if (byteCounts[i] > 0) {
            double p = (double)(byteCounts[i]) / bytesRead;
            entropy -= p * log(p) / log2;
        }
    }
    return entropy;
}

/**
 * Detect volume-type encryption in the image starting at the given offset.
 * May return null on error. Note that client is responsible for freeing the result.
 * 
 * @param img_info The open image
 * @param offset   The offset for the beginning of the volume
 *
 * @return encryption_detected_result containing the result of the check. null for certain types of errors.
*/
encryption_detected_result*
detectVolumeEncryption(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) {

    encryption_detected_result* result = (encryption_detected_result*)tsk_malloc(sizeof(encryption_detected_result));
    if (result == NULL) {
        return result;
    }
    result->encryptionType = ENCRYPTION_DETECTED_NONE;
    result->desc[0] = '\0';

    if (img_info == NULL) {
        return result;
    }
    if (offset > (uint64_t)img_info->size) {
        return result;
    }

    // Read the beginning of the image. There should be room for all the signature searches.
    size_t len = 1024;
    char* buf = (char*)tsk_malloc(len);
    if (buf == NULL) {
        return result;
    }
    if (tsk_img_read(img_info, offset, buf, len) != (ssize_t)len) {
        free(buf);
        return result;
    }

    // Look for BitLocker signature
    if (detectBitLocker(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "BitLocker");
        free(buf);
        return result;
    }

    // Look for Linux Unified Key Setup (LUKS) signature
    if (detectLUKS(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "LUKS");
        free(buf);
        return result;
    }

    // Look for FileVault
    if (detectFileVault(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "FileVault");
        free(buf);
        return result;
    }

    free(buf);

    // Final test - check entropy
    double entropy = calculateEntropy(img_info, offset);
    if (entropy > 7.5) {
        result->encryptionType = ENCRYPTION_DETECTED_ENTROPY;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "High entropy (%1.2lf)", entropy);
        return result;
    }

    return result;
}

/**
* Detect full disk encryption in the image starting at the given offset.
* May return null on error. Note that client is responsible for freeing the result.
*
* @param img_info The open image
* @param offset   The offset for the beginning of the image TODO TODO do we need this??
*
* @return encryption_detected_result containing the result of the check. null for certain types of errors.
*/
encryption_detected_result*
detectDiskEncryption(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) {

    encryption_detected_result* result = (encryption_detected_result*)tsk_malloc(sizeof(encryption_detected_result));
    if (result == NULL) {
        return result;
    }
    result->encryptionType = ENCRYPTION_DETECTED_NONE;
    result->desc[0] = '\0';

    if (img_info == NULL) {
        return result;
    }
    if (offset > (uint64_t)img_info->size) {
        return result;
    }

    // Read the beginning of the image. There should be room for all the signature searches.
    size_t len = 1024;
    char* buf = (char*)tsk_malloc(len);
    if (buf == NULL) {
        return result;
    }
    if (tsk_img_read(img_info, offset, buf, len) != (ssize_t)len) {
        free(buf);
        return result;
    }

    // Look for Symatec PGP signature
    if (detectSymantecPGP(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "Symantec PGP");
        free(buf);
        return result;
    }

    // Look for McAfee Safeboot signature
    if (detectMcAfee(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "McAfee Safeboot");
        free(buf);
        return result;
    }

    // Look for Sophos Safeguard
    if (detectSophos(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "Sophos Safeguard");
        free(buf);
        return result;
    }

    // Look for Guardian Edge signature
    if (detectGuardianEdge(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "Guardian Edge");
        free(buf);
        return result;
    }

    // Look for Check Point signature
    if (detectCheckPoint(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "Check Point");
        free(buf);
        return result;
    }

    // Look for WinMagic SecureDoc signature
    if (detectWinMagic(buf, len)) {
        result->encryptionType = ENCRYPTION_DETECTED_SIGNATURE;
        snprintf(result->desc, TSK_ERROR_STRING_MAX_LENGTH, "WinMagic SecureDoc");
        free(buf);
        return result;
    }
    free(buf);
    return result;
}