forked from kmdm/ruuveal
/
htcaes.c
131 lines (110 loc) · 3.93 KB
/
htcaes.c
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
/* ruuveal - Decrypt HTC encrypted RUUs (rom.zip files).
*
* Copyright (C) 2013 Kenny Millington
*
* This file is part of ruuveal.
*
* ruuveal 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 3 of the License, or
* (at your option) any later version.
*
* ruuveal 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 ruuveal. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mcrypt.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "htcaes.h"
static unsigned int get_num_chunks(unsigned int size, unsigned int chunk_size)
{
/* FIXME: This implementation could very well not be complete. */
unsigned int chunks;
if(chunk_size == 1)
return size;
else if(chunk_size - 1 < 1)
return 0;
else if(size < chunk_size)
return 0;
else if(size == chunk_size)
return 1;
chunks = size / chunk_size;
chunks--;
if(size - (chunk_size * chunks) != 0)
chunks++;
return chunks;
}
static int decrypt_chunk(MCRYPT td, char *buf, int size, char *key, char *iv)
{
char new_iv[HTC_AES_KEYSIZE];
memcpy(new_iv, &buf[size - HTC_AES_KEYSIZE], HTC_AES_KEYSIZE);
mcrypt_generic_init(td, key, HTC_AES_KEYSIZE, iv);
mdecrypt_generic(td, buf, size);
mcrypt_generic_deinit(td);
memcpy(iv, new_iv, HTC_AES_KEYSIZE);
}
static int encrypt_chunk(MCRYPT td, char *buf, int size, char *key, char *iv)
{
mcrypt_generic_init(td, key, HTC_AES_KEYSIZE, iv);
mcrypt_generic(td, buf, size);
mcrypt_generic_deinit(td);
memcpy(iv, &buf[size - HTC_AES_KEYSIZE], HTC_AES_KEYSIZE);
}
static int htc_aes_crypt(FILE *in, FILE *out, char *key, char *iv,
unsigned char chunks_in, htc_aes_progress_t callback,
htc_aes_crypt_t crypt_func)
{
char buf[HTC_AES_READBUF], orig_iv[HTC_AES_KEYSIZE];
unsigned int pos, size, chunks, bytes, chunksdone = 0;
unsigned int count = HTC_AES_READBUF_ROUNDS + 1;
unsigned int chunk_size = (((int)chunks_in)<<HTC_AES_CHUNK_SIZE);
MCRYPT td;
/* Get size of zip data. */
pos = ftell(in);
fseek(in, 0, SEEK_END);
size = ftell(in) - pos;
fseek(in, pos, SEEK_SET);
chunks = get_num_chunks(size, chunk_size);
td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, NULL, MCRYPT_CBC, NULL);
if(td == MCRYPT_FAILED) {
perror("failed to open mcrypt module");
return 0;
}
memcpy(orig_iv, iv, HTC_AES_KEYSIZE);
while((bytes = fread(buf, sizeof(char), sizeof(buf), in)) > 0) {
if(callback) callback(ftell(in), size);
if(chunksdone < chunks) {
if((ftell(in) - bytes - pos) % chunk_size == 0) {
count = 0;
memcpy(iv, orig_iv, HTC_AES_KEYSIZE);
}
if(count < HTC_AES_READBUF_ROUNDS) {
crypt_func(td, buf, sizeof(buf), key, iv);
count++;
} else if(count == HTC_AES_READBUF_ROUNDS) {
chunksdone++;
count++;
}
}
fwrite(buf, sizeof(char), sizeof(buf), out);
}
mcrypt_module_close(td);
return 1;
}
int htc_aes_decrypt(FILE *in, FILE *out, char *key, char *iv,
unsigned char chunks, htc_aes_progress_t callback)
{
return htc_aes_crypt(in, out, key, iv, chunks, callback, decrypt_chunk);
}
int htc_aes_encrypt(FILE *in, FILE *out, char *key, char *iv,
unsigned char chunks, htc_aes_progress_t callback)
{
return htc_aes_crypt(in, out, key, iv, chunks, callback, encrypt_chunk);
}