summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-08-30 17:19:30 +1000
committerAmaury Pouly <amaury.pouly@gmail.com>2016-08-30 17:21:05 +1000
commitcf82f208e3ece54fd38cb7c90b77ad91aa3a4c8c (patch)
tree5fe88d8fdaa9306a28b65a2dad042e0b6577816e
parentde8950d63da5ce199a94e3f094a7e13da3eeca6c (diff)
downloadrockbox-cf82f208e3ece54fd38cb7c90b77ad91aa3a4c8c.tar.gz
rockbox-cf82f208e3ece54fd38cb7c90b77ad91aa3a4c8c.zip
nwztools: cleanup the code
There was a lot of copy and paste, and the code was just crap. This commit tries to clarify the code and also document the encryption procedure. Hopefully I didn't break anything. Change-Id: I257793010e7cf94f2b090b30bb8608359d3886e3
-rw-r--r--utils/nwztools/upgtools/fwp.h3
-rw-r--r--utils/nwztools/upgtools/keysig_search.c108
-rw-r--r--utils/nwztools/upgtools/keysig_search.h4
-rw-r--r--utils/nwztools/upgtools/misc.c1
-rw-r--r--utils/nwztools/upgtools/misc.h2
-rw-r--r--utils/nwztools/upgtools/upgtool.c423
6 files changed, 267 insertions, 274 deletions
diff --git a/utils/nwztools/upgtools/fwp.h b/utils/nwztools/upgtools/fwp.h
index 7b527d47ba..0d928fbec1 100644
--- a/utils/nwztools/upgtools/fwp.h
+++ b/utils/nwztools/upgtools/fwp.h
@@ -28,8 +28,9 @@ extern "C" {
28#endif 28#endif
29 29
30#define NWZ_KAS_SIZE 32 30#define NWZ_KAS_SIZE 32
31#define NWZ_KEYSIG_SIZE 51 31#define NWZ_KEYSIG_SIZE 16
32#define NWZ_KEY_SIZE 8 32#define NWZ_KEY_SIZE 8
33#define NWZ_SIG_SIZE 8
33#define NWZ_EXPKEY_SIZE (NWZ_KEY_SIZE * NWZ_KEY_SIZE) 34#define NWZ_EXPKEY_SIZE (NWZ_KEY_SIZE * NWZ_KEY_SIZE)
34#define NWZ_DES_BLOCK 8 35#define NWZ_DES_BLOCK 8
35 36
diff --git a/utils/nwztools/upgtools/keysig_search.c b/utils/nwztools/upgtools/keysig_search.c
index 6054ea43ba..7652efa233 100644
--- a/utils/nwztools/upgtools/keysig_search.c
+++ b/utils/nwztools/upgtools/keysig_search.c
@@ -22,8 +22,24 @@
22#include "misc.h" 22#include "misc.h"
23#include "mg.h" 23#include "mg.h"
24#include <string.h> 24#include <string.h>
25#include <stdio.h>
25 26
26#define HEX_MAJ 27/* Key search methods
28 *
29 * This code tries to find the key and signature of a device using an upgrade
30 * file. It more or less relies on brute force and makes the following assumptions.
31 * It assumes the key and the signature are hexadecimal strings (it appears to be
32 * true thus far). The code lists all possible keys and decrypts the first
33 * 8 bytes of the file. If the decrypted signature happens to be an hex string,
34 * the code reports the key and signature as potentially valid. Note that some
35 * key/sig pairs may not be valid but since the likelyhood of decrypting a
36 * random 8-byte sequence using an hex string key and to produce an hex string
37 * is very small, there should be almost no false positive.
38 *
39 * Since the key is supposedly random, the code starts by looking at "balanced"
40 * keys: keys with slightly more digits (0-9) than letters (a-f) and then moving
41 * towards very unbalanced strings (only digits or only letters).
42 */
27 43
28static uint8_t g_cipher[8]; 44static uint8_t g_cipher[8];
29static keysig_notify_fn_t g_notify; 45static keysig_notify_fn_t g_notify;
@@ -31,11 +47,10 @@ static uint8_t g_key[8];
31static void *g_user; 47static void *g_user;
32static bool is_hex[256]; 48static bool is_hex[256];
33static bool is_init = false; 49static bool is_init = false;
34#ifdef HEX_MAJ 50static uint64_t g_tot_count;
35static char hex_digits[] = "02468ABEF"; 51static uint64_t g_cur_count;
36#else 52static int g_last_percent;
37static char hex_digits[] = "02468abef"; 53static int g_last_subpercent;
38#endif
39 54
40static void keysig_search_init() 55static void keysig_search_init()
41{ 56{
@@ -44,11 +59,7 @@ static void keysig_search_init()
44 memset(is_hex, 0, sizeof(is_hex)); 59 memset(is_hex, 0, sizeof(is_hex));
45 for(int i = '0'; i <= '9'; i++) 60 for(int i = '0'; i <= '9'; i++)
46 is_hex[i] = true; 61 is_hex[i] = true;
47#ifdef HEX_MAJ
48 for(int i = 'A'; i <= 'F'; i++)
49#else
50 for(int i = 'a'; i <= 'f'; i++) 62 for(int i = 'a'; i <= 'f'; i++)
51#endif
52 is_hex[i] = true; 63 is_hex[i] = true;
53} 64}
54 65
@@ -63,6 +74,24 @@ static inline bool is_full_ascii(uint8_t *arr)
63static inline bool check_stupid() 74static inline bool check_stupid()
64{ 75{
65 uint8_t res[8]; 76 uint8_t res[8];
77 // display progress
78 g_cur_count++;
79 int percent = (g_cur_count * 100ULL) / g_tot_count;
80 int subpercent = ((g_cur_count * 1000ULL) / g_tot_count) % 10;
81 if(percent != g_last_percent)
82 {
83 cprintf(RED, "%d%%", percent);
84 fflush(stdout);
85 g_last_subpercent = 0;
86 }
87 if(subpercent != g_last_subpercent)
88 {
89 cprintf(WHITE, ".");
90 fflush(stdout);
91 }
92 g_last_percent = percent;
93 g_last_subpercent = subpercent;
94
66 mg_decrypt_fw(g_cipher, 8, res, g_key); 95 mg_decrypt_fw(g_cipher, 8, res, g_key);
67 if(is_full_ascii(res)) 96 if(is_full_ascii(res))
68 return g_notify(g_user, g_key, res); 97 return g_notify(g_user, g_key, res);
@@ -75,7 +104,7 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
75 return check_stupid(); 104 return check_stupid();
76 if(rem_digit > 0) 105 if(rem_digit > 0)
77 { 106 {
78 for(int i = '0'; i <= '9'; i += 2) 107 for(int i = '0'; i <= '9'; i++)
79 { 108 {
80 g_key[pos] = i; 109 g_key[pos] = i;
81 if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1)) 110 if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1))
@@ -84,11 +113,7 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
84 } 113 }
85 if(rem_letter > 0) 114 if(rem_letter > 0)
86 { 115 {
87#ifdef HEX_MAJ 116 for(int i = 'a' - 1; i <= 'f'; i++)
88 for(int i = 'a' - 1; i <= 'f'; i += 2)
89#else
90 for(int i = 'A' - 1; i <= 'F'; i += 2)
91#endif
92 { 117 {
93 g_key[pos] = i; 118 g_key[pos] = i;
94 if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1)) 119 if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1))
@@ -100,6 +125,12 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
100 125
101static bool search_stupid(int rem_digit, int rem_letter) 126static bool search_stupid(int rem_digit, int rem_letter)
102{ 127{
128 cprintf(WHITE, "\n Looking for keys with ");
129 cprintf(RED, "%d", rem_digit);
130 cprintf(WHITE, " digits and ");
131 cprintf(RED, "%d", rem_letter);
132 cprintf(WHITE, " letters...");
133 fflush(stdout);
103 return search_stupid_rec(rem_digit, rem_letter, 0); 134 return search_stupid_rec(rem_digit, rem_letter, 0);
104} 135}
105 136
@@ -109,28 +140,35 @@ bool keysig_search_ascii_stupid(uint8_t *cipher, keysig_notify_fn_t notify, void
109 memcpy(g_cipher, cipher, 8); 140 memcpy(g_cipher, cipher, 8);
110 g_notify = notify; 141 g_notify = notify;
111 g_user = user; 142 g_user = user;
112#if 1 143 // compute number of possibilities
113 return search_stupid(4, 4) || 144 g_cur_count = 0;
114 search_stupid(3, 5) || search_stupid(5, 3) || 145 g_tot_count = 1;
115 search_stupid(2, 6) || search_stupid(6, 2) || 146 g_last_percent = -1;
116 search_stupid(1, 7) || search_stupid(7, 1) || 147 for(int i = 0; i < 8; i++)
117 search_stupid(0, 8) || search_stupid(8, 0); 148 g_tot_count *= 16ULL;
118#else 149 cprintf(WHITE, " Search space:");
119#define do(i) for(int a##i = 0; a##i < sizeof(hex_digits); a##i++) { g_key[i] = hex_digits[a##i]; 150 cprintf(RED, " %llu", (unsigned long long)g_tot_count);
120#define od() } 151 // sorted by probability:
121 152 bool ret = search_stupid(5, 3) // 5 digits, 3 letters: 0.281632
122 do(0)do(1)do(2)do(3)do(4)do(5)do(6)do(7) 153 || search_stupid(6, 2) // 6 digits, 2 letters: 0.234693
123 if(check_stupid()) return true; 154 || search_stupid(4, 4) // 4 digits, 4 letters: 0.211224
124 od()od()od()od()od()od()od()od() 155 || search_stupid(7, 1) // 7 digits, 1 letters: 0.111759
125#undef do 156 || search_stupid(3, 5) // 3 digits, 5 letters: 0.101388
126#undef od 157 || search_stupid(2, 6) // 2 digits, 6 letters: 0.030416
127 return false; 158 || search_stupid(8, 0) // 8 digits, 0 letters: 0.023283
128#endif 159 || search_stupid(1, 7) // 1 digits, 7 letters: 0.005214
160 || search_stupid(0, 8);// 0 digits, 8 letters: 0.000391
161 cprintf(OFF, "\n");
162 return ret;
129} 163}
130 164
131bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user) 165bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user)
132{ 166{
167 (void) cipher;
168 (void) notify;
169 (void) user;
133 keysig_search_init(); 170 keysig_search_init();
171 cprintf(RED, "Unimplemented\n");
134 return false; 172 return false;
135} 173}
136 174
@@ -144,9 +182,9 @@ struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST] =
144 }, 182 },
145 [KEYSIG_SEARCH_ASCII_STUPID] = 183 [KEYSIG_SEARCH_ASCII_STUPID] =
146 { 184 {
147 .name = "ascii-stupid", 185 .name = "ascii-hex",
148 .fn = keysig_search_ascii_stupid, 186 .fn = keysig_search_ascii_stupid,
149 .comment = "Try to find a balance ascii key ignoring lsb" 187 .comment = "Try to find an hexadecimal ascii string keysig"
150 }, 188 },
151 [KEYSIG_SEARCH_ASCII_BRUTE] = 189 [KEYSIG_SEARCH_ASCII_BRUTE] =
152 { 190 {
diff --git a/utils/nwztools/upgtools/keysig_search.h b/utils/nwztools/upgtools/keysig_search.h
index 46639dfb47..9009a73284 100644
--- a/utils/nwztools/upgtools/keysig_search.h
+++ b/utils/nwztools/upgtools/keysig_search.h
@@ -23,6 +23,7 @@
23 23
24#include <stdbool.h> 24#include <stdbool.h>
25#include <stdint.h> 25#include <stdint.h>
26#include "fwp.h"
26 27
27enum keysig_search_method_t 28enum keysig_search_method_t
28{ 29{
@@ -34,7 +35,8 @@ enum keysig_search_method_t
34}; 35};
35 36
36/* notify returns true if the key seems ok */ 37/* notify returns true if the key seems ok */
37typedef bool (*keysig_notify_fn_t)(void *user, uint8_t key[8], uint8_t sig[8]); 38typedef bool (*keysig_notify_fn_t)(void *user, uint8_t key[NWZ_KEY_SIZE],
39 uint8_t sig[NWZ_SIG_SIZE]);
38/* returns true if a key was accepted by notify */ 40/* returns true if a key was accepted by notify */
39typedef bool (*keysig_search_fn_t)(uint8_t *cipher, keysig_notify_fn_t notify, void *user); 41typedef bool (*keysig_search_fn_t)(uint8_t *cipher, keysig_notify_fn_t notify, void *user);
40 42
diff --git a/utils/nwztools/upgtools/misc.c b/utils/nwztools/upgtools/misc.c
index 108235e7fd..00832cd585 100644
--- a/utils/nwztools/upgtools/misc.c
+++ b/utils/nwztools/upgtools/misc.c
@@ -31,6 +31,7 @@ char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
31char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; 31char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
32char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; 32char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
33char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; 33char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
34char WHITE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '7', 0x6d, '\0' };
34 35
35static bool g_color_enable = true; 36static bool g_color_enable = true;
36 37
diff --git a/utils/nwztools/upgtools/misc.h b/utils/nwztools/upgtools/misc.h
index 96666a2eff..4e8294f1ee 100644
--- a/utils/nwztools/upgtools/misc.h
+++ b/utils/nwztools/upgtools/misc.h
@@ -34,7 +34,7 @@
34 34
35typedef char color_t[]; 35typedef char color_t[];
36 36
37extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; 37extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE, WHITE;
38void *xmalloc(size_t s); 38void *xmalloc(size_t s);
39void color(color_t c); 39void color(color_t c);
40void enable_color(bool enable); 40void enable_color(bool enable);
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c
index fc5cf0fb92..065cede63c 100644
--- a/utils/nwztools/upgtools/upgtool.c
+++ b/utils/nwztools/upgtools/upgtool.c
@@ -69,9 +69,9 @@ struct nwz_model_t
69{ 69{
70 const char *model; 70 const char *model;
71 unsigned flags; 71 unsigned flags;
72 char kas[NWZ_KAS_SIZE]; /* key and signature */ 72 char *kas;
73 char key[8]; 73 char *key;
74 char sig[8]; 74 char *sig;
75}; 75};
76 76
77struct upg_md5_t 77struct upg_md5_t
@@ -81,7 +81,7 @@ struct upg_md5_t
81 81
82struct upg_header_t 82struct upg_header_t
83{ 83{
84 char sig[8]; 84 char sig[NWZ_SIG_SIZE];
85 uint32_t nr_files; 85 uint32_t nr_files;
86 uint32_t pad; // make sure structure size is a multiple of 8 86 uint32_t pad; // make sure structure size is a multiple of 8
87} __attribute__((packed)); 87} __attribute__((packed));
@@ -92,6 +92,72 @@ struct upg_entry_t
92 uint32_t size; 92 uint32_t size;
93} __attribute__((packed)); 93} __attribute__((packed));
94 94
95/** KAS / Key / Signature
96 *
97 * Since this is all very confusing, we need some terminology and notations:
98 * - [X, Y, Z] is a sequence of bytes, for example:
99 * [8, 0x89, 42]
100 * is a sequence of three bytes.
101 * - "abcdef" is a string: it is a sequences of bytes where each byte happens to
102 * be the ASCII encoding of a letter. So for example:
103 * "abc" = [97, 98, 99]
104 * because 'a' has ASCII encoding 97 and so one
105 * - HexString(Seq) refers to the string where each byte of the original sequence
106 * is represented in hexadecimal by two ASCII characters. For example:
107 * HexString([8, 0x89, 42]) = "08892a"
108 * because 8 = 0x08 so it represented by "08" and 42 = 0x2a. Note that the length
109 * of HexString(Seq) is always exactly twice the length of Seq.
110 * - DES(Seq,Pass) is the result of encrypting Seq with Pass using the DES cipher.
111 * Seq must be a sequence of 8 bytes (known as a block) and Pass must be a
112 * sequence of 8 bytes. The result is also a 8-byte sequence.
113 * - ECB_DES([Block0, Block1, ..., BlockN], Pass)
114 * = [DES(Block0,Pass), DES(Block1,Pass), ..., DES(BlockN,Pass)]
115 * where Blocki is a block (8 byte).
116 *
117 *
118 * A firmware upgrade file is always encrypted using a Key. To authenticate it,
119 * the upgrade file (before encryption) contains a Sig(nature). The pair (Key,Sig)
120 * is refered to as KeySig and is specific to each series. For example all
121 * NWZ-E46x use the same KeySig but the NWZ-E46x and NWZ-A86x use different KeySig.
122 * In the details, a Key is a sequence of 8 bytes and a Sig is also a sequence
123 * of 8 bytes. A KeySig is a simply the concatenation of the Key followed by
124 * the Sig, so it is a sequence of 16 bytes. Probably in an attempt to obfuscate
125 * things a little further, Sony never provides the KeySig directly but instead
126 * encrypts it using DES in ECB mode using a hardcoded password and provides
127 * the hexadecimal string of the result, known as the KAS, which is thus a string
128 * of 32 ASCII characters.
129 * Note that since DES works on blocks of 8 bytes and ECB encrypts blocks
130 * independently, it is the same to encrypt the KeySig as once or encrypt the Key
131 * and Sig separately.
132 *
133 * To summarize:
134 * Key = [K0, K1, K2, ..., K7] (8 bytes) (model specific)
135 * Sig = [S0, S1, S2, ..., S7] (8 bytes) (model specific)
136 * KeySig = [Key, Sig] = [K0, ... K7, S0, ..., S7] (16 bytes)
137 * FwpPass = "ed295076" (8 bytes) (never changes)
138 * EncKeySig = ECB_DES(KeySig, FwpPass) = [DES(Key, FwpPass), DES(Sig, FwpPass)]
139 * KAS = HexString(EncKeySig) (32 characters)
140 *
141 * In theory, the Key and Sig can be any 8-byte sequence. In practice, they always
142 * are strings, probably to make it easier to write them down. In many cases, the
143 * Key and Sig are even the hexadecimal string of 4-byte sequences but it is
144 * unclear if this is the result of pure luck, confused engineers, lazyness on
145 * Sony's part or by design. The following code assumes that Key and Sig are
146 * strings (though it could easily be fixed to work with anything if this is
147 * really needed).
148 *
149 *
150 * Here is a real example, from the NWZ-E46x Series:
151 * Key = "6173819e" (note that this is a string and even a hex string in this case)
152 * Sig = "30b82e5c"
153 * KeySig = [Key, Sig] = "6173819e30b82e5c"
154 * FwpPass = "ed295076" (never changes)
155 * EncKeySig = ECB_DES(KeySig, FwpPass)
156 * = [0x8a, 0x01, 0xb6, ..., 0xc5] (16 bytes)
157 * KAS = HexString(EncKeySig) = "8a01b624bfbfde4a1662a1772220e3c5"
158 *
159 */
160
95struct nwz_model_t g_model_list[] = 161struct nwz_model_t g_model_list[] =
96{ 162{
97 { "nwz-e45x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "8a01b624bfbfde4a1662a1772220e3c5", "6173819e", "30b82e5c"}, 163 { "nwz-e45x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "8a01b624bfbfde4a1662a1772220e3c5", "6173819e", "30b82e5c"},
@@ -99,7 +165,7 @@ struct nwz_model_t g_model_list[] =
99 { "nwz-a86x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "a7c4af6c28b8900a783f307c1ba538c5", "c824e4e2", "7c262bb0" }, 165 { "nwz-a86x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "a7c4af6c28b8900a783f307c1ba538c5", "c824e4e2", "7c262bb0" },
100 /* The following keys were obtained by brute forcing firmware upgrades, 166 /* The following keys were obtained by brute forcing firmware upgrades,
101 * someone with a device needs to confirm that they work */ 167 * someone with a device needs to confirm that they work */
102 { "nw-a82x", HAS_KEY | HAS_SIG, {""}, "4df06482", "07fa0b6e" }, 168 { "nw-a82x", HAS_KEY | HAS_SIG, "", "4df06482", "07fa0b6e" },
103}; 169};
104 170
105static int digit_value(char c) 171static int digit_value(char c)
@@ -115,15 +181,14 @@ static char hex_digit(unsigned v)
115 return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x'; 181 return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x';
116} 182}
117 183
118static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE]) 184static int decrypt_keysig(const char kas[NWZ_KAS_SIZE], char key[NWZ_KEY_SIZE],
185 char sig[NWZ_SIG_SIZE])
119{ 186{
120 uint8_t src[16]; 187 uint8_t src[NWZ_KAS_SIZE / 2];
121 for(int i = 32; i < NWZ_KEYSIG_SIZE; i++) 188 for(int index = 0; index < NWZ_KAS_SIZE / 2; index++)
122 keysig[i] = 0;
123 for(int index = 0; index < 16; index++)
124 { 189 {
125 int a = digit_value(keysig[index * 2]); 190 int a = digit_value(kas[index * 2]);
126 int b = digit_value(keysig[index * 2 + 1]); 191 int b = digit_value(kas[index * 2 + 1]);
127 if(a < 0 || b < 0) 192 if(a < 0 || b < 0)
128 { 193 {
129 cprintf(GREY, "Invalid KAS !\n"); 194 cprintf(GREY, "Invalid KAS !\n");
@@ -133,166 +198,161 @@ static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE])
133 } 198 }
134 fwp_setkey("ed295076"); 199 fwp_setkey("ed295076");
135 fwp_crypt(src, sizeof(src), 1); 200 fwp_crypt(src, sizeof(src), 1);
136 memcpy(keysig + 33, src, 8); 201 memcpy(key, src, NWZ_KEY_SIZE);
137 memcpy(keysig + 42, src + 8, 8); 202 memcpy(sig, src + NWZ_KEY_SIZE, NWZ_SIG_SIZE);
138 return 0; 203 return 0;
139} 204}
140 205
141static bool upg_notify_keysig(void *user, uint8_t key[8], uint8_t sig[8]) 206static void encrypt_keysig(char kas[NWZ_KEY_SIZE],
207 const char key[NWZ_SIG_SIZE], const char sig[NWZ_KAS_SIZE])
142{ 208{
143 memcpy(user + 33, key, 8); 209 uint8_t src[NWZ_KAS_SIZE / 2];
144 memcpy(user + 42, sig, 8); 210 fwp_setkey("ed295076");
145 return true; 211 memcpy(src, key, NWZ_KEY_SIZE);
212 memcpy(src + NWZ_KEY_SIZE, sig, NWZ_SIG_SIZE);
213 fwp_crypt(src, sizeof(src), 0);
214 for(int i = 0; i < NWZ_KAS_SIZE / 2; i++)
215 {
216 kas[2 * i] = hex_digit((src[i] >> 4) & 0xf);
217 kas[2 * i + 1] = hex_digit(src[i] & 0xf);
218 }
146} 219}
147 220
148static int do_upg(void *buf, long size) 221/* user needs to be pointer to a NWZ_KEYSIG_SIZE-byte buffer, on success g_key
222 * and g_sig are updated to point to the key and sig in the buffer */
223static bool upg_notify_keysig(void *user, uint8_t key[NWZ_KEY_SIZE],
224 uint8_t sig[NWZ_SIG_SIZE])
149{ 225{
150 struct upg_md5_t *md5 = buf; 226 g_key = user;
151 cprintf(BLUE, "Preliminary\n"); 227 g_sig = user + NWZ_KEY_SIZE;
152 cprintf(GREEN, " MD5: "); 228 memcpy(g_key, key, NWZ_KEY_SIZE);
153 for(int i = 0; i < 16; i++) 229 memcpy(g_sig, sig, NWZ_SIG_SIZE);
154 cprintf(YELLOW, "%02x", md5->md5[i]); 230 return true;
155 printf(" "); 231}
156
157 uint8_t actual_md5[MD5_DIGEST_LENGTH];
158 {
159 MD5_CTX c;
160 MD5_Init(&c);
161 MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t));
162 MD5_Final(actual_md5, &c);
163 }
164 check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n");
165 232
166 if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL) 233static int get_key_and_sig(bool is_extract, void *encrypted_hdr)
234{
235 static char keysig[NWZ_KEYSIG_SIZE];
236 static char kas[NWZ_KAS_SIZE];
237 /* database lookup */
238 if(g_model_index != -1)
167 { 239 {
168 cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); 240 if(g_model_list[g_model_index].flags & HAS_KAS)
169 cprintf(GREY, "You have the following options(see help for more details):\n"); 241 g_kas = g_model_list[g_model_index].kas;
170 cprintf(GREY, "- select a model with a known KAS\n"); 242 if(g_model_list[g_model_index].flags & HAS_KEY)
171 cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n"); 243 g_key = g_model_list[g_model_index].key;
172 cprintf(GREY, "- let me try to find the keysig(slow !)\n"); 244 if(g_model_list[g_model_index].flags & HAS_SIG)
173 return 1; 245 g_sig = g_model_list[g_model_index].sig;
174 } 246 }
175 247
176 char kas[NWZ_KAS_SIZE]; 248 /* always prefer KAS because it contains everything */
177 char keysig[NWZ_KEYSIG_SIZE];
178
179 memset(kas, '?', NWZ_KAS_SIZE);
180 memset(keysig, '?', NWZ_KEYSIG_SIZE);
181 keysig[32] = keysig[41] = keysig[50] = 0;
182
183 if(g_kas) 249 if(g_kas)
184 { 250 {
185 if(strlen(g_kas) != NWZ_KAS_SIZE) 251 if(strlen(g_kas) != NWZ_KAS_SIZE)
186 { 252 {
187 cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); 253 cprintf(GREY, "The KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE);
188 return 4; 254 return 4;
189 } 255 }
190 memcpy(keysig, g_kas, NWZ_KAS_SIZE); 256 g_key = keysig;
191 decrypt_keysig(keysig); 257 g_sig = keysig + NWZ_KEY_SIZE;
192 g_kas = keysig; 258 decrypt_keysig(g_kas, g_key, g_sig);
193 g_key = keysig + 33;
194 g_sig = keysig + 42;
195 } 259 }
196 else if(g_key) 260 /* fall back to key and signature otherwise. The signature is not required
261 * when extracting but prevents from checking decryption */
262 else if(g_key && (is_extract || g_sig))
197 { 263 {
198 if(strlen(g_key) != 8) 264 if(strlen(g_key) != 8)
199 { 265 {
200 cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); 266 cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n");
201 return 4; 267 return 4;
202 } 268 }
203 if(g_sig && strlen(g_sig) != 8) 269
270 /* if there is a signature, it must have the correct size */
271 if(g_sig)
204 { 272 {
205 cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); 273 if(strlen(g_sig) != 8)
206 return 5; 274 {
275 cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n");
276 return 5;
277 }
207 } 278 }
208
209 memcpy(keysig + 33, g_key, 8);
210 if(!g_sig)
211 cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n");
212 else 279 else
213 memcpy(keysig + 42, g_sig, 8); 280 {
214 g_key = keysig + 33; 281 cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n");
215 if(g_sig) 282 }
216 g_sig = keysig + 42;
217 } 283 }
218 else if(g_model_index == -1) 284 /* for extraction, we offer a brute force search method from the MD5 */
285 else if(is_extract && g_keysig_search != KEYSIG_SEARCH_NONE)
219 { 286 {
220 cprintf(BLUE, "keysig Search\n"); 287 cprintf(BLUE, "keysig Search\n");
221 cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name); 288 cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name);
222 bool ok = keysig_search_desc[g_keysig_search].fn((void *)(md5 + 1), &upg_notify_keysig, keysig); 289 bool ok = keysig_search_desc[g_keysig_search].fn(encrypted_hdr, &upg_notify_keysig, keysig);
223 cprintf(GREEN, " Result: "); 290 cprintf(GREEN, " Result: ");
224 cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found"); 291 cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found");
225 if(!ok) 292 if(!ok)
226 return 2; 293 return 2;
227 g_key = keysig + 33;
228 g_sig = keysig + 42;
229 } 294 }
230 else 295 else
231 { 296 {
232 if(g_model_list[g_model_index].flags & HAS_KAS) 297 cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n");
233 g_kas = g_model_list[g_model_index].kas; 298 cprintf(GREY, "You have the following options(see help for more details):\n");
234 if(g_model_list[g_model_index].flags & HAS_KEY) 299 cprintf(GREY, "- select a model with a known KAS\n");
235 g_key = g_model_list[g_model_index].key; 300 cprintf(GREY, "- specify an explicit KAS or key+sig\n");
236 if(g_model_list[g_model_index].flags & HAS_SIG) 301 if(is_extract)
237 g_sig = g_model_list[g_model_index].sig; 302 cprintf(GREY, "- let me try to find the keysig(slow !)\n");
238 303 return 1;
239 if(g_kas)
240 {
241 memcpy(keysig, g_kas, NWZ_KAS_SIZE);
242 decrypt_keysig(keysig);
243 g_kas = keysig;
244 g_key = keysig + 33;
245 g_sig = keysig + 42;
246 }
247 else
248 {
249 if(g_key)
250 {
251 memcpy(keysig + 33, g_key, 8);
252 g_key = keysig + 33;
253 }
254 if(g_sig)
255 {
256 memcpy(keysig + 42, g_sig, 8);
257 g_sig = keysig + 42;
258 }
259 }
260 } 304 }
261 305
306 /* If we only have the key and signature, we can create a "fake" KAS
307 * that decrypts to the same key and signature. Since it is not unique,
308 * it will generally not match the "official" one from Sony but will produce
309 * valid files anyway */
262 if(!g_kas) 310 if(!g_kas)
263 { 311 {
264 g_kas = keysig; 312 if(!g_sig)
265 fwp_setkey("ed295076");
266 if(g_key)
267 {
268 memcpy(kas, g_key, 8);
269 fwp_crypt(kas, 8, 0);
270 for(int i = 0; i < 8; i++)
271 {
272 g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf);
273 g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf);
274 }
275 }
276 if(g_sig)
277 { 313 {
278 memcpy(kas + 8, g_sig, 8); 314 /* if we extract and don't have a signature, just use a random
279 fwp_crypt(kas + 8, 8, 0); 315 * one, we cannot check it anyway */
280 for(int i = 8; i < 16; i++) 316 g_sig = keysig;
281 { 317 memset(g_sig, '?', NWZ_SIG_SIZE);
282 g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf);
283 g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf);
284 }
285 } 318 }
319 g_kas = kas;
320 encrypt_keysig(g_kas, g_key, g_sig);
286 } 321 }
287 322
288 cprintf(BLUE, "Keys\n"); 323 cprintf(BLUE, "Keys\n");
289 cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); 324 cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas);
290 cprintf_field(" Key: ", "%s\n", g_key); 325 cprintf_field(" Key: ", "%."STR(NWZ_KEY_SIZE)"s\n", g_key);
291 if(g_sig) 326 if(g_sig)
292 cprintf_field(" Sig: ", "%s\n", g_sig); 327 cprintf_field(" Sig: ", "%."STR(NWZ_SIG_SIZE)"s\n", g_sig);
328
329 return 0;
330}
331
332static int do_upg(void *buf, long size)
333{
334 struct upg_md5_t *md5 = buf;
335 cprintf(BLUE, "Preliminary\n");
336 cprintf(GREEN, " MD5: ");
337 for(int i = 0; i < 16; i++)
338 cprintf(YELLOW, "%02x", md5->md5[i]);
339 printf(" ");
340
341 uint8_t actual_md5[MD5_DIGEST_LENGTH];
342 {
343 MD5_CTX c;
344 MD5_Init(&c);
345 MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t));
346 MD5_Final(actual_md5, &c);
347 }
348 check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n");
349
350 int ret = get_key_and_sig(true, md5 + 1);
351 if(ret != 0)
352 return ret;
293 353
294 struct upg_header_t *hdr = (void *)(md5 + 1); 354 struct upg_header_t *hdr = (void *)(md5 + 1);
295 int ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key); 355 ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key);
296 if(ret) 356 if(ret)
297 return ret; 357 return ret;
298 358
@@ -336,7 +396,6 @@ static int do_upg(void *buf, long size)
336 return ret; 396 return ret;
337 // but write the *good* amount of data 397 // but write the *good* amount of data
338 fwrite(buf + entry->offset, 1, entry->size, f); 398 fwrite(buf + entry->offset, 1, entry->size, f);
339
340 fclose(f); 399 fclose(f);
341 } 400 }
342 else 401 else
@@ -414,118 +473,10 @@ static int create_upg(int argc, char **argv)
414 printf("You must specify a firmware filename\n"); 473 printf("You must specify a firmware filename\n");
415 usage(); 474 usage();
416 } 475 }
417
418 if(g_model_index == -1 && (g_key == NULL || g_sig == NULL) && g_kas == NULL)
419 {
420 cprintf(GREY, "A KAS or a keysig is needed to encrypt the firmware\n");
421 cprintf(GREY, "You have the following options(see help for more details):\n");
422 cprintf(GREY, "- select a model with a known KAS\n");
423 cprintf(GREY, "- specify an explicit KAS or key+sig\n");
424 return 1;
425 }
426
427 char kas[NWZ_KAS_SIZE];
428 char keysig[NWZ_KEYSIG_SIZE];
429 476
430 memset(kas, '?', NWZ_KAS_SIZE); 477 int ret = get_key_and_sig(false, NULL);
431 memset(keysig, '?', NWZ_KEYSIG_SIZE); 478 if(ret != 0)
432 keysig[32] = keysig[41] = keysig[50] = 0; 479 return ret;
433
434 if(g_kas)
435 {
436 if(strlen(g_kas) != NWZ_KAS_SIZE)
437 {
438 cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE);
439 return 4;
440 }
441 memcpy(keysig, g_kas, NWZ_KAS_SIZE);
442 decrypt_keysig(keysig);
443 g_kas = keysig;
444 g_key = keysig + 33;
445 g_sig = keysig + 42;
446 }
447 else if(g_key)
448 {
449 if(strlen(g_key) != 8)
450 {
451 cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n");
452 return 4;
453 }
454 if(strlen(g_sig) != 8)
455 {
456 cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n");
457 return 5;
458 }
459
460 memcpy(keysig + 33, g_key, 8);
461 if(!g_sig)
462 cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n");
463 else
464 memcpy(keysig + 42, g_sig, 8);
465 g_key = keysig + 33;
466 g_sig = keysig + 42;
467 }
468 else if(g_model_index != -1)
469 {
470 if(g_model_list[g_model_index].flags & HAS_KAS)
471 g_kas = g_model_list[g_model_index].kas;
472 if(g_model_list[g_model_index].flags & HAS_KEY)
473 g_key = g_model_list[g_model_index].key;
474 if(g_model_list[g_model_index].flags & HAS_SIG)
475 g_sig = g_model_list[g_model_index].sig;
476
477 if(g_key && g_sig)
478 {
479 memcpy(keysig + 33, g_key, 8);
480 g_key = keysig + 33;
481 memcpy(keysig + 42, g_sig, 8);
482 g_sig = keysig + 42;
483 }
484 else if(g_kas)
485 {
486 memcpy(keysig, g_kas, NWZ_KAS_SIZE);
487 decrypt_keysig(keysig);
488 g_kas = keysig;
489 g_key = keysig + 33;
490 g_sig = keysig + 42;
491 }
492 else
493 {
494 printf("Target doesn't have enough information to get key and sig\n");
495 return 1;
496 }
497 }
498 else
499 {
500 printf("Kill me\n");
501 return 1;
502 }
503
504 if(!g_kas)
505 {
506 g_kas = keysig;
507 fwp_setkey("ed295076");
508 memcpy(kas, g_key, 8);
509 fwp_crypt(kas, 8, 0);
510 for(int i = 0; i < 8; i++)
511 {
512 g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf);
513 g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf);
514 }
515 memcpy(kas + 8, g_sig, 8);
516 fwp_crypt(kas + 8, 8, 0);
517 for(int i = 8; i < 16; i++)
518 {
519 g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf);
520 g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf);
521 }
522 }
523
524 cprintf(BLUE, "Keys\n");
525 cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas);
526 cprintf_field(" Key: ", "%s\n", g_key);
527 if(g_sig)
528 cprintf_field(" Sig: ", "%s\n", g_sig);
529 480
530 FILE *fout = fopen(argv[0], "wb"); 481 FILE *fout = fopen(argv[0], "wb");
531 if(fout == NULL) 482 if(fout == NULL)
@@ -558,8 +509,8 @@ static int create_upg(int argc, char **argv)
558 memcpy(hdr.sig, g_sig, 8); 509 memcpy(hdr.sig, g_sig, 8);
559 hdr.nr_files = nr_files; 510 hdr.nr_files = nr_files;
560 hdr.pad = 0; 511 hdr.pad = 0;
561 512
562 int ret = fwp_write(&hdr, sizeof(hdr), &hdr, (void *)g_key); 513 ret = fwp_write(&hdr, sizeof(hdr), &hdr, (void *)g_key);
563 if(ret) 514 if(ret)
564 return ret; 515 return ret;
565 MD5_Update(&c, &hdr, sizeof(hdr)); 516 MD5_Update(&c, &hdr, sizeof(hdr));
@@ -573,7 +524,7 @@ static int create_upg(int argc, char **argv)
573 entry.offset = offset; 524 entry.offset = offset;
574 entry.size = filesize(files[i]); 525 entry.size = filesize(files[i]);
575 offset += ROUND_UP(entry.size, 8); // do it before encryption !! 526 offset += ROUND_UP(entry.size, 8); // do it before encryption !!
576 527
577 ret = fwp_write(&entry, sizeof(entry), &entry, (void *)g_key); 528 ret = fwp_write(&entry, sizeof(entry), &entry, (void *)g_key);
578 if(ret) 529 if(ret)
579 return ret; 530 return ret;