add dlink-sge-image for D-Link devices by SGE
[project/firmware-utils.git] / src / dlink-sge-image.c
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 }