summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c82
1 files changed, 51 insertions, 31 deletions
diff --git a/main.c b/main.c
index 95b8587..faeb4c8 100644
--- a/main.c
+++ b/main.c
@@ -8,21 +8,30 @@
const char *hexchars = "0123456789ABCDEF";
typedef struct s_key_search_ctx {
- uint64_t ciphertext; // first 8 bytes of the ciphertext in encrypted QQ flash image
- uint64_t yield; // if routine `yield_possible_key` returns true, the possible 64-bit DES key will be stored here
- uint32_t next_possible_key; // 4 byte effective key space
+ /* first 8 bytes of the ciphertext in encrypted QQ flash image */
+ uint64_t ciphertext;
+ /* if routine `yield_possible_key` returns true,
+ * the possible 64-bit DES key will be stored here */
+ uint64_t yield;
+ /* 4 byte effective key space */
+ uint32_t next_possible_key;
bool finished;
} key_search_ctx;
/* constructor of type `key_search_ctx` */
-void new_key_search_ctx(key_search_ctx *ctx, uint64_t ciphertext) {
+void new_key_search_ctx(
+ key_search_ctx *ctx,
+ uint64_t ciphertext,
+ uint32_t a
+) {
ctx->finished = false;
- ctx->next_possible_key = 0u;
+ ctx->next_possible_key = a;
ctx->ciphertext = ciphertext;
}
-/* returns false if no result yield from this call and searching is finished */
-bool yield_possible_key(key_search_ctx *ctx) {
+/* search key in range [a, b), returns false if
+ * no result yield from this call and searching is finished */
+bool yield_possible_key(key_search_ctx *ctx, uint32_t b) {
if (ctx->finished) return false;
// const char[] hexchars = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
@@ -46,7 +55,8 @@ bool yield_possible_key(key_search_ctx *ctx) {
FILL_KEY(key, k, 7);
// decrypt file header with this key
int err;
- if ((err = des_setup((const unsigned char *) key, 8, 0, &skey)) != CRYPT_OK) {
+ if ((err = des_setup((const unsigned char *) key, 8, 0, &skey)) !=
+ CRYPT_OK) {
fprintf(stderr, "Err: setup: %s", error_to_string(err));
return false;
}
@@ -59,8 +69,8 @@ bool yield_possible_key(key_search_ctx *ctx) {
// validate first 3 bytes of the cleartext
if ((plaintext & 0xFFFFFFu) == 0xFFD8FFu) {
ctx->yield = *(uint64_t *) key;
- // if next_possible_key rewinds to 0, finished will be set to true
- ctx->finished = !++ctx->next_possible_key;
+ // if current `k` goes out of range, finished will be set to true
+ ctx->finished = k >= b;
return true;
}
} while ((k = ++ctx->next_possible_key));
@@ -68,7 +78,8 @@ bool yield_possible_key(key_search_ctx *ctx) {
return false;
}
-/* given buf, returns length of the pad, or -1 if the data is not padded with valid pkcs7 */
+/* given buf, returns length of the pad, or -1 if
+ * the data is not padded with valid pkcs7 */
int pkcs7_check_pad(const char *buf, size_t n) {
if (!n) return -1;
--n;
@@ -90,13 +101,14 @@ int main(int argc, char *argv[]) {
if (argc != 2 && argc != 3) {
printf("Usage: %s <fp_file> [<where_to_save_the_decrypted_file>]\n"
- "The decrypted image won't be saved if save path is not specified.\n",
+ "The decrypted image won't be saved if "
+ "save path is not specified.\n",
argv[0]);
return 0;
}
- const char* plaintext_save_path = (argc == 3) ? (argv[2]) : NULL;
- const char* ciphertext_file_path = argv[1];
+ const char *plaintext_save_path = (argc == 3) ? (argv[2]) : NULL;
+ const char *ciphertext_file_path = argv[1];
// open file
if (!(fp = fopen(ciphertext_file_path, "rb"))) {
@@ -125,11 +137,14 @@ int main(int argc, char *argv[]) {
const unsigned long ciphertext_length = file_length - 8;
if (ciphertext_length % 8 != 0) {
- fprintf(stderr, "Invalid file length: %ld can not be divided by 8.\n", file_length);
+ fprintf(stderr, "Invalid file length: %ld can not be divided by 8.\n",
+ file_length);
return 1;
}
char *ciphertext = malloc(ciphertext_length);
- char *plaintext = malloc(ciphertext_length); // for the future decryption use, padded plaintext (pkcs7)
+ /* this buffer is for the future decryption usage,
+ * storing padded plaintext (pkcs7) */
+ char *plaintext = malloc(ciphertext_length);
if (ciphertext == NULL || plaintext == NULL) {
perror("malloc");
return 1;
@@ -141,27 +156,28 @@ int main(int argc, char *argv[]) {
return 1;
}
- // start searching
+ /* start searching */
printf("Searching key...\n");
fflush(stdout);
key_search_ctx ctx;
new_key_search_ctx(&ctx, *(uint64_t *) ciphertext);
- // FOR DEBUGGING ONLY
+ /* FOR DEBUGGING ONLY */
// assert(*(uint64_t *) ciphertext == 8022485120222247589ull);
// ctx.next_possible_key = 0xA0979B6Du;
while (yield_possible_key(&ctx)) {
- // found a possible correct key
- // validate it by calculating md5 hashsum of the plaintext
+ /* found a possible correct key */
+ /* validate it by calculating md5 hashsum of the plaintext */
printf("Possible key: %zu\n", ctx.yield);
fflush(stdout);
- // decrypt the whole ciphertext
+ /* decrypt the whole ciphertext */
int err;
symmetric_key skey;
- if ((err = des_setup((const unsigned char *) (&ctx.yield), 8, 0, &skey)) != CRYPT_OK) {
+ if ((err = des_setup((const unsigned char *) (&ctx.yield), 8, 0,
+ &skey)) != CRYPT_OK) {
fprintf(stderr, "Err: setup: %s", error_to_string(err));
- continue; // skip this key
+ continue;
}
uint_fast32_t blk_cnt = ciphertext_length >> 3;
@@ -170,28 +186,31 @@ int main(int argc, char *argv[]) {
(const unsigned char *) ((uint64_t *) ciphertext + blk),
(unsigned char *) ((uint64_t *) plaintext + blk),
(const symmetric_key *) &skey
- ); // error checking is unnecessary
+ );
+ /* error checking is unnecessary here */
}
int pad_length = pkcs7_check_pad(plaintext, ciphertext_length);
const unsigned int unpadded_length = ciphertext_length - pad_length;
assert(pad_length < ciphertext_length);
if (pad_length < 0) {
- // invalid pad, this key is incorrect, skip it
+ /* invalid pad, this key is incorrect, skip it */
fprintf(stderr, "Invalid pad.\n");
continue;
}
- // calculate md5 checksum of the decrypted plaintext
+ /* calculate md5 checksum of the decrypted plaintext */
char md5_out[16];
hash_state md;
md5_init(&md);
md5_process(&md, (const unsigned char *) plaintext, unpadded_length);
md5_done(&md, (unsigned char *) md5_out);
- // compare md5_out[0~3] with 8-byte ASCII hex string ctx.yield
- char md5_hex[8+1]; // hex of first 4-byte of md5_out, 1 more byte to hold the '\0' terminator
- snprintf(md5_hex, 8+1, "%02X%02X%02X%02X",
+ /* compare md5_out[0~3] with 8-byte ASCII hex string ctx.yield */
+ /* hex of first 4-byte of md5_out,
+ * 1 more byte to hold the '\0' terminator */
+ char md5_hex[8 + 1];
+ snprintf(md5_hex, 8 + 1, "%02X%02X%02X%02X",
md5_out[0] & 0xFFu, md5_out[1] & 0xFFu,
md5_out[2] & 0xFFu, md5_out[3] & 0xFFu);
if (!memcmp(md5_hex, (const char *) (&ctx.yield), 8)) {
@@ -205,12 +224,13 @@ int main(int argc, char *argv[]) {
}
fwrite(plaintext, 1, unpadded_length, fout);
fclose(fout);
- printf("Flash photo has been saved in: %s\n", plaintext_save_path);
+ printf("Flash photo has been saved in: %s\n",
+ plaintext_save_path);
}
return 0;
}
- // otherwise the key is incorrect, continue searching
+ /* otherwise the key is incorrect, continue searching */
}
return 0;