1 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT 2 /* 3 * Copyright (C) 2023 Sebastian Schaper <openwrt@sebastianschaper.net> 4 * 5 * This tool encrypts factory images for certain D-Link Devices 6 * manufactured by SGE / T&W, e.g. COVR-C1200, COVR-P2500, DIR-882, ... 7 * 8 * Usage: 9 * ./dlink-sge-image DEVICE_MODEL infile outfile [-d: decrypt] 10 * 11 */ 12 13 #include "dlink-sge-image.h" 14 15 #include <openssl/evp.h> 16 #include <openssl/pem.h> 17 18 #include <arpa/inet.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #define BUFSIZE 4096 24 25 #define HEAD_MAGIC "SHRS" 26 #define HEAD_MAGIC_LEN 4 27 #define SHA512_DIGEST_LENGTH 64 28 #define RSA_KEY_LENGTH_BYTES 512 29 #define AES_BLOCK_SIZE 16 30 #define HEADER_LEN 1756 31 32 unsigned char aes_iv[AES_BLOCK_SIZE]; 33 34 unsigned char readbuf[BUFSIZE]; 35 unsigned char encbuf[BUFSIZE]; 36 37 unsigned int read_bytes; 38 unsigned long read_total; 39 unsigned int i; 40 41 unsigned char vendor_key[AES_BLOCK_SIZE]; 42 BIO *rsa_private_bio; 43 const EVP_CIPHER *aes128; 44 EVP_CIPHER_CTX *aes_ctx; 45 46 FILE *input_file; 47 FILE *output_file; 48 49 int pass_cb(char *buf, int size, int rwflag, void *u) 50 { 51 char *tmp = "12345678"; 52 size_t len = strlen(tmp); 53 54 if (len > size) 55 len = size; 56 memcpy(buf, tmp, len); 57 return len; 58 } 59 60 void image_encrypt(void) 61 { 62 char buf[HEADER_LEN]; 63 const EVP_MD *sha512; 64 EVP_MD_CTX *digest_before; 65 EVP_MD_CTX *digest_post; 66 EVP_MD_CTX *digest_vendor; 67 EVP_PKEY *signing_key; 68 EVP_PKEY_CTX *rsa_ctx; 69 uint32_t payload_length_before, pad_len, sizebuf; 70 unsigned char md_before[SHA512_DIGEST_LENGTH]; 71 unsigned char md_post[SHA512_DIGEST_LENGTH]; 72 unsigned char md_vendor[SHA512_DIGEST_LENGTH]; 73 unsigned char sigret[RSA_KEY_LENGTH_BYTES]; 74 size_t siglen; 75 char footer[] = {0x00, 0x00, 0x00, 0x00, 0x30}; 76 77 // seek to position 1756 (begin of AES-encrypted data), 78 // write image headers later 79 memset(buf, 0, HEADER_LEN); 80 fwrite(&buf, 1, HEADER_LEN, output_file); 81 digest_before = EVP_MD_CTX_new(); 82 digest_post = EVP_MD_CTX_new(); 83 digest_vendor = EVP_MD_CTX_new(); 84 sha512 = EVP_sha512(); 85 EVP_DigestInit_ex(digest_before, sha512, NULL); 86 EVP_DigestInit_ex(digest_post, sha512, NULL); 87 EVP_DigestInit_ex(digest_vendor, sha512, NULL); 88 89 signing_key = PEM_read_bio_PrivateKey(rsa_private_bio, NULL, pass_cb, NULL); 90 rsa_ctx = EVP_PKEY_CTX_new(signing_key, NULL); 91 92 EVP_PKEY_sign_init(rsa_ctx); 93 EVP_PKEY_CTX_set_signature_md(rsa_ctx, sha512); 94 95 memcpy(&aes_iv, &salt, AES_BLOCK_SIZE); 96 aes_ctx = EVP_CIPHER_CTX_new(); 97 EVP_EncryptInit_ex(aes_ctx, aes128, NULL, &vendor_key[0], aes_iv); 98 EVP_CIPHER_CTX_set_padding(aes_ctx, 0); 99 int outlen; 100 101 while ((read_bytes = fread(&readbuf, 1, BUFSIZE, input_file)) == BUFSIZE) { 102 EVP_DigestUpdate(digest_before, &readbuf[0], read_bytes); 103 read_total += read_bytes; 104 105 EVP_EncryptUpdate(aes_ctx, encbuf, &outlen, &readbuf[0], BUFSIZE); 106 fwrite(&encbuf, 1, BUFSIZE, output_file); 107 108 EVP_DigestUpdate(digest_post, &encbuf[0], BUFSIZE); 109 } 110 111 // handle last block of data (read_bytes < BUFSIZE) 112 EVP_DigestUpdate(digest_before, &readbuf[0], read_bytes); 113 read_total += read_bytes; 114 115 pad_len = AES_BLOCK_SIZE - (read_total % AES_BLOCK_SIZE); 116 if (pad_len == 0) 117 pad_len = AES_BLOCK_SIZE; 118 memset(&readbuf[read_bytes], 0, pad_len); 119 120 EVP_EncryptUpdate(aes_ctx, encbuf, &outlen, &readbuf[0], read_bytes + pad_len); 121 EVP_CIPHER_CTX_free(aes_ctx); 122 fwrite(&encbuf, 1, read_bytes + pad_len, output_file); 123 124 EVP_DigestUpdate(digest_post, &encbuf[0], read_bytes + pad_len); 125 126 fclose(input_file); 127 payload_length_before = read_total; 128 printf("\npayload_length_before: %li\n", read_total); 129 130 // copy digest state, since we need another one with vendor key appended 131 EVP_MD_CTX_copy_ex(digest_vendor, digest_before); 132 133 EVP_DigestFinal_ex(digest_before, &md_before[0], NULL); 134 EVP_MD_CTX_free(digest_before); 135 136 printf("\ndigest_before: "); 137 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 138 printf("%02x", md_before[i]); 139 140 EVP_DigestUpdate(digest_vendor, &vendor_key[0], AES_BLOCK_SIZE); 141 EVP_DigestFinal_ex(digest_vendor, &md_vendor[0], NULL); 142 EVP_MD_CTX_free(digest_vendor); 143 144 printf("\ndigest_vendor: "); 145 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 146 printf("%02x", md_vendor[i]); 147 148 EVP_DigestFinal_ex(digest_post, &md_post[0], NULL); 149 EVP_MD_CTX_free(digest_post); 150 151 printf("\ndigest_post: "); 152 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 153 printf("%02x", md_post[i]); 154 155 fwrite(&footer, 1, 5, output_file); 156 157 // go back to file header and write all the digests and signatures 158 fseek(output_file, 0, SEEK_SET); 159 160 fwrite(HEAD_MAGIC, 1, HEAD_MAGIC_LEN, output_file); 161 162 // write payload length before 163 sizebuf = htonl(payload_length_before); 164 fwrite((char *) &sizebuf, 1, 4, output_file); 165 166 // write payload length post 167 payload_length_before += pad_len; 168 sizebuf = htonl(payload_length_before); 169 fwrite((char *) &sizebuf, 1, 4, output_file); 170 171 // write salt and digests 172 fwrite(salt, 1, AES_BLOCK_SIZE, output_file); 173 fwrite(&md_vendor[0], 1, SHA512_DIGEST_LENGTH, output_file); 174 fwrite(&md_before[0], 1, SHA512_DIGEST_LENGTH, output_file); 175 fwrite(&md_post[0], 1, SHA512_DIGEST_LENGTH, output_file); 176 177 // zero-fill rsa_pub field, unused in header 178 memset(sigret, 0, RSA_KEY_LENGTH_BYTES); 179 fwrite(&sigret[0], 1, RSA_KEY_LENGTH_BYTES, output_file); 180 181 // sign md_before 182 EVP_PKEY_sign(rsa_ctx, &sigret[0], &siglen, &md_before[0], SHA512_DIGEST_LENGTH); 183 printf("\nsigned before:\n"); 184 for (i = 0; i < RSA_KEY_LENGTH_BYTES; i++) 185 printf("%02x", sigret[i]); 186 fwrite(&sigret[0], 1, RSA_KEY_LENGTH_BYTES, output_file); 187 188 // sign md_post 189 EVP_PKEY_sign(rsa_ctx, &sigret[0], &siglen, &md_post[0], SHA512_DIGEST_LENGTH); 190 printf("\nsigned post:\n"); 191 for (i = 0; i < RSA_KEY_LENGTH_BYTES; i++) 192 printf("%02x", sigret[i]); 193 fwrite(&sigret[0], 1, RSA_KEY_LENGTH_BYTES, output_file); 194 195 printf("\n"); 196 197 fclose(output_file); 198 } 199 200 void image_decrypt(void) 201 { 202 char magic[4]; 203 uint32_t payload_length_before, payload_length_post, pad_len; 204 char salt[AES_BLOCK_SIZE]; 205 char md_vendor[SHA512_DIGEST_LENGTH]; 206 char md_before[SHA512_DIGEST_LENGTH]; 207 char md_post[SHA512_DIGEST_LENGTH]; 208 EVP_PKEY *signing_key; 209 EVP_PKEY_CTX *rsa_ctx; 210 unsigned char rsa_sign_before[RSA_KEY_LENGTH_BYTES]; 211 unsigned char rsa_sign_post[RSA_KEY_LENGTH_BYTES]; 212 unsigned char md_post_actual[SHA512_DIGEST_LENGTH]; 213 unsigned char md_before_actual[SHA512_DIGEST_LENGTH]; 214 unsigned char md_vendor_actual[SHA512_DIGEST_LENGTH]; 215 const EVP_MD *sha512; 216 EVP_MD_CTX *digest_before; 217 EVP_MD_CTX *digest_post; 218 EVP_MD_CTX *digest_vendor; 219 220 printf("\ndecrypt mode\n"); 221 222 if (fread(&magic, 1, HEAD_MAGIC_LEN, input_file) == 0) 223 goto error_read; 224 if (strncmp(magic, HEAD_MAGIC, HEAD_MAGIC_LEN) != 0) { 225 fprintf(stderr, "Input File header magic does not match '%s'.\n" 226 "Maybe this file is not encrypted?\n", HEAD_MAGIC); 227 goto error; 228 } 229 230 if (fread((char *) &payload_length_before, 1, 4, input_file) == 0) 231 goto error_read; 232 if (fread((char *) &payload_length_post, 1, 4, input_file) == 0) 233 goto error_read; 234 payload_length_before = ntohl(payload_length_before); 235 payload_length_post = ntohl(payload_length_post); 236 237 if (fread(salt, 1, AES_BLOCK_SIZE, input_file) == 0) 238 goto error_read; 239 if (fread(md_vendor, 1, SHA512_DIGEST_LENGTH, input_file) == 0) 240 goto error_read; 241 if (fread(md_before, 1, SHA512_DIGEST_LENGTH, input_file) == 0) 242 goto error_read; 243 if (fread(md_post, 1, SHA512_DIGEST_LENGTH, input_file) == 0) 244 goto error_read; 245 246 // skip rsa_pub 247 if (fread(readbuf, 1, RSA_KEY_LENGTH_BYTES, input_file) == 0) 248 goto error_read; 249 250 if (fread(rsa_sign_before, 1, RSA_KEY_LENGTH_BYTES, input_file) == 0) 251 goto error_read; 252 if (fread(rsa_sign_post, 1, RSA_KEY_LENGTH_BYTES, input_file) == 0) 253 goto error_read; 254 255 // file should be at position HEADER_LEN now, start AES decryption 256 digest_before = EVP_MD_CTX_new(); 257 digest_post = EVP_MD_CTX_new(); 258 digest_vendor = EVP_MD_CTX_new(); 259 sha512 = EVP_sha512(); 260 EVP_DigestInit_ex(digest_before, sha512, NULL); 261 EVP_DigestInit_ex(digest_post, sha512, NULL); 262 EVP_DigestInit_ex(digest_vendor, sha512, NULL); 263 264 memcpy(&aes_iv, &salt, AES_BLOCK_SIZE); 265 aes_ctx = EVP_CIPHER_CTX_new(); 266 EVP_DecryptInit_ex(aes_ctx, aes128, NULL, &vendor_key[0], aes_iv); 267 EVP_CIPHER_CTX_set_padding(aes_ctx, 0); 268 int outlen; 269 pad_len = payload_length_post - payload_length_before; 270 271 while (read_total < payload_length_post) { 272 if (read_total + BUFSIZE <= payload_length_post) 273 read_bytes = fread(&readbuf, 1, BUFSIZE, input_file); 274 else 275 read_bytes = fread(&readbuf, 1, payload_length_post - read_total, \ 276 input_file); 277 278 read_total += read_bytes; 279 280 EVP_DigestUpdate(digest_post, &readbuf[0], read_bytes); 281 282 EVP_DecryptUpdate(aes_ctx, encbuf, &outlen, &readbuf[0], read_bytes); 283 284 // only update digest_before until payload_length_before, 285 // do not hash decrypted padding 286 if (read_total > payload_length_before) { 287 // only calc hash for data before padding 288 EVP_DigestUpdate(digest_before, &encbuf[0], read_bytes - pad_len); 289 fwrite(&encbuf[0], 1, read_bytes - pad_len, output_file); 290 291 // copy digest state, since we need another one with vendor key appended 292 EVP_MD_CTX_copy_ex(digest_vendor, digest_before); 293 294 // append vendor_key 295 EVP_DigestUpdate(digest_vendor, &vendor_key[0], AES_BLOCK_SIZE); 296 } else { 297 // calc hash for all of read_bytes 298 EVP_DigestUpdate(digest_before, &encbuf[0], read_bytes); 299 fwrite(&encbuf[0], 1, read_bytes, output_file); 300 } 301 } 302 303 fclose(input_file); 304 fclose(output_file); 305 EVP_CIPHER_CTX_free(aes_ctx); 306 307 EVP_DigestFinal_ex(digest_post, &md_post_actual[0], NULL); 308 EVP_MD_CTX_free(digest_post); 309 310 printf("\ndigest_post: "); 311 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 312 printf("%02x", md_post_actual[i]); 313 314 if (strncmp(md_post, (char *) md_post_actual, SHA512_DIGEST_LENGTH) != 0) { 315 fprintf(stderr, "SHA512 post does not match file contents.\n"); 316 goto error; 317 } 318 319 EVP_DigestFinal_ex(digest_before, &md_before_actual[0], NULL); 320 EVP_MD_CTX_free(digest_before); 321 322 printf("\ndigest_before: "); 323 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 324 printf("%02x", md_before_actual[i]); 325 326 if (strncmp(md_before, (char *) md_before_actual, SHA512_DIGEST_LENGTH) != 0) { 327 fprintf(stderr, "SHA512 before does not match decrypted payload.\n"); 328 goto error; 329 } 330 331 EVP_DigestFinal_ex(digest_vendor, &md_vendor_actual[0], NULL); 332 EVP_MD_CTX_free(digest_vendor); 333 334 printf("\ndigest_vendor: "); 335 for (i = 0; i < SHA512_DIGEST_LENGTH; i++) 336 printf("%02x", md_vendor_actual[i]); 337 338 if (strncmp(md_vendor, (char *) md_vendor_actual, SHA512_DIGEST_LENGTH) != 0) { 339 fprintf(stderr, "SHA512 vendor does not match decrypted payload padded" \ 340 " with vendor key.\n"); 341 goto error; 342 } 343 344 signing_key = PEM_read_bio_PrivateKey(rsa_private_bio, NULL, pass_cb, NULL); 345 rsa_ctx = EVP_PKEY_CTX_new(signing_key, NULL); 346 EVP_PKEY_verify_init(rsa_ctx); 347 EVP_PKEY_CTX_set_signature_md(rsa_ctx, sha512); 348 349 if (EVP_PKEY_verify(rsa_ctx, &rsa_sign_before[0], RSA_KEY_LENGTH_BYTES, \ 350 &md_before_actual[0], SHA512_DIGEST_LENGTH)) { 351 printf("\nsignature before verification success"); 352 } else { 353 fprintf(stderr, "Signature before verification failed.\nThe decrypted" \ 354 " image file may however be flashable via bootloader recovery.\n"); 355 } 356 357 if (EVP_PKEY_verify(rsa_ctx, &rsa_sign_post[0], RSA_KEY_LENGTH_BYTES, \ 358 &md_post_actual[0], SHA512_DIGEST_LENGTH)) { 359 printf("\nsignature post verification success"); 360 } else { 361 fprintf(stderr, "Signature post verification failed.\nThe decrypted" \ 362 " image file may however be flashable via bootloader recovery.\n"); 363 } 364 365 printf("\n"); 366 367 return; 368 369 error_read: 370 fprintf(stderr, "Error reading header fields from input file.\n"); 371 error: 372 fclose(input_file); 373 fclose(output_file); 374 exit(1); 375 } 376 377 /* 378 generate legacy vendor key for COVR-C1200, COVR-P2500, DIR-882, DIR-2660, ... 379 decrypt ciphertext key2 using aes128 with key1 and iv, write result to *vkey 380 */ 381 void generate_vendorkey_legacy(unsigned char *vkey) 382 { 383 int outlen; 384 memcpy(&aes_iv, &iv, AES_BLOCK_SIZE); 385 aes_ctx = EVP_CIPHER_CTX_new(); 386 EVP_DecryptInit_ex(aes_ctx, aes128, NULL, &key1[0], &aes_iv[0]); 387 EVP_CIPHER_CTX_set_padding(aes_ctx, 0); 388 EVP_DecryptUpdate(aes_ctx, vkey, &outlen, &key2[0], AES_BLOCK_SIZE); 389 EVP_CIPHER_CTX_free(aes_ctx); 390 } 391 392 /* 393 helper function for generate_vendorkey_dimgkey() 394 deinterleave input in chunks of 8 bytes according to pattern, 395 last block shorter than 8 bytes is appended in reverse order 396 */ 397 void deinterleave(unsigned char *enk, size_t len, unsigned char *vkey) 398 { 399 unsigned char i, pattern = 0; 400 401 while (len >= INTERLEAVE_BLOCK_SIZE) 402 { 403 for (i = 0; i < INTERLEAVE_BLOCK_SIZE; i++) 404 *(vkey + i) = *(enk + interleaving_pattern[pattern][i]); 405 406 vkey += INTERLEAVE_BLOCK_SIZE; 407 enk += INTERLEAVE_BLOCK_SIZE; 408 len -= INTERLEAVE_BLOCK_SIZE; 409 410 if (pattern++ >= INTERLEAVE_BLOCK_SIZE) 411 pattern = 0; 412 } 413 414 for (i = 0; i < len; i++) 415 *(vkey + i) = *(enk + (len - i - 1)); 416 } 417 418 /* 419 generate vendor key for COVR-X1860, DIR-X3260, ... 420 base64 decode enk, pass to deinterleave, result will be in *vkey 421 */ 422 void generate_vendorkey_dimgkey(const unsigned char *enk, size_t len, unsigned char *vkey) 423 { 424 unsigned char *decode_buf = malloc(3 * (len / 4)); 425 int outlen; 426 EVP_ENCODE_CTX *base64_ctx = EVP_ENCODE_CTX_new(); 427 EVP_DecodeInit(base64_ctx); 428 EVP_DecodeUpdate(base64_ctx, decode_buf, &outlen, enk, len); 429 EVP_DecodeFinal(base64_ctx, decode_buf + outlen, &outlen); 430 EVP_ENCODE_CTX_free(base64_ctx); 431 432 // limit deinterleaving output to first 16 bytes 433 deinterleave(decode_buf, AES_BLOCK_SIZE, vkey); 434 } 435 436 int main(int argc, char **argv) 437 { 438 if (argc < 3 || argc > 5) { 439 fprintf(stderr, "Usage:\n" 440 "\tdlink-sge-image DEVICE_MODEL infile outfile [-d: decrypt]\n\n" 441 "DEVICE_MODEL can be any of:\n" 442 "\tCOVR-C1200\n" 443 "\tCOVR-P2500\n" 444 "\tCOVR-X1860\n" 445 "\tDIR-853\n" 446 "\tDIR-867\n" 447 "\tDIR-878\n" 448 "\tDIR-882\n" 449 "\tDIR-1935\n" 450 "\tDIR-2150\n" 451 "\tDIR-X3260\n\n" 452 "Any other value will default to COVR-C1200/P2500/DIR-8xx keys\n" 453 "which may work to decrypt images for several further devices,\n" 454 "however there are currently no private keys known that would\n" 455 "allow for signing images to be used for flashing those devices.\n\n" 456 ); 457 exit(1); 458 } 459 460 input_file = fopen(argv[2], "rb"); 461 if (input_file == NULL) { 462 fprintf(stderr, "Input File %s could not be opened.\n", argv[2]); 463 exit(1); 464 } 465 466 output_file = fopen(argv[3], "wb"); 467 if (input_file == NULL) { 468 fprintf(stderr, "Output File %s could not be opened.\n", argv[3]); 469 fclose(input_file); 470 exit(1); 471 } 472 473 aes128 = EVP_aes_128_cbc(); 474 475 if (strncmp(argv[1], "COVR-X1860", 10) == 0) 476 { 477 generate_vendorkey_dimgkey(enk_covrx1860, sizeof(enk_covrx1860), &vendor_key[0]); 478 rsa_private_bio = BIO_new_mem_buf(key_covrx1860_pem, -1); 479 } 480 else if (strncmp(argv[1], "DIR-X3260", 9) == 0) 481 { 482 generate_vendorkey_dimgkey(enk_dirx3260, sizeof(enk_dirx3260), &vendor_key[0]); 483 rsa_private_bio = BIO_new_mem_buf(key_dirx3260_pem, -1); 484 } 485 else if (strncmp(argv[1], "DIR-1260", 8) == 0) 486 { 487 generate_vendorkey_legacy(&vendor_key[0]); 488 rsa_private_bio = BIO_new_mem_buf(key_dir1260_pem, -1); 489 } 490 else if (strncmp(argv[1], "DIR-2150", 8) == 0) 491 { 492 generate_vendorkey_legacy(&vendor_key[0]); 493 rsa_private_bio = BIO_new_mem_buf(key_dir2150_pem, -1); 494 } 495 else 496 { 497 /* COVR-C1200, COVR-P2500, DIR-853, DIR-867, DIR-878, DIR-882, DIR-1935 */ 498 generate_vendorkey_legacy(&vendor_key[0]); 499 rsa_private_bio = BIO_new_mem_buf(key_legacy_pem, -1); 500 } 501 502 printf("\nvendor_key: "); 503 for (i = 0; i < AES_BLOCK_SIZE; i++) 504 printf("%02x", vendor_key[i]); 505 506 if (argc == 5 && strncmp(argv[4], "-d", 2) == 0) 507 image_decrypt(); 508 else 509 image_encrypt(); 510 } 511
This page was automatically generated by LXR 0.3.1. • OpenWrt