-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathRootFSDecrypt.c
More file actions
executable file
·200 lines (163 loc) · 5.17 KB
/
RootFSDecrypt.c
File metadata and controls
executable file
·200 lines (163 loc) · 5.17 KB
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
/*!
@source RootFSDecrypt.m
@project Pusher
@author Alexander Maksimenko
@copyright Copyright (c) 2009 Ripdev. All rights reserved.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
#include <openssl/aes.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
typedef struct
{
unsigned char sig[8];
uint32_t version;
uint32_t enc_iv_size;
uint32_t unk1;
uint32_t unk2;
uint32_t unk3;
uint32_t unk4;
uint32_t unk5;
unsigned char uuid[16];
uint32_t blocksize;
uint64_t datasize;
uint64_t dataoffset;
uint8_t filler1[0x260];
uint32_t kdf_algorithm;
uint32_t kdf_prng_algorithm;
uint32_t kdf_iteration_count;
uint32_t kdf_salt_len; /* in bytes */
uint8_t kdf_salt[32];
uint32_t blob_enc_iv_size;
uint8_t blob_enc_iv[32];
uint32_t blob_enc_key_bits;
uint32_t blob_enc_algorithm;
uint32_t blob_enc_padding;
uint32_t blob_enc_mode;
uint32_t encrypted_keyblob_size;
uint8_t encrypted_keyblob[0x30];
} cencrypted_v2_pwheader;
uint32_t fs_swap32(uint32_t x)
{
x = (x>>24) |
((x<<8) & 0x00FF0000) |
((x>>8) & 0x0000FF00) |
(x<<24);
return x;
}
uint32_t fs_endian_swap32(uint32_t x)
{
#ifdef __i386__
x = fs_swap32(x);
#endif
return x;
}
uint64_t fs_endian_swap64(uint64_t x)
{
#ifdef __i386__
x = ((uint64_t) fs_endian_swap32((uint32_t)(x >> 32))) | (((uint64_t) fs_endian_swap32((uint32_t) (x & 0xFFFFFFFF))) << 32);
#endif
return x;
}
void adjust_v2_header_byteorder(cencrypted_v2_pwheader *pwhdr)
{
pwhdr->blocksize = fs_endian_swap32(pwhdr->blocksize);
pwhdr->datasize = fs_endian_swap64(pwhdr->datasize);
pwhdr->dataoffset = fs_endian_swap64(pwhdr->dataoffset);
pwhdr->kdf_algorithm = fs_endian_swap32(pwhdr->kdf_algorithm);
pwhdr->kdf_prng_algorithm = fs_endian_swap32(pwhdr->kdf_prng_algorithm);
pwhdr->kdf_iteration_count = fs_endian_swap32(pwhdr->kdf_iteration_count);
pwhdr->kdf_salt_len = fs_endian_swap32(pwhdr->kdf_salt_len);
pwhdr->blob_enc_iv_size = fs_endian_swap32(pwhdr->blob_enc_iv_size);
pwhdr->blob_enc_key_bits = fs_endian_swap32(pwhdr->blob_enc_key_bits);
pwhdr->blob_enc_algorithm = fs_endian_swap32(pwhdr->blob_enc_algorithm);
pwhdr->blob_enc_padding = fs_endian_swap32(pwhdr->blob_enc_padding);
pwhdr->blob_enc_mode = fs_endian_swap32(pwhdr->blob_enc_mode);
pwhdr->encrypted_keyblob_size = fs_endian_swap32(pwhdr->encrypted_keyblob_size);
}
void convert_hex(const char *str, uint8_t *bytes, int len)
{
int rpos, wpos = 0;
for(rpos = 0; rpos < len; rpos++)
sscanf(&str[rpos*2], "%02hhx", &bytes[wpos++]);
}
HMAC_CTX hmacsha1_ctx;
AES_KEY aes_decrypt_key;
uint32_t CHUNK_SIZE = 4096;
void dump_hex(uint8_t *buf, uint8_t size)
{
int i = 0;
for(i = 0;i < size;i++)
printf("%02X",buf[i]);
printf("\n");
}
void compute_iv(uint32_t chunk_no, uint8_t *iv)
{
unsigned char mdResult[SHA_DIGEST_LENGTH];
unsigned int mdLen;
chunk_no = ntohl(chunk_no);
HMAC_Init_ex(&hmacsha1_ctx, NULL, 0, NULL, NULL);
HMAC_Update(&hmacsha1_ctx, (unsigned char *)&chunk_no, sizeof(uint32_t));
HMAC_Final(&hmacsha1_ctx, mdResult, &mdLen);
memcpy(iv, mdResult, AES_BLOCK_SIZE);
}
void decrypt_chunk(uint8_t *ctext, uint8_t *ptext, uint32_t chunk_no)
{
uint8_t iv[AES_BLOCK_SIZE];
compute_iv(chunk_no, iv);
AES_cbc_encrypt(ctext, ptext, CHUNK_SIZE, &aes_decrypt_key, iv, AES_DECRYPT);
}
int decryptRootFS(const char* key, const char* filename, const char* output)
{
FILE *in, *out;
cencrypted_v2_pwheader v2header;
uint8_t hmacsha1_key[SHA_DIGEST_LENGTH], aes_key[AES_BLOCK_SIZE], *inbuf, *outbuf;
uint32_t chunk_no;
convert_hex(key, aes_key, AES_BLOCK_SIZE);
convert_hex(key + 2 * AES_BLOCK_SIZE, hmacsha1_key, SHA_DIGEST_LENGTH);
if ((in = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "Error: unable to open %s\n", filename);
return -1;
}
if ((out = fopen(output, "wb")) == NULL)
{
fprintf(stderr, "Error: unable to open %s\n", output);
return -1;
}
fseek(in, 0L, SEEK_SET);
if (fread(&v2header, sizeof(cencrypted_v2_pwheader), 1, in) < 1)
{
fprintf(stderr, "RootFS header corrupted\n");
return -1;
}
adjust_v2_header_byteorder(&v2header);
CHUNK_SIZE = v2header.blocksize;
HMAC_CTX_init(&hmacsha1_ctx);
HMAC_Init_ex(&hmacsha1_ctx, hmacsha1_key, sizeof(hmacsha1_key), EVP_sha1(), NULL);
AES_set_decrypt_key(aes_key, AES_BLOCK_SIZE * 8, &aes_decrypt_key);
fseek(in, (uint32_t)v2header.dataoffset, SEEK_SET);
inbuf = (uint8_t*)malloc(CHUNK_SIZE);
outbuf = (uint8_t*)malloc(CHUNK_SIZE);
chunk_no = 0;
while(fread(inbuf, CHUNK_SIZE, 1, in) > 0)
{
decrypt_chunk(inbuf, outbuf, chunk_no);
chunk_no++;
if(((uint32_t)v2header.datasize - ftell(out)) < CHUNK_SIZE)
{
fwrite(outbuf, (uint32_t)v2header.datasize - ftell(out), 1, out);
break;
}
fwrite(outbuf, CHUNK_SIZE, 1, out);
}
free(inbuf);
free(outbuf);
fclose(in);
fclose(out);
return 0;
}