summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2020-06-13 16:21:16 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2020-10-11 13:08:03 +0200
commit53d2742a482eba04fab02a5f1b8a5b2fa48206e2 (patch)
tree10f04b099fad6bd3bb42b597f536c0a247fc10ab
parentcda16f9439359c79c4d8f54f63b0cdb10dc79bfb (diff)
downloadrockbox-53d2742a482eba04fab02a5f1b8a5b2fa48206e2.tar.gz
rockbox-53d2742a482eba04fab02a5f1b8a5b2fa48206e2.zip
nwztools: add support for new UPG format on post-WM1/A30 devices
The new code supports reading and writing UPG files. I kept the old keysig search code but it only supports the old format (the new format has too long keys anyway). Since we now have to support two types of encryption(DES and AES), I reorganized the crypto routines and clean-up some code. Change-Id: Ie9be220ec2431ec6d0bd11699fa0493b62e1cec2
-rw-r--r--utils/nwztools/upgtools/Makefile2
-rw-r--r--utils/nwztools/upgtools/fwp.c57
-rw-r--r--utils/nwztools/upgtools/fwp.h48
-rw-r--r--utils/nwztools/upgtools/keysig_search.c5
-rw-r--r--utils/nwztools/upgtools/keysig_search.h5
-rw-r--r--utils/nwztools/upgtools/mg.cpp105
-rw-r--r--utils/nwztools/upgtools/mg.h26
-rw-r--r--utils/nwztools/upgtools/upg.c360
-rw-r--r--utils/nwztools/upgtools/upg.h58
-rw-r--r--utils/nwztools/upgtools/upgtool.c38
10 files changed, 446 insertions, 258 deletions
diff --git a/utils/nwztools/upgtools/Makefile b/utils/nwztools/upgtools/Makefile
index 046eb1a1a9..5dede1447c 100644
--- a/utils/nwztools/upgtools/Makefile
+++ b/utils/nwztools/upgtools/Makefile
@@ -30,7 +30,7 @@ all: $(BINS)
30%.o: %.cpp 30%.o: %.cpp
31 $(CXX) $(CXXFLAGS) -c -o $@ $< 31 $(CXX) $(CXXFLAGS) -c -o $@ $<
32 32
33upgtool: upgtool.o upg.o misc.o fwp.o mg.o keysig_search.o md5.o 33upgtool: upgtool.o upg.o misc.o mg.o keysig_search.o md5.o
34 $(LD) -o $@ $^ $(LDFLAGS) 34 $(LD) -o $@ $^ $(LDFLAGS)
35 35
36clean: 36clean:
diff --git a/utils/nwztools/upgtools/fwp.c b/utils/nwztools/upgtools/fwp.c
deleted file mode 100644
index 7d8f8002a8..0000000000
--- a/utils/nwztools/upgtools/fwp.c
+++ /dev/null
@@ -1,57 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <string.h>
22#include <stdlib.h>
23#include "fwp.h"
24#include "misc.h"
25#include "mg.h"
26
27void fwp_read(void *in, int size, void *out, uint8_t *key)
28{
29 mg_decrypt_fw(in, size, out, key);
30}
31
32void fwp_write(void *in, int size, void *out, uint8_t *key)
33{
34 mg_encrypt_fw(in, size, out, key);
35}
36
37static uint8_t g_key[NWZ_KEY_SIZE];
38
39void fwp_setkey(char key[NWZ_KEY_SIZE])
40{
41 memcpy(g_key, key, NWZ_KEY_SIZE);
42}
43
44void fwp_crypt(void *buf, int size, int mode)
45{
46 while(size >= NWZ_KEY_SIZE)
47 {
48 if(mode)
49 mg_decrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key);
50 else
51 mg_encrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key);
52 buf += NWZ_KEY_SIZE;
53 size -= NWZ_KEY_SIZE;
54 }
55 if(size != 0)
56 abort(); /* size is not a multiple of 8 */
57}
diff --git a/utils/nwztools/upgtools/fwp.h b/utils/nwztools/upgtools/fwp.h
deleted file mode 100644
index 32fe260090..0000000000
--- a/utils/nwztools/upgtools/fwp.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __fwp_h__
22#define __fwp_h__
23
24#include <stdint.h>
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#define NWZ_KAS_SIZE 32
31#define NWZ_KEYSIG_SIZE 16
32#define NWZ_KEY_SIZE 8
33#define NWZ_SIG_SIZE 8
34#define NWZ_EXPKEY_SIZE (NWZ_KEY_SIZE * NWZ_KEY_SIZE)
35#define NWZ_DES_BLOCK 8
36#define NWZ_MD5_SIZE 16
37
38/* size must be a multiple of 8 */
39void fwp_read(void *in, int size, void *out, uint8_t *key);
40void fwp_write(void *in, int size, void *out, uint8_t *key);
41void fwp_setkey(char key[8]);
42void fwp_crypt(void *buf, int size, int mode);
43
44#ifdef __cplusplus
45}
46#endif
47
48#endif /* __fwp_h__ */
diff --git a/utils/nwztools/upgtools/keysig_search.c b/utils/nwztools/upgtools/keysig_search.c
index 2f234d6358..c16dae5260 100644
--- a/utils/nwztools/upgtools/keysig_search.c
+++ b/utils/nwztools/upgtools/keysig_search.c
@@ -218,11 +218,10 @@ typedef bool (*sig_validate_fn_t)(uint8_t *key);
218static bool check_key(uint8_t key[NWZ_KEY_SIZE], sig_validate_fn_t validate) 218static bool check_key(uint8_t key[NWZ_KEY_SIZE], sig_validate_fn_t validate)
219{ 219{
220 struct upg_header_t hdr; 220 struct upg_header_t hdr;
221 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr.sig), (void *)&hdr, key); 221 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr), (void *)&hdr, key);
222 if(validate(hdr.sig)) 222 if(validate(hdr.sig))
223 { 223 {
224 /* the signature looks correct, so decrypt the header futher to be sure */ 224 /* the signature looks correct, so check the header to be sure */
225 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr), (void *)&hdr, key);
226 /* we expect the number of files to be small and the padding to be 0 */ 225 /* we expect the number of files to be small and the padding to be 0 */
227 if(hdr.nr_files == 0 || hdr.nr_files > 10 || hdr.pad != 0) 226 if(hdr.nr_files == 0 || hdr.nr_files > 10 || hdr.pad != 0)
228 return false; 227 return false;
diff --git a/utils/nwztools/upgtools/keysig_search.h b/utils/nwztools/upgtools/keysig_search.h
index 877da2f89c..72649e042e 100644
--- a/utils/nwztools/upgtools/keysig_search.h
+++ b/utils/nwztools/upgtools/keysig_search.h
@@ -24,7 +24,10 @@
24#include <stdbool.h> 24#include <stdbool.h>
25#include <stdint.h> 25#include <stdint.h>
26#include <stddef.h> 26#include <stddef.h>
27#include "fwp.h" 27
28/* these values are for the V1 format */
29#define NWZ_KEY_SIZE 8
30#define NWZ_SIG_SIZE 8
28 31
29enum keysig_search_method_t 32enum keysig_search_method_t
30{ 33{
diff --git a/utils/nwztools/upgtools/mg.cpp b/utils/nwztools/upgtools/mg.cpp
index 66566770f9..4bab5d9c61 100644
--- a/utils/nwztools/upgtools/mg.cpp
+++ b/utils/nwztools/upgtools/mg.cpp
@@ -26,43 +26,96 @@
26#include <stdio.h> 26#include <stdio.h>
27 27
28using namespace CryptoPP; 28using namespace CryptoPP;
29namespace 29
30void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key)
30{ 31{
31 inline void dec_des_ecb(void *in, int size, void *out, uint8_t *key) 32 ECB_Mode< DES >::Decryption dec;
32 { 33 if(size % 8)
33 ECB_Mode< DES >::Decryption dec; 34 abort(); /* size must be a multiple of 8 */
34 if(size % 8) 35 dec.SetKey(key, 8);
35 abort(); /* size must be a multiple of 8 */ 36 dec.ProcessData((byte*)out, (byte*)in, size);
36 dec.SetKey(key, 8);
37 dec.ProcessData((byte*)out, (byte*)in, size);
38 }
39
40 inline void enc_des_ecb(void *in, int size, void *out, uint8_t *key)
41 {
42 ECB_Mode< DES >::Encryption enc;
43 if(size % 8)
44 abort(); /* size must be a multiple of 8 */
45 enc.SetKey(key, 8);
46 enc.ProcessData((byte*)out, (byte*)in, size);
47 }
48} 37}
49 38
50void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key) 39static ECB_Mode< DES >::Decryption g_des_ecb_dec;
40
41void des_ecb_dec_set_key(const uint8_t key[8])
51{ 42{
52 dec_des_ecb(in, size, out, key); 43 g_des_ecb_dec.SetKey(key, 8);
53} 44}
54 45
55void mg_encrypt_fw(void *in, int size, void *out, uint8_t *key) 46void des_ecb_dec(void *in, int size, void *out)
56{ 47{
57 enc_des_ecb(in, size, out, key); 48 if(size % 8)
49 abort(); /* size must be a multiple of 8 */
50 g_des_ecb_dec.ProcessData((byte*)out, (byte*)in, size);
58} 51}
59 52
60void mg_decrypt_pass(void *in, int size, void *out, uint8_t *key) 53static ECB_Mode< DES >::Encryption g_des_ecb_enc;
54
55void des_ecb_enc_set_key(const uint8_t key[8])
56{
57 g_des_ecb_enc.SetKey(key, 8);
58}
59
60void des_ecb_enc(void *in, int size, void *out)
61{
62 if(size % 8)
63 abort(); /* size must be a multiple of 8 */
64 g_des_ecb_enc.ProcessData((byte*)out, (byte*)in, size);
65}
66
67static ECB_Mode< AES >::Decryption g_aes_ecb_dec;
68
69void aes_ecb_dec_set_key(const uint8_t key[16])
70{
71 g_aes_ecb_dec.SetKey(key, 16);
72}
73
74void aes_ecb_dec(void *in, int size, void *out)
75{
76 if(size % 16)
77 abort(); /* size must be a multiple of 16 */
78 g_aes_ecb_dec.ProcessData((byte*)out, (byte*)in, size);
79}
80
81static ECB_Mode< AES >::Encryption g_aes_ecb_enc;
82
83void aes_ecb_enc_set_key(const uint8_t key[16])
84{
85 g_aes_ecb_enc.SetKey(key, 16);
86}
87
88void aes_ecb_enc(void *in, int size, void *out)
89{
90 if(size % 16)
91 abort(); /* size must be a multiple of 16 */
92 g_aes_ecb_enc.ProcessData((byte*)out, (byte*)in, size);
93}
94
95static CBC_Mode< AES >::Decryption g_aes_cbc_dec;
96
97void aes_cbc_dec_set_key_iv(const uint8_t key[16], const uint8_t iv[16])
98{
99 g_aes_cbc_dec.SetKeyWithIV(key, 16, iv);
100}
101
102void aes_cbc_dec(void *in, int size, void *out)
103{
104 if(size % 16)
105 abort(); /* size must be a multiple of 16 */
106 g_aes_cbc_dec.ProcessData((byte*)out, (byte*)in, size);
107}
108
109static CBC_Mode< AES >::Encryption g_aes_cbc_enc;
110
111void aes_cbc_enc_set_key_iv(const uint8_t key[16], const uint8_t iv[16])
61{ 112{
62 dec_des_ecb(in, size, out, key); 113 g_aes_cbc_enc.SetKeyWithIV(key, 16, iv);
63} 114}
64 115
65void mg_encrypt_pass(void *in, int size, void *out, uint8_t *key) 116void aes_cbc_enc(void *in, int size, void *out)
66{ 117{
67 enc_des_ecb(in, size, out, key); 118 if(size % 16)
119 abort(); /* size must be a multiple of 16 */
120 g_aes_cbc_enc.ProcessData((byte*)out, (byte*)in, size);
68} 121}
diff --git a/utils/nwztools/upgtools/mg.h b/utils/nwztools/upgtools/mg.h
index ef8dcd5ecb..fe6ec7c2f6 100644
--- a/utils/nwztools/upgtools/mg.h
+++ b/utils/nwztools/upgtools/mg.h
@@ -26,11 +26,27 @@
26#ifdef __cplusplus 26#ifdef __cplusplus
27extern "C" { 27extern "C" {
28#endif 28#endif
29/* size must be a multiple of 8 */ 29/* size must be a multiple of 8, this function is thread-safe */
30void mg_decrypt_fw(void *in, int size, void *out, uint8_t *key); 30void mg_decrypt_fw(void *in, int size, void *out, uint8_t key[8]);
31void mg_encrypt_fw(void *in, int size, void *out, uint8_t *key); 31
32void mg_decrypt_pass(void *in, int size, void *out, uint8_t *key); 32/* for simplicity, these function use some global variables, this could be
33void mg_encrypt_pass(void *in, int size, void *out, uint8_t *key); 33 * change if necessary in the future */
34
35/* DES: sizes must be a multiple of 8 */
36void des_ecb_dec_set_key(const uint8_t key[8]);
37void des_ecb_dec(void *in, int size, void *out);
38void des_ecb_enc_set_key(const uint8_t key[8]);
39void des_ecb_enc(void *in, int size, void *out);
40
41/* AES: size must be a multiple of 16 */
42void aes_ecb_dec_set_key(const uint8_t key[16]);
43void aes_ecb_dec(void *in, int size, void *out);
44void aes_ecb_enc_set_key(const uint8_t key[16]);
45void aes_ecb_enc(void *in, int size, void *out);
46void aes_cbc_dec_set_key_iv(const uint8_t key[16], const uint8_t iv[16]);
47void aes_cbc_dec(void *in, int size, void *out);
48void aes_cbc_enc_set_key_iv(const uint8_t key[16], const uint8_t iv[16]);
49void aes_cbc_enc(void *in, int size, void *out);
34#ifdef __cplusplus 50#ifdef __cplusplus
35} 51}
36#endif 52#endif
diff --git a/utils/nwztools/upgtools/upg.c b/utils/nwztools/upgtools/upg.c
index 599fbbeaf6..910c37a9bf 100644
--- a/utils/nwztools/upgtools/upg.c
+++ b/utils/nwztools/upgtools/upg.c
@@ -54,6 +54,12 @@ struct nwz_model_t g_model_list[] =
54 { 0 } 54 { 0 }
55}; 55};
56 56
57/* KEY/IV for pre-WM1/A30 models */
58static uint8_t g_des_passkey[9] = "ed295076";
59/* device after WM1/NW-A30 */
60static uint8_t g_aes_passkey[17] = "9cc4419c8bef488c";
61static uint8_t g_aes_iv[17] = "6063ce1efa1d543a";
62
57static int digit_value(char c) 63static int digit_value(char c)
58{ 64{
59 if(c >= '0' && c <= '9') return c - '0'; 65 if(c >= '0' && c <= '9') return c - '0';
@@ -67,42 +73,83 @@ static char hex_digit(unsigned v)
67 return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x'; 73 return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x';
68} 74}
69 75
70int decrypt_keysig(const char kas[NWZ_KAS_SIZE], char key[NWZ_KEY_SIZE], 76int decrypt_keysig(const char *kas, char **key, char **sig)
71 char sig[NWZ_SIG_SIZE])
72{ 77{
73 uint8_t src[NWZ_KAS_SIZE / 2]; 78 int len = strlen(kas);
74 for(int index = 0; index < NWZ_KAS_SIZE / 2; index++) 79 if(len % 2)
80 return -1; /* length must be a multiple of two */
81 uint8_t *src = malloc(len / 2);
82 for(int index = 0; index < len / 2; index++)
75 { 83 {
76 int a = digit_value(kas[index * 2]); 84 int a = digit_value(kas[index * 2]);
77 int b = digit_value(kas[index * 2 + 1]); 85 int b = digit_value(kas[index * 2 + 1]);
78 if(a < 0 || b < 0) 86 if(a < 0 || b < 0)
79 return -1; 87 return -1; /* bad digit */
80 src[index] = a << 4 | b; 88 src[index] = a << 4 | b;
81 } 89 }
82 fwp_setkey("ed295076"); 90 if(*key == NULL)
83 fwp_crypt(src, sizeof(src), 1); 91 *key = malloc(len / 4 + 1);
84 memcpy(key, src, NWZ_KEY_SIZE); 92 if(*sig == NULL)
85 memcpy(sig, src + NWZ_KEY_SIZE, NWZ_SIG_SIZE); 93 *sig = malloc(len / 4 + 1);
94
95 if(len == 32)
96 {
97 /* Device before WM1/NW-A30 use DES */
98 des_ecb_dec_set_key(g_des_passkey);
99 des_ecb_dec(src, len / 2, src);
100 }
101 else if(len == 64)
102 {
103 /* device after WM1/NW-A30 */
104 aes_cbc_dec_set_key_iv(g_aes_passkey, g_aes_iv);
105 aes_cbc_dec(src, len / 2, src);
106 }
107 else
108 {
109 free(src);
110 return -1;
111 }
112 memcpy(*key, src, len / 4);
113 (*key)[len / 4] = 0;
114 memcpy(*sig, src + len / 4, len / 4);
115 (*sig)[len / 4] = 0;
116 free(src);
86 return 0; 117 return 0;
87} 118}
88 119
89void encrypt_keysig(char kas[NWZ_KEY_SIZE], 120void encrypt_keysig(char **kas, const char *key, const char *sig)
90 const char key[NWZ_SIG_SIZE], const char sig[NWZ_KAS_SIZE])
91{ 121{
92 uint8_t src[NWZ_KAS_SIZE / 2]; 122 int len = strlen(key);
93 fwp_setkey("ed295076"); 123 if(len != strlen(sig))
94 memcpy(src, key, NWZ_KEY_SIZE); 124 abort();
95 memcpy(src + NWZ_KEY_SIZE, sig, NWZ_SIG_SIZE); 125 uint8_t *src = malloc(len * 2);
96 fwp_crypt(src, sizeof(src), 0); 126 memcpy(src, key, len);
97 for(int i = 0; i < NWZ_KAS_SIZE / 2; i++) 127 memcpy(src + len, sig, len);
128 if(len == 8)
129 {
130 des_ecb_enc_set_key(g_des_passkey);
131 des_ecb_enc(src, len * 2, src);
132 }
133 else if(len == 16)
98 { 134 {
99 kas[2 * i] = hex_digit((src[i] >> 4) & 0xf); 135 aes_cbc_enc_set_key_iv(g_aes_passkey, g_aes_iv);
100 kas[2 * i + 1] = hex_digit(src[i] & 0xf); 136 aes_cbc_enc(src, len * 2, src);
101 } 137 }
138 else
139 abort();
140 if(*kas == NULL)
141 *kas = malloc(len * 4 + 1);
142 for(int i = 0; i < len * 2; i++)
143 {
144 (*kas)[2 * i] = hex_digit((src[i] >> 4) & 0xf);
145 (*kas)[2 * i + 1] = hex_digit(src[i] & 0xf);
146 }
147 (*kas)[len * 4] = 0;
148 free(src);
102} 149}
103 150
104struct upg_file_t *upg_read_memory(void *buf, size_t size, char key[NWZ_KEY_SIZE], 151struct upg_file_t *upg_read_memory(void *buf, size_t size, const char *key,
105 char *sig, void *u, generic_printf_t printf) 152 const char *sig, void *u, generic_printf_t printf)
106{ 153{
107#define cprintf(col, ...) printf(u, false, col, __VA_ARGS__) 154#define cprintf(col, ...) printf(u, false, col, __VA_ARGS__)
108#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0) 155#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0)
@@ -114,6 +161,8 @@ struct upg_file_t *upg_read_memory(void *buf, size_t size, char key[NWZ_KEY_SIZE
114 cprintf(YELLOW, "%02x", md5->md5[i]); 161 cprintf(YELLOW, "%02x", md5->md5[i]);
115 cprintf(OFF, " "); 162 cprintf(OFF, " ");
116 163
164 int key_len = strlen(key);
165
117 /* check MD5 */ 166 /* check MD5 */
118 uint8_t actual_md5[NWZ_MD5_SIZE]; 167 uint8_t actual_md5[NWZ_MD5_SIZE];
119 MD5_CalculateDigest(actual_md5, (md5 + 1), size - sizeof(struct upg_header_t)); 168 MD5_CalculateDigest(actual_md5, (md5 + 1), size - sizeof(struct upg_header_t));
@@ -125,72 +174,186 @@ struct upg_file_t *upg_read_memory(void *buf, size_t size, char key[NWZ_KEY_SIZE
125 } 174 }
126 cprintf(RED, "Ok\n"); 175 cprintf(RED, "Ok\n");
127 176
128 struct upg_header_t *hdr = (void *)(md5 + 1); 177 bool is_v2 = false;
129 /* decrypt the whole file at once */ 178 void *hdr = (void *)(md5 + 1);
130 fwp_read(hdr, size - sizeof(*md5), hdr, (void *)key); 179 /* decrypt just the header */
180 if(key_len == 8)
181 {
182 des_ecb_dec_set_key((uint8_t *)key);
183 des_ecb_dec(hdr, sizeof(struct upg_header_t), hdr);
184 }
185 else if(key_len == 16)
186 {
187 aes_ecb_dec_set_key((uint8_t *)key);
188 aes_ecb_dec(hdr, sizeof(struct upg_header_v2_t), hdr);
189 is_v2 = true;
190 }
191 else
192 {
193 cprintf(GREY, "I don't know how to decrypt with a key of length %s\n", key_len);
194 return NULL;
195 }
131 196
132 cprintf(BLUE, "Header\n"); 197 cprintf(BLUE, "Header\n");
133 cprintf_field(" Signature:", " "); 198 int nr_files = 0;
134 for(int i = 0; i < NWZ_SIG_SIZE; i++) 199 void *content = NULL;
135 cprintf(YELLOW, "%c", isprint(hdr->sig[i]) ? hdr->sig[i] : '.'); 200 if(!is_v2)
136 if(sig)
137 { 201 {
138 if(memcmp(hdr->sig, sig, NWZ_SIG_SIZE) != 0) 202 struct upg_header_t *hdr_v1 = hdr;
203 cprintf_field(" Signature: ", "");
204 for(int i = 0; i < 8; i++)
205 cprintf_field("", "%c", isprint(hdr_v1->sig[i]) ? hdr_v1->sig[i] : '.');
206 if(sig)
139 { 207 {
140 cprintf(RED, "Mismatch\n"); 208 if(memcmp(hdr_v1->sig, sig, 8) != 0)
141 err_printf(GREY, "Signature Mismatch\n"); 209 {
142 return NULL; 210 cprintf(RED, " Mismatch\n");
211 err_printf(GREY, "Signature Mismatch\n");
212 return NULL;
213 }
214 cprintf(RED, " Ok\n");
143 } 215 }
144 cprintf(RED, " Ok\n"); 216 else
217 cprintf(RED, " Can't check\n");
218 cprintf_field(" Files: ", "%d\n", hdr_v1->nr_files);
219 if(hdr_v1->pad != 0)
220 cprintf_field(" Pad: ", "0x%x\n", hdr_v1->pad);
221
222 nr_files = hdr_v1->nr_files;
223 content = hdr_v1 + 1;
145 } 224 }
146 else 225 else
147 cprintf(RED, " Can't check\n");
148 cprintf_field(" Files: ", "%d\n", hdr->nr_files);
149 cprintf_field(" Pad: ", "0x%x\n", hdr->pad);
150
151
152 /* Do a first pass to decrypt in-place */
153 cprintf(BLUE, "Files\n");
154 struct upg_entry_t *entry = (void *)(hdr + 1);
155 for(unsigned i = 0; i < hdr->nr_files; i++, entry++)
156 { 226 {
157 cprintf(GREY, " File"); 227 struct upg_header_v2_t *hdr_v2 = hdr;
158 cprintf(RED, " %d\n", i); 228 cprintf_field(" Signature: ", "");
159 cprintf_field(" Offset: ", "0x%x\n", entry->offset); 229 for(int i = 0; i < 16; i++)
160 cprintf_field(" Size: ", "0x%x\n", entry->size); 230 cprintf_field("", "%c", isprint(hdr_v2->sig[i]) ? hdr_v2->sig[i] : '.');
231 if(sig)
232 {
233 if(memcmp(hdr_v2->sig, sig, 16) != 0)
234 {
235 cprintf(RED, " Mismatch\n");
236 err_printf(GREY, "Signature Mismatch\n");
237 return NULL;
238 }
239 cprintf(RED, " Ok\n");
240 }
241 else
242 cprintf(RED, " Can't check\n");
243 cprintf_field(" Files: ", "%d\n", hdr_v2->nr_files);
244 if(hdr_v2->pad[0] != 0 || hdr_v2->pad[1] != 0 || hdr_v2->pad[2] != 0)
245 cprintf_field(" Pad: ", "0x%x 0x%x 0x%x\n", hdr_v2->pad[0], hdr_v2->pad[1], hdr_v2->pad[2]);
246
247 nr_files = hdr_v2->nr_files;
248 content = hdr_v2 + 1;
161 } 249 }
162 /* Do a second pass to create the file structure */ 250
163 /* create file */ 251 /* create file */
164 struct upg_file_t *file = malloc(sizeof(struct upg_file_t)); 252 struct upg_file_t *file = malloc(sizeof(struct upg_file_t));
165 memset(file, 0, sizeof(struct upg_file_t)); 253 memset(file, 0, sizeof(struct upg_file_t));
166 file->nr_files = hdr->nr_files; 254 file->nr_files = nr_files;
167 file->files = malloc(sizeof(struct upg_file_entry_t) * file->nr_files); 255 file->files = malloc(sizeof(struct upg_file_entry_t) * file->nr_files);
168 256
169 entry = (void *)(hdr + 1); 257 /* decrypt the file list */
170 for(unsigned i = 0; i < hdr->nr_files; i++, entry++) 258 if(key_len == 8)
259 des_ecb_dec(content, sizeof(struct upg_entry_t) * nr_files, content);
260 else if(key_len == 16)
261 aes_ecb_dec(content, sizeof(struct upg_entry_v2_t) * nr_files, content);
262
263 /* Extract files */
264 cprintf(BLUE, "Files\n");
265 struct upg_entry_t *entry_v1 = content;
266 struct upg_entry_v2_t *entry_v2 = content;
267 for(unsigned i = 0; i < nr_files; i++)
171 { 268 {
269 uint32_t offset, size;
270 cprintf(GREY, " File");
271 cprintf(RED, " %d\n", i);
272 if(!is_v2)
273 {
274 offset = entry_v1[i].offset;
275 size = entry_v1[i].size;
276 }
277 else
278 {
279 offset = entry_v2[i].offset;
280 size = entry_v2[i].size;
281 }
282 cprintf_field(" Offset: ", "0x%x\n", offset);
283 cprintf_field(" Size: ", "0x%x\n", size);
284 if(is_v2 && (entry_v2[i].pad[0] != 0 || entry_v2[i].pad[1] != 0))
285 cprintf_field(" Pad:", " %x %x\n", entry_v2[i].pad[0], entry_v2[i].pad[1]);
286
287 /* decrypt file content, we round up the size to make sure it's a multiple of 8/16 */
288 if(key_len == 8)
289 des_ecb_dec(buf + offset, ROUND_UP(size, 8), buf + offset);
290 else if(key_len == 16)
291 {
292 aes_cbc_dec_set_key_iv((uint8_t *)key, (uint8_t *)g_aes_iv);
293 aes_cbc_dec(buf + offset, ROUND_UP(size, 16), buf + offset);
294 }
295
296 /* in V2 of the format, some entries can be compressed using zlib but there is no marker for
297 * that; instead the OF has the fwpup program that can extract the nth entry of the archive
298 * and takes an optional -z flag to specify whether to uncompress(). Hence we don't support
299 * that at the moment. */
172 memset(&file->files[i], 0, sizeof(struct upg_file_entry_t)); 300 memset(&file->files[i], 0, sizeof(struct upg_file_entry_t));
173 file->files[i].size = entry->size; 301 file->files[i].size = size;
174 file->files[i].data = malloc(file->files[i].size); 302 file->files[i].data = malloc(file->files[i].size);
175 memcpy(file->files[i].data, buf + entry->offset, entry->size); 303 memcpy(file->files[i].data, buf + offset, size);
176 } 304 }
177 305
178 return file; 306 return file;
179} 307}
180 308
181void *upg_write_memory(struct upg_file_t *file, char key[NWZ_KEY_SIZE], 309void *upg_write_memory(struct upg_file_t *file, const char *key,
182 char sig[NWZ_SIG_SIZE], size_t *out_size, void *u, generic_printf_t printf) 310 const char *sig, size_t *out_size, void *u, generic_printf_t printf)
183{ 311{
312 int key_len = strlen(key);
313 if(strlen(sig) != key_len)
314 {
315 err_printf(GREY, "The key must have the same length as the signature\n");
316 return NULL;
317 }
184 if(file->nr_files == 0) 318 if(file->nr_files == 0)
185 { 319 {
186 err_printf(GREY, "A UPG file must have at least one file\n"); 320 err_printf(GREY, "A UPG file must have at least one file\n");
187 return NULL; 321 return NULL;
188 } 322 }
323 if(key_len == 16 && file->nr_files == 1)
324 {
325 err_printf(RED, "This will probably not work: the firmware updater for this device expects at least two files in the archive.\n");
326 err_printf(RED, "The first one is a shell script and the second is a MD5 file. You can probably put whatever you want in this file,\n");
327 err_printf(RED, "even make it empty, but it needs to be there.\n");
328 /* let it run just in case */
329 }
330
331 bool is_v2 = false;
332 size_t min_chunk_size, hdr_sz, ent_sz;
333 if(key_len == 8)
334 {
335 min_chunk_size = 8;
336 hdr_sz = sizeof(struct upg_header_t);
337 ent_sz = sizeof(struct upg_entry_t);
338 }
339 else if(key_len == 16)
340 {
341 min_chunk_size = 16;
342 hdr_sz = sizeof(struct upg_header_v2_t);
343 ent_sz = sizeof(struct upg_entry_v2_t);
344 is_v2 = true;
345 }
346 else
347 {
348 cprintf(GREY, "I don't know how to decrypt with a key of length %s\n", key_len);
349 return NULL;
350 }
351
189 /* compute total size and create buffer */ 352 /* compute total size and create buffer */
190 size_t tot_size = sizeof(struct upg_md5_t) + sizeof(struct upg_header_t) 353 size_t tot_hdr_siz = hdr_sz + file->nr_files * ent_sz;
191 + file->nr_files * sizeof(struct upg_entry_t); 354 size_t tot_size = sizeof(struct upg_md5_t) + tot_hdr_siz;
192 for(int i = 0; i < file->nr_files; i++) 355 for(int i = 0; i < file->nr_files; i++)
193 tot_size += ROUND_UP(file->files[i].size, 8); 356 tot_size += ROUND_UP(file->files[i].size, min_chunk_size);
194 /* allocate buffer */ 357 /* allocate buffer */
195 void *buf = malloc(tot_size); 358 void *buf = malloc(tot_size);
196 359
@@ -198,40 +361,75 @@ void *upg_write_memory(struct upg_file_t *file, char key[NWZ_KEY_SIZE],
198 struct upg_md5_t *md5 = buf; 361 struct upg_md5_t *md5 = buf;
199 memset(md5, 0, sizeof(*md5)); 362 memset(md5, 0, sizeof(*md5));
200 /* create the encrypted signature and header */ 363 /* create the encrypted signature and header */
201 struct upg_header_t *hdr = (void *)(md5 + 1); 364 if(!is_v2)
202 memcpy(hdr->sig, sig, NWZ_SIG_SIZE); 365 {
203 hdr->nr_files = file->nr_files; 366 struct upg_header_t *hdr = (void *)(md5 + 1);
204 hdr->pad = 0; 367 memcpy(hdr->sig, sig, 8);
368 hdr->nr_files = file->nr_files;
369 hdr->pad = 0;
370 }
371 else
372 {
373 struct upg_header_v2_t *hdr = (void *)(md5 + 1);
374 memcpy(hdr->sig, sig, 16);
375 hdr->nr_files = file->nr_files;
376 hdr->pad[0] = hdr->pad[1] = hdr->pad[2] = 0;
377 }
205 378
206 /* create file headers */ 379 /* create file headers */
207 size_t offset = sizeof(*md5) + sizeof(*hdr) + file->nr_files * sizeof(struct upg_entry_t); 380 size_t offset = sizeof(struct upg_md5_t) + tot_hdr_siz;
208 struct upg_entry_t *entry = (void *)(hdr + 1); 381 struct upg_entry_t *entry_v1 = (void *)((uint8_t *)(md5 + 1) + hdr_sz);
382 struct upg_entry_v2_t *entry_v2 = (void *)entry_v1;
209 cprintf(BLUE, "Files\n"); 383 cprintf(BLUE, "Files\n");
210 for(int i = 0; i < file->nr_files; i++) 384 for(int i = 0; i < file->nr_files; i++)
211 { 385 {
212 entry[i].offset = offset;
213 entry[i].size = file->files[i].size;
214 offset += ROUND_UP(entry[i].size, 8); /* pad each file to a multiple of 8 for encryption */
215
216 cprintf(GREY, " File"); 386 cprintf(GREY, " File");
217 cprintf(RED, " %d\n", i); 387 cprintf(RED, " %d\n", i);
218 cprintf_field(" Offset: ", "0x%lx\n", entry[i].offset); 388 cprintf_field(" Offset: ", "0x%lx\n", offset);
219 cprintf_field(" Size: ", "0x%lx\n", entry[i].size); 389 cprintf_field(" Size: ", "0x%lx\n", file->files[i].size);
220 } 390 if(!is_v2)
221 391 {
222 /* add file data */ 392 entry_v1[i].offset = offset;
223 for(int i = 0; i < file->nr_files; i++) 393 entry_v1[i].size = file->files[i].size;
224 { 394 }
225 /* copy data to buffer, and then encrypt in-place */ 395 else
226 size_t r_size = ROUND_UP(file->files[i].size, 8); 396 {
227 void *data_ptr = (uint8_t *)buf + entry[i].offset; 397 entry_v2[i].offset = offset;
398 entry_v2[i].size = file->files[i].size;
399 entry_v2[i].pad[0] = entry_v2[i].pad[1] = 0;
400 }
401 /* copy data to buffer, with padding */
402 size_t r_size = ROUND_UP(file->files[i].size, min_chunk_size);
403 void *data_ptr = (uint8_t *)buf + offset;
228 memset(data_ptr, 0, r_size); /* the padding will be zero 0 */ 404 memset(data_ptr, 0, r_size); /* the padding will be zero 0 */
229 memcpy(data_ptr, file->files[i].data, file->files[i].size); 405 memcpy(data_ptr, file->files[i].data, file->files[i].size);
406 /* encrypt in-place */
407 if(!is_v2)
408 {
409 des_ecb_enc_set_key((uint8_t *)key);
410 des_ecb_enc(data_ptr, r_size, data_ptr);
411 }
412 else
413 {
414 aes_cbc_enc_set_key_iv((uint8_t *)key, (uint8_t *)g_aes_iv);
415 aes_cbc_enc(data_ptr, r_size, data_ptr);
416 }
417
418 offset += r_size;
419 }
420 /* encrypt headers */
421 if(!is_v2)
422 {
423 des_ecb_enc_set_key((uint8_t *)key);
424 des_ecb_enc(md5 + 1, tot_hdr_siz, md5 + 1);
425 }
426 else
427 {
428 aes_ecb_enc_set_key((uint8_t *)key);
429 aes_ecb_enc(md5 + 1, tot_hdr_siz, md5 + 1);
230 } 430 }
231 /* encrypt everything and hash everything */ 431 /* compute MD5 of the whole file */
232 fwp_write(hdr, tot_size - sizeof(*md5), hdr, (void *)key); 432 MD5_CalculateDigest(md5->md5, md5 + 1, tot_size - sizeof(*md5));
233 /* write final MD5 */
234 MD5_CalculateDigest(md5->md5, (void *)hdr, tot_size - sizeof(*md5));
235 *out_size = tot_size; 433 *out_size = tot_size;
236 return buf; 434 return buf;
237} 435}
diff --git a/utils/nwztools/upgtools/upg.h b/utils/nwztools/upgtools/upg.h
index bc7c9787c9..e6cdaba1f7 100644
--- a/utils/nwztools/upgtools/upg.h
+++ b/utils/nwztools/upgtools/upg.h
@@ -22,10 +22,9 @@
22#define __UPG_H__ 22#define __UPG_H__
23 23
24#include "misc.h" 24#include "misc.h"
25#include "fwp.h"
26#include "mg.h" 25#include "mg.h"
27 26
28/** Firmware format 27/** Firmware format V1/V2
29 * 28 *
30 * The firmware starts with the MD5 hash of the entire file (except the MD5 hash 29 * The firmware starts with the MD5 hash of the entire file (except the MD5 hash
31 * itself of course). This is used to check that the file was not corrupted. 30 * itself of course). This is used to check that the file was not corrupted.
@@ -35,7 +34,20 @@
35 * the key and finding the right signature serves to authenticate the firmware. 34 * the key and finding the right signature serves to authenticate the firmware.
36 * The header is followed by N entries (where N is the number of files) giving 35 * The header is followed by N entries (where N is the number of files) giving
37 * the offset, within the file, and size of each file. Note that the files in 36 * the offset, within the file, and size of each file. Note that the files in
38 * the firmware have no name. */ 37 * the firmware have no name. The only difference between V1 and V2 is that the
38 * size of the signature is 16 bytes instead of 8 and the upg entries are 16 bytes
39 * long so they are padded.
40 *
41 * There is, however a practical difference between how the OF performs the update on
42 * newer devices (and hence corrolates exactly with V2 usage). On these devices, the
43 * update script will first extract the first file (the bash script) and the second file
44 * which is called "md5.txt". At this point it then runs the script. Hence it is not
45 * important what the content of the second file is, it is not checked unless fwpup is
46 * called. For the records, here is an exerct of such a file:
47 * 838860800 eae2acabcd6523a750f61f5ea3e9a80b system.img
48 */
49
50#define NWZ_MD5_SIZE 16
39 51
40struct upg_md5_t 52struct upg_md5_t
41{ 53{
@@ -44,7 +56,7 @@ struct upg_md5_t
44 56
45struct upg_header_t 57struct upg_header_t
46{ 58{
47 uint8_t sig[NWZ_SIG_SIZE]; 59 uint8_t sig[8];
48 uint32_t nr_files; 60 uint32_t nr_files;
49 uint32_t pad; // make sure structure size is a multiple of 8 61 uint32_t pad; // make sure structure size is a multiple of 8
50} __attribute__((packed)); 62} __attribute__((packed));
@@ -55,6 +67,20 @@ struct upg_entry_t
55 uint32_t size; 67 uint32_t size;
56} __attribute__((packed)); 68} __attribute__((packed));
57 69
70struct upg_header_v2_t
71{
72 uint8_t sig[16];
73 uint32_t nr_files;
74 uint32_t pad[3]; // make sure structure size is a multiple of 16
75} __attribute__((packed));
76
77struct upg_entry_v2_t
78{
79 uint32_t offset;
80 uint32_t size;
81 uint32_t pad[2]; // make sure structure size is a multiple of 16
82} __attribute__((packed));
83
58/** KAS / Key / Signature 84/** KAS / Key / Signature
59 * 85 *
60 * Since this is all very confusing, we need some terminology and notations: 86 * Since this is all very confusing, we need some terminology and notations:
@@ -131,7 +157,7 @@ struct nwz_model_t
131 * it is a KAS built from a key and sig brute-forced from an upgrade. In this 157 * it is a KAS built from a key and sig brute-forced from an upgrade. In this
132 * case, the KAS might be different from the 'official' one although for all 158 * case, the KAS might be different from the 'official' one although for all
133 * intent and purposes it should not make any difference. */ 159 * intent and purposes it should not make any difference. */
134 char *kas; 160 const char *kas;
135}; 161};
136 162
137/* list of models with keys and status. Sentinel NULL entry at the end */ 163/* list of models with keys and status. Sentinel NULL entry at the end */
@@ -150,21 +176,21 @@ struct upg_file_t
150 struct upg_file_entry_t *files; 176 struct upg_file_entry_t *files;
151}; 177};
152 178
153/* decrypt a KAS into a key and signature, return <0 if the KAS contains a non-hex 179/* IMPORTANT: all functions assume that the kas/key/sig are string and are zero terminated */
154 * character */ 180
155int decrypt_keysig(const char kas[NWZ_KAS_SIZE], char key[NWZ_KEY_SIZE], 181/* Decrypt a KAS into a key and signature, return <0 if the KAS contains a non-hex
156 char sig[NWZ_SIG_SIZE]); 182 * character. The function will allocate key and sig if *key and/or *sig is NULL */
157/* encrypt a key and signature into a KAS */ 183int decrypt_keysig(const char *kas, char **key, char **sig);
158void encrypt_keysig(char kas[NWZ_KEY_SIZE], 184/* Encrypt a key and signature into a KAS, it will allocate kas if *kas is NULL */
159 const char key[NWZ_SIG_SIZE], const char sig[NWZ_KAS_SIZE]); 185void encrypt_keysig(char **kas, const char *key, const char *sig);
160 186
161/* Read a UPG file: return a structure on a success or NULL on error. 187/* Read a UPG file: return a structure on a success or NULL on error.
162 * Note that the memory buffer is modified to perform in-place decryption. */ 188 * Note that the memory buffer is modified to perform in-place decryption. */
163struct upg_file_t *upg_read_memory(void *file, size_t size, char key[NWZ_KEY_SIZE], 189struct upg_file_t *upg_read_memory(void *file, size_t size, const char *key,
164 char sig[NWZ_SIG_SIZE], void *u, generic_printf_t printf); 190 const char *sig, void *u, generic_printf_t printf);
165/* Write a UPG file: return a buffer containing the whole image, or NULL on error. */ 191/* Write a UPG file: return a buffer containing the whole image, or NULL on error. */
166void *upg_write_memory(struct upg_file_t *file, char key[NWZ_KEY_SIZE], 192void *upg_write_memory(struct upg_file_t *file, const char *key,
167 char sig[NWZ_SIG_SIZE], size_t *out_size, void *u, generic_printf_t printf); 193 const char *sig, size_t *out_size, void *u, generic_printf_t printf);
168/* create empty upg file */ 194/* create empty upg file */
169struct upg_file_t *upg_new(void); 195struct upg_file_t *upg_new(void);
170/* append a file to a upg, data is NOT copied */ 196/* append a file to a upg, data is NOT copied */
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c
index ff2a1f60f7..e0ccc15c48 100644
--- a/utils/nwztools/upgtools/upgtool.c
+++ b/utils/nwztools/upgtools/upgtool.c
@@ -18,6 +18,7 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#define _XOPEN_SOURCE 500 /* for strdup */
21#include <stdio.h> 22#include <stdio.h>
22#include <stdint.h> 23#include <stdint.h>
23#include <stdbool.h> 24#include <stdbool.h>
@@ -30,7 +31,6 @@
30#include "elf.h" 31#include "elf.h"
31#include <sys/stat.h> 32#include <sys/stat.h>
32#include "crypt.h" 33#include "crypt.h"
33#include "fwp.h"
34#include "keysig_search.h" 34#include "keysig_search.h"
35#include "upg.h" 35#include "upg.h"
36 36
@@ -71,50 +71,49 @@ static bool upg_notify_keysig(void *user, uint8_t key[NWZ_KEY_SIZE],
71 uint8_t sig[NWZ_SIG_SIZE]) 71 uint8_t sig[NWZ_SIG_SIZE])
72{ 72{
73 g_key = user; 73 g_key = user;
74 g_sig = user + NWZ_KEY_SIZE; 74 g_sig = user + 9;
75 memcpy(g_key, key, NWZ_KEY_SIZE); 75 memcpy(g_key, key, NWZ_KEY_SIZE);
76 g_key[8] = 0;
76 memcpy(g_sig, sig, NWZ_SIG_SIZE); 77 memcpy(g_sig, sig, NWZ_SIG_SIZE);
78 g_sig[8] = 0;
77 return true; 79 return true;
78} 80}
79 81
80static int get_key_and_sig(bool is_extract, void *buf) 82static int get_key_and_sig(bool is_extract, void *buf)
81{ 83{
82 static char keysig[NWZ_KEYSIG_SIZE];
83 static char kas[NWZ_KAS_SIZE];
84 /* database lookup */ 84 /* database lookup */
85 if(g_model_index != -1) 85 if(g_model_index != -1)
86 g_kas = g_model_list[g_model_index].kas; 86 g_kas = strdup(g_model_list[g_model_index].kas);
87 87
88 /* always prefer KAS because it contains everything */ 88 /* always prefer KAS because it contains everything */
89 if(g_kas) 89 if(g_kas)
90 { 90 {
91 if(strlen(g_kas) != NWZ_KAS_SIZE) 91 if(strlen(g_kas) != 32 && strlen(g_kas) != 64)
92 { 92 {
93 cprintf(GREY, "The KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); 93 cprintf(GREY, "The KAS has wrong length (must be 32 or 64 hex digits)\n");
94 return 4; 94 return 4;
95 } 95 }
96 g_key = keysig; 96 decrypt_keysig(g_kas, &g_key, &g_sig);
97 g_sig = keysig + NWZ_KEY_SIZE;
98 decrypt_keysig(g_kas, g_key, g_sig);
99 } 97 }
100 /* Otherwise require key and signature */ 98 /* Otherwise require key and signature */
101 else if(g_key && g_sig) 99 else if(g_key && g_sig)
102 { 100 {
103 /* check key and signature size */ 101 /* check key and signature size */
104 if(strlen(g_key) != 8) 102 if(strlen(g_key) != 8 && strlen(g_key) != 16)
105 { 103 {
106 cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); 104 cprintf(GREY, "The specified key has wrong length (must be 8 or 16 hex digits)\n");
107 return 4; 105 return 4;
108 } 106 }
109 if(strlen(g_sig) != 8) 107 if(strlen(g_sig) != strlen(g_key))
110 { 108 {
111 cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); 109 cprintf(GREY, "The specified sig has wrong length (must match key length)\n");
112 return 5; 110 return 5;
113 } 111 }
114 } 112 }
115 /* for extraction, we offer a brute force search method from the MD5 */ 113 /* for extraction, we offer a brute force search method from the MD5 */
116 else if(is_extract && g_keysig_search != KEYSIG_SEARCH_NONE) 114 else if(is_extract && g_keysig_search != KEYSIG_SEARCH_NONE)
117 { 115 {
116 static char keysig[18]; /* 8+NUL+8+NULL */
118 struct upg_md5_t *md5 = (void *)buf; 117 struct upg_md5_t *md5 = (void *)buf;
119 void *encrypted_hdr = (md5 + 1); 118 void *encrypted_hdr = (md5 + 1);
120 cprintf(BLUE, "keysig Search\n"); 119 cprintf(BLUE, "keysig Search\n");
@@ -145,14 +144,13 @@ static int get_key_and_sig(bool is_extract, void *buf)
145 { 144 {
146 /* This is useful to print the KAS for the user when brute-forcing since 145 /* This is useful to print the KAS for the user when brute-forcing since
147 * the process will produce a key+sig and the database requires a KAS */ 146 * the process will produce a key+sig and the database requires a KAS */
148 g_kas = kas; 147 encrypt_keysig(&g_kas, g_key, g_sig);
149 encrypt_keysig(g_kas, g_key, g_sig);
150 } 148 }
151 149
152 cprintf(BLUE, "Keys\n"); 150 cprintf(BLUE, "Keys\n");
153 cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); 151 cprintf_field(" KAS: ", "%s\n", g_kas);
154 cprintf_field(" Key: ", "%."STR(NWZ_KEY_SIZE)"s\n", g_key); 152 cprintf_field(" Key: ", "%s\n", g_key);
155 cprintf_field(" Sig: ", "%."STR(NWZ_SIG_SIZE)"s\n", g_sig); 153 cprintf_field(" Sig: ", "%s\n", g_sig);
156 154
157 return 0; 155 return 0;
158} 156}
@@ -268,7 +266,7 @@ static int create_upg(int argc, char **argv)
268 if(f == NULL) 266 if(f == NULL)
269 { 267 {
270 upg_free(upg); 268 upg_free(upg);
271 printf(GREY, "Cannot open input file '%s': %m\n", argv[i + 1]); 269 cprintf(GREY, "Cannot open input file '%s': %m\n", argv[i + 1]);
272 return 1; 270 return 1;
273 } 271 }
274 size_t size = filesize(f); 272 size_t size = filesize(f);