diff options
-rw-r--r-- | main.c | 82 |
1 files changed, 51 insertions, 31 deletions
@@ -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; |