io_decrypt.c 9.57 KB
Newer Older
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * Copyright (C) 2013 Magic Lantern Team
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */
 
22
23
24
25
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
26
#include <inttypes.h>
27
28
29

#include "io_crypt.h"
#include "crypt_lfsr64.h"
30
#include "crypt_rsa.h"
31
32
33
34
35
36
#include "hash_password.h"


#define BLOCKSIZE (8 * 1024)


37
38
39
40
41
42
static const uint8_t cr2_magic[] = "\x49\x49\x2A\x00";
static const uint8_t jpg_magic[] = "\xff\xd8\xff\xe1";
static const uint8_t rsa_magic[] = "\xff\xd8\xff\xd8";
static const uint8_t lfsr_magic[] = "\xff\xd8\xff\x8d";


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
static uint32_t lfsr113[] = { 0x00009821, 0x00098722, 0x00986332, 0x961FEFA7 };

void rand_fill(uint32_t *buffer, uint32_t length)
{
    for(uint32_t pos = 0; pos < length; pos++)
    {
        lfsr113[0] = ((lfsr113[0] & 0xFFFFFFFE) << 18) ^ (((lfsr113[0] <<  6) ^ lfsr113[0]) >> 13);
        lfsr113[1] = ((lfsr113[1] & 0xFFFFFFF8) <<  2) ^ (((lfsr113[1] <<  2) ^ lfsr113[1]) >> 27);
        lfsr113[2] = ((lfsr113[2] & 0xFFFFFFF0) <<  7) ^ (((lfsr113[2] << 13) ^ lfsr113[2]) >> 21);
        lfsr113[3] = ((lfsr113[3] & 0xFFFFFF80) << 13) ^ (((lfsr113[3] <<  3) ^ lfsr113[3]) >> 12);

        buffer[pos] = lfsr113[0] ^ lfsr113[1] ^ lfsr113[2] ^ lfsr113[3];
    }
}

void rand_seed(uint32_t seed)
{
    uint32_t tmp = 0;

    /* apply seed to internal states and do a few rounds to equally distribute seed bits */
    for(int loops = 0; loops < 128; loops++)
    {
        lfsr113[loops%4] ^= seed;
        rand_fill(&tmp, 1);
    }
}

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
/* this routine checks if the LFSR64 encryption is handling all cases correctly */
static void io_decrypt_test()
{
    uint64_t key = 0xDEADBEEFDEADBEEF;
    uint32_t lfsr_blocksize = 0x00000224;
    uint32_t file_offset = 0;
    crypt_cipher_t crypt_ctx;

    /* initialize encryption with some common parameters */
    crypt_lfsr64_init(&crypt_ctx, key);
    crypt_ctx.set_blocksize(&crypt_ctx, lfsr_blocksize);
    
    rand_seed(0x12341234);
    
    uint32_t bufsize = 1 * 1024 * 1024;
    char *buf_src = malloc(bufsize);
    char *buf_dst = malloc(bufsize);
    
    for(int loop = 0; loop < 1000; loop++)
    {
        /* prepare both buffers */
        rand_fill(buf_src, bufsize / 4);
        memcpy(buf_dst, buf_src, bufsize);
        
        /* forge some test start and length */
        uint32_t start = 0;
        uint32_t length = 0;
        
        rand_fill(&start, 1);
        rand_fill(&length, 1);
        
        start %= bufsize;
        length %= (bufsize - start + 1);
        
        /* now do en- and de-cryption */
        printf("#%03d 0x%08X 0x%08X\n", loop, start, length);
        crypt_ctx.encrypt(&crypt_ctx, &buf_dst[start], &buf_src[start], length, 0);
        crypt_ctx.decrypt(&crypt_ctx, &buf_dst[start], &buf_dst[start], length, 0);
        
        /* check if both match */
        if(memcmp(buf_src, buf_dst, bufsize))
        {
            printf("  --> Check failed!!\n");
            return;
        }
    }
    
    free(buf_src);
    free(buf_dst);
}

121
static crypt_cipher_t iocrypt_rsa_ctx;
122
123
int main(int argc, char *argv[])
{
124
    //io_decrypt_test();
125
    //crypt_rsa_test();
126
    
127
    if(argc < 2)
128
    {
129
        printf("Usage: '%s <infile> [outfile] [password]\n", argv[0]);
130
131
132
        return -1;
    }
    
133
134
135
    uint64_t key = 0;
    uint32_t lfsr_blocksize = 0x00020000;
    
136
    char *in_filename = argv[1];
137
138
139
140
141
142
143
144
    char *out_filename = malloc(strlen(in_filename) + 9);
    
    sprintf(out_filename, "%s_out.cr2", in_filename);
    
    if(argc >= 3)
    {
        out_filename = strdup(argv[2]);
    }
145
    
146
147
148
149
150
151
    /* password is optional */
    if(argc >= 4)
    {
        /* hash the password */
        hash_password(argv[3], &key);
    }
152
153
154
155
156
157
    
    /* open files */
    FILE *in_file = fopen(in_filename, "rb");
    if(!in_file)
    {
        printf("Could not open '%s'\n", in_filename);
158
        return -1;
159
160
161
    } 
    
    char *buffer = malloc(BLOCKSIZE);
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
    
    
    /* try to detect file type */
    if(fread(buffer, 1, 4, in_file) != 4)
    {
        printf("Could not read '%s'\n", in_filename);
        return -1;
    }
    
    if(!memcmp(buffer, jpg_magic, 4))
    {
        printf("File type: JPEG (plain)\n");
        return 0;
    }
    else if(!memcmp(buffer, cr2_magic, 4))
    {
        printf("File type: CR2 (plain)\n");
        return 0;
    }
    else if(!memcmp(buffer, lfsr_magic, 4))
    {
        printf("File type: LFSR64\n");
        
        if(!key)
        {
            printf("Error: Please specify a password\n");
            return -2;
        }
        if(fread(&lfsr_blocksize, 1, sizeof(uint32_t), in_file) != sizeof(uint32_t))
        {
            printf("Could not read '%s'\n", in_filename);
            return -1;
        }
        
        fseek(in_file, 0x200, SEEK_SET);
    }
    else if(!memcmp(buffer, rsa_magic, 4))
    {
        printf("File type: RSA+LFSR64\n");
        
        crypt_rsa_init(&iocrypt_rsa_ctx);
203
204
205
206
207
208
        
        if(crypt_rsa_get_keysize(iocrypt_rsa_ctx.priv) < 64)
        {
            printf("Invalid key size\n");
            return;
        }
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

        uint32_t encrypted_size = 0;
        
        if(fread(&encrypted_size, 1, sizeof(uint32_t), in_file) != sizeof(uint32_t))
        {
            printf("Could not read '%s'\n", in_filename);
            return -1;
        }
        
        if(fread(&lfsr_blocksize, 1, sizeof(uint32_t), in_file) != sizeof(uint32_t))
        {
            printf("Could not read '%s'\n", in_filename);
            return -1;
        }

        if(!encrypted_size || encrypted_size > 32768 * 4)
        {
            printf("encrypted_size: %d\n", encrypted_size);
            return -1;
        }
        
        if(!lfsr_blocksize || lfsr_blocksize > 0x10000000)
        {
            printf("lfsr_blocksize: %d\n", lfsr_blocksize);
            return -1;
        }
        
        char *encrypted = malloc(encrypted_size);
        if(fread(encrypted, 1, encrypted_size, in_file) != encrypted_size)
        {
            printf("Could not read '%s'\n", in_filename);
            return -1;
        }
242
        uint32_t decrypted_size = iocrypt_rsa_ctx.decrypt(iocrypt_rsa_ctx.priv, (uint8_t *)encrypted, (uint8_t *)encrypted, encrypted_size, 0);
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

        if(!decrypted_size || decrypted_size > encrypted_size)
        {
            printf("decrypted_size: %d. maybe key mismatch?\n", decrypted_size);
            return -1;
        }
        
        /* that decrypted data is the file crypt key */
        memcpy(&key, encrypted, sizeof(uint64_t));
        
        free(encrypted);
    
        uint32_t used_header = 4 + sizeof(uint32_t) + encrypted_size;
        uint32_t aligned_header = (used_header + 0x1FF) & ~0x1FF;
        
        /* now skip that header and continue with LFSR113 decryption */
        fseek(in_file, aligned_header, SEEK_SET);
    }
    else
    {
        if(key)
        {
            printf("File type: unknown. assuming LFSR64\n");
        }
        else
        {
            printf("File type: unknown. assuming LFSR64. Please specify a password\n");
            return -2;
        }
    }
    
    /* setup cipher with that hash */
275
276
277
    uint32_t first = 1;
    FILE *out_file = NULL;
    
278
    uint32_t file_offset = 0;
279
280
    crypt_cipher_t crypt_ctx;
    crypt_lfsr64_init(&crypt_ctx, key);
281
    crypt_ctx.set_blocksize(crypt_ctx.priv, lfsr_blocksize);
282
    
283
    
284
285
286
287
288
289
    while(!feof(in_file))
    {
        int ret = fread(buffer, 1, BLOCKSIZE, in_file);
        
        if(ret > 0)
        {
290
            crypt_ctx.decrypt(crypt_ctx.priv, (uint8_t *)buffer, (uint8_t *)buffer, ret, file_offset);
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
            
            /* try to detect file type */
            if(first)
            {
                first = 0;
                
                if(!memcmp(buffer, jpg_magic, 4))
                {
                    printf("File type: JPEG (decrypted)\n");
                }
                else if(!memcmp(buffer, cr2_magic, 4))
                {
                    printf("File type: CR2 (decrypted)\n");
                }
                else
                {
                    printf("File type: unknown. invalid key?\n");
                    fclose(in_file);
                    free(out_filename);
                    return 0;
                }
                
                out_file = fopen(out_filename, "w");
                if(!out_file)
                {
                    printf("Could not open '%s'\n", out_filename);
                    return -1;
                }
            }
            
321
322
323
            fwrite(buffer, 1, ret, out_file);
            file_offset += ret;
        }
324
325
326
327
328
        if(ret < 0)
        {
            printf("Could not read '%s'\n", in_filename);
            break;
        }
329
330
331
332
    }
    
    fclose(in_file);
    fclose(out_file);
333
    free(out_filename);
334
}