diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/nwztools/upgtools/Makefile | 26 | ||||
-rw-r--r-- | utils/nwztools/upgtools/fwp.c | 56 | ||||
-rw-r--r-- | utils/nwztools/upgtools/fwp.h | 44 | ||||
-rw-r--r-- | utils/nwztools/upgtools/keysig_search.c | 157 | ||||
-rw-r--r-- | utils/nwztools/upgtools/keysig_search.h | 50 | ||||
-rw-r--r-- | utils/nwztools/upgtools/mg.cpp | 67 | ||||
-rw-r--r-- | utils/nwztools/upgtools/mg.h | 37 | ||||
-rw-r--r-- | utils/nwztools/upgtools/misc.c | 53 | ||||
-rw-r--r-- | utils/nwztools/upgtools/misc.h | 46 | ||||
-rw-r--r-- | utils/nwztools/upgtools/upgtool.c | 542 |
10 files changed, 1078 insertions, 0 deletions
diff --git a/utils/nwztools/upgtools/Makefile b/utils/nwztools/upgtools/Makefile new file mode 100644 index 0000000000..ad83c0e4c6 --- /dev/null +++ b/utils/nwztools/upgtools/Makefile | |||
@@ -0,0 +1,26 @@ | |||
1 | DEFINES= | ||
2 | CC=gcc | ||
3 | CXX=g++ | ||
4 | LD=g++ | ||
5 | PROFILE= | ||
6 | CFLAGS=-g $(PROFILE) -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl` `pkg-config --cflags libcrypto++` | ||
7 | CXXFLAGS=-g $(PROFILE) -W -Wall $(DEFINES) `pkg-config --cflags openssl` `pkg-config --cflags libcrypto++` | ||
8 | LDFLAGS=$(PROFILE) `pkg-config --libs openssl` `pkg-config --libs libcrypto++` -lcrypt | ||
9 | BINS=upgtool | ||
10 | |||
11 | all: $(BINS) | ||
12 | |||
13 | %.o: %.c | ||
14 | $(CC) $(CFLAGS) -c -o $@ $< | ||
15 | |||
16 | %.o: %.cpp | ||
17 | $(CXX) $(CXXFLAGS) -c -o $@ $< | ||
18 | |||
19 | upgtool: upgtool.o misc.o fwp.o mg.o keysig_search.o | ||
20 | $(LD) -o $@ $^ $(LDFLAGS) | ||
21 | |||
22 | clean: | ||
23 | rm -fr *.o | ||
24 | |||
25 | veryclean: | ||
26 | rm -rf $(BINS) | ||
diff --git a/utils/nwztools/upgtools/fwp.c b/utils/nwztools/upgtools/fwp.c new file mode 100644 index 0000000000..e739b8caef --- /dev/null +++ b/utils/nwztools/upgtools/fwp.c | |||
@@ -0,0 +1,56 @@ | |||
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 <stdio.h> | ||
22 | #include "fwp.h" | ||
23 | #include "misc.h" | ||
24 | #include "mg.h" | ||
25 | #include <string.h> | ||
26 | |||
27 | int fwp_read(void *in, int size, void *out, uint8_t *key) | ||
28 | { | ||
29 | return mg_decrypt_fw(in, size, out, key); | ||
30 | } | ||
31 | |||
32 | static uint8_t g_key[NWZ_KEY_SIZE]; | ||
33 | |||
34 | void fwp_setkey(char key[NWZ_KEY_SIZE]) | ||
35 | { | ||
36 | memcpy(g_key, key, NWZ_KEY_SIZE); | ||
37 | } | ||
38 | |||
39 | int fwp_crypt(void *buf, int size, int mode) | ||
40 | { | ||
41 | while(size >= NWZ_KEY_SIZE) | ||
42 | { | ||
43 | if(mode) | ||
44 | mg_decrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key); | ||
45 | else | ||
46 | mg_encrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key); | ||
47 | buf += NWZ_KEY_SIZE; | ||
48 | size -= NWZ_KEY_SIZE; | ||
49 | } | ||
50 | if(size != 0) | ||
51 | { | ||
52 | cprintf(GREY, "Cannot fwp_crypt non-multiple of 8!\n"); | ||
53 | return -1; | ||
54 | } | ||
55 | return 0; | ||
56 | } \ No newline at end of file | ||
diff --git a/utils/nwztools/upgtools/fwp.h b/utils/nwztools/upgtools/fwp.h new file mode 100644 index 0000000000..dcfe80027e --- /dev/null +++ b/utils/nwztools/upgtools/fwp.h | |||
@@ -0,0 +1,44 @@ | |||
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 | ||
27 | extern "C" { | ||
28 | #endif | ||
29 | |||
30 | #define NWZ_KAS_SIZE 32 | ||
31 | #define NWZ_KEYSIG_SIZE 51 | ||
32 | #define NWZ_KEY_SIZE 8 | ||
33 | #define NWZ_EXPKEY_SIZE (NWZ_KEY_SIZE * NWZ_KEY_SIZE) | ||
34 | #define NWZ_DES_BLOCK 8 | ||
35 | |||
36 | int fwp_read(void *in, int size, void *out, uint8_t *key); | ||
37 | void fwp_setkey(char key[8]); | ||
38 | int fwp_crypt(void *buf, int size, int mode); | ||
39 | |||
40 | #ifdef __cplusplus | ||
41 | } | ||
42 | #endif | ||
43 | |||
44 | #endif /* __fwp_h__ */ | ||
diff --git a/utils/nwztools/upgtools/keysig_search.c b/utils/nwztools/upgtools/keysig_search.c new file mode 100644 index 0000000000..6054ea43ba --- /dev/null +++ b/utils/nwztools/upgtools/keysig_search.c | |||
@@ -0,0 +1,157 @@ | |||
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 "keysig_search.h" | ||
22 | #include "misc.h" | ||
23 | #include "mg.h" | ||
24 | #include <string.h> | ||
25 | |||
26 | #define HEX_MAJ | ||
27 | |||
28 | static uint8_t g_cipher[8]; | ||
29 | static keysig_notify_fn_t g_notify; | ||
30 | static uint8_t g_key[8]; | ||
31 | static void *g_user; | ||
32 | static bool is_hex[256]; | ||
33 | static bool is_init = false; | ||
34 | #ifdef HEX_MAJ | ||
35 | static char hex_digits[] = "02468ABEF"; | ||
36 | #else | ||
37 | static char hex_digits[] = "02468abef"; | ||
38 | #endif | ||
39 | |||
40 | static void keysig_search_init() | ||
41 | { | ||
42 | if(is_init) return; | ||
43 | is_init = true; | ||
44 | memset(is_hex, 0, sizeof(is_hex)); | ||
45 | for(int i = '0'; i <= '9'; i++) | ||
46 | 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++) | ||
51 | #endif | ||
52 | is_hex[i] = true; | ||
53 | } | ||
54 | |||
55 | static inline bool is_full_ascii(uint8_t *arr) | ||
56 | { | ||
57 | for(int i = 0; i < 8; i++) | ||
58 | if(!is_hex[arr[i]]) | ||
59 | return false; | ||
60 | return true; | ||
61 | } | ||
62 | |||
63 | static inline bool check_stupid() | ||
64 | { | ||
65 | uint8_t res[8]; | ||
66 | mg_decrypt_fw(g_cipher, 8, res, g_key); | ||
67 | if(is_full_ascii(res)) | ||
68 | return g_notify(g_user, g_key, res); | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | static bool search_stupid_rec(int rem_digit, int rem_letter, int pos) | ||
73 | { | ||
74 | if(pos == 8) | ||
75 | return check_stupid(); | ||
76 | if(rem_digit > 0) | ||
77 | { | ||
78 | for(int i = '0'; i <= '9'; i += 2) | ||
79 | { | ||
80 | g_key[pos] = i; | ||
81 | if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1)) | ||
82 | return true; | ||
83 | } | ||
84 | } | ||
85 | if(rem_letter > 0) | ||
86 | { | ||
87 | #ifdef HEX_MAJ | ||
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 | { | ||
93 | g_key[pos] = i; | ||
94 | if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1)) | ||
95 | return true; | ||
96 | } | ||
97 | } | ||
98 | return false; | ||
99 | } | ||
100 | |||
101 | static bool search_stupid(int rem_digit, int rem_letter) | ||
102 | { | ||
103 | return search_stupid_rec(rem_digit, rem_letter, 0); | ||
104 | } | ||
105 | |||
106 | bool keysig_search_ascii_stupid(uint8_t *cipher, keysig_notify_fn_t notify, void *user) | ||
107 | { | ||
108 | keysig_search_init(); | ||
109 | memcpy(g_cipher, cipher, 8); | ||
110 | g_notify = notify; | ||
111 | g_user = user; | ||
112 | #if 1 | ||
113 | return search_stupid(4, 4) || | ||
114 | search_stupid(3, 5) || search_stupid(5, 3) || | ||
115 | search_stupid(2, 6) || search_stupid(6, 2) || | ||
116 | search_stupid(1, 7) || search_stupid(7, 1) || | ||
117 | search_stupid(0, 8) || search_stupid(8, 0); | ||
118 | #else | ||
119 | #define do(i) for(int a##i = 0; a##i < sizeof(hex_digits); a##i++) { g_key[i] = hex_digits[a##i]; | ||
120 | #define od() } | ||
121 | |||
122 | do(0)do(1)do(2)do(3)do(4)do(5)do(6)do(7) | ||
123 | if(check_stupid()) return true; | ||
124 | od()od()od()od()od()od()od()od() | ||
125 | #undef do | ||
126 | #undef od | ||
127 | return false; | ||
128 | #endif | ||
129 | } | ||
130 | |||
131 | bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user) | ||
132 | { | ||
133 | keysig_search_init(); | ||
134 | return false; | ||
135 | } | ||
136 | |||
137 | struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST] = | ||
138 | { | ||
139 | [KEYSIG_SEARCH_NONE] = | ||
140 | { | ||
141 | .name = "none", | ||
142 | .fn = NULL, | ||
143 | .comment = "don't use", | ||
144 | }, | ||
145 | [KEYSIG_SEARCH_ASCII_STUPID] = | ||
146 | { | ||
147 | .name = "ascii-stupid", | ||
148 | .fn = keysig_search_ascii_stupid, | ||
149 | .comment = "Try to find a balance ascii key ignoring lsb" | ||
150 | }, | ||
151 | [KEYSIG_SEARCH_ASCII_BRUTE] = | ||
152 | { | ||
153 | .name = "ascii-brute", | ||
154 | .fn = keysig_search_ascii_brute, | ||
155 | .comment = "Brute force all ASCII keys" | ||
156 | }, | ||
157 | }; | ||
diff --git a/utils/nwztools/upgtools/keysig_search.h b/utils/nwztools/upgtools/keysig_search.h new file mode 100644 index 0000000000..46639dfb47 --- /dev/null +++ b/utils/nwztools/upgtools/keysig_search.h | |||
@@ -0,0 +1,50 @@ | |||
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 __keysig_search_h__ | ||
22 | #define __keysig_search_h__ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include <stdint.h> | ||
26 | |||
27 | enum keysig_search_method_t | ||
28 | { | ||
29 | KEYSIG_SEARCH_NONE = 0, | ||
30 | KEYSIG_SEARCH_FIRST, | ||
31 | KEYSIG_SEARCH_ASCII_STUPID = KEYSIG_SEARCH_FIRST, | ||
32 | KEYSIG_SEARCH_ASCII_BRUTE, | ||
33 | KEYSIG_SEARCH_LAST | ||
34 | }; | ||
35 | |||
36 | /* notify returns true if the key seems ok */ | ||
37 | typedef bool (*keysig_notify_fn_t)(void *user, uint8_t key[8], uint8_t sig[8]); | ||
38 | /* returns true if a key was accepted by notify */ | ||
39 | typedef bool (*keysig_search_fn_t)(uint8_t *cipher, keysig_notify_fn_t notify, void *user); | ||
40 | |||
41 | struct keysig_search_desc_t | ||
42 | { | ||
43 | const char *name; | ||
44 | const char *comment; | ||
45 | keysig_search_fn_t fn; | ||
46 | }; | ||
47 | |||
48 | struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST]; | ||
49 | |||
50 | #endif /* __keysig_search_h__ */ | ||
diff --git a/utils/nwztools/upgtools/mg.cpp b/utils/nwztools/upgtools/mg.cpp new file mode 100644 index 0000000000..8816259755 --- /dev/null +++ b/utils/nwztools/upgtools/mg.cpp | |||
@@ -0,0 +1,67 @@ | |||
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 "mg.h" | ||
22 | #include <crypto++/cryptlib.h> | ||
23 | #include <crypto++/modes.h> | ||
24 | #include <crypto++/des.h> | ||
25 | #include <crypto++/aes.h> | ||
26 | #include <stdio.h> | ||
27 | |||
28 | using namespace CryptoPP; | ||
29 | namespace | ||
30 | { | ||
31 | ECB_Mode< DES >::Decryption g_dec; | ||
32 | ECB_Mode< DES >::Encryption g_enc; | ||
33 | |||
34 | inline int dec_des_ecb(void *in, int size, void *out, uint8_t *key) | ||
35 | { | ||
36 | g_dec.SetKey(key, 8); | ||
37 | g_dec.ProcessData((byte*)out, (byte*)in, size); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | inline int enc_des_ecb(void *in, int size, void *out, uint8_t *key) | ||
42 | { | ||
43 | g_enc.SetKey(key, 8); | ||
44 | g_enc.ProcessData((byte*)out, (byte*)in, size); | ||
45 | return 0; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | int mg_decrypt_fw(void *in, int size, void *out, uint8_t *key) | ||
50 | { | ||
51 | return dec_des_ecb(in, size, out, key); | ||
52 | } | ||
53 | |||
54 | int mg_encrypt_fw(void *in, int size, void *out, uint8_t *key) | ||
55 | { | ||
56 | return enc_des_ecb(in, size, out, key); | ||
57 | } | ||
58 | |||
59 | int mg_decrypt_pass(void *in, int size, void *out, uint8_t *key) | ||
60 | { | ||
61 | return dec_des_ecb(in, size, out, key); | ||
62 | } | ||
63 | |||
64 | int mg_encrypt_pass(void *in, int size, void *out, uint8_t *key) | ||
65 | { | ||
66 | return enc_des_ecb(in, size, out, key); | ||
67 | } | ||
diff --git a/utils/nwztools/upgtools/mg.h b/utils/nwztools/upgtools/mg.h new file mode 100644 index 0000000000..a0c1f2ef65 --- /dev/null +++ b/utils/nwztools/upgtools/mg.h | |||
@@ -0,0 +1,37 @@ | |||
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 __mg_h__ | ||
22 | #define __mg_h__ | ||
23 | |||
24 | #include <stdint.h> | ||
25 | |||
26 | #ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | #endif | ||
29 | int mg_decrypt_fw(void *in, int size, void *out, uint8_t *key); | ||
30 | int mg_encrypt_fw(void *in, int size, void *out, uint8_t *key); | ||
31 | int mg_decrypt_pass(void *in, int size, void *out, uint8_t *key); | ||
32 | int mg_encrypt_pass(void *in, int size, void *out, uint8_t *key); | ||
33 | #ifdef __cplusplus | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | #endif /* __mg_h__ */ \ No newline at end of file | ||
diff --git a/utils/nwztools/upgtools/misc.c b/utils/nwztools/upgtools/misc.c new file mode 100644 index 0000000000..108235e7fd --- /dev/null +++ b/utils/nwztools/upgtools/misc.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 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 <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include <time.h> | ||
24 | #include <ctype.h> | ||
25 | #include "misc.h" | ||
26 | |||
27 | char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; | ||
28 | |||
29 | char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; | ||
30 | char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; | ||
31 | char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; | ||
32 | char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; | ||
33 | char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | ||
34 | |||
35 | static bool g_color_enable = true; | ||
36 | |||
37 | void *xmalloc(size_t s) | ||
38 | { | ||
39 | void * r = malloc(s); | ||
40 | if(!r) bugp("malloc"); | ||
41 | return r; | ||
42 | } | ||
43 | |||
44 | void enable_color(bool enable) | ||
45 | { | ||
46 | g_color_enable = enable; | ||
47 | } | ||
48 | |||
49 | void color(color_t c) | ||
50 | { | ||
51 | if(g_color_enable) | ||
52 | printf("%s", (char *)c); | ||
53 | } | ||
diff --git a/utils/nwztools/upgtools/misc.h b/utils/nwztools/upgtools/misc.h new file mode 100644 index 0000000000..96666a2eff --- /dev/null +++ b/utils/nwztools/upgtools/misc.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 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 __MISC_H__ | ||
22 | #define __MISC_H__ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include <stddef.h> | ||
26 | |||
27 | #define _STR(a) #a | ||
28 | #define STR(a) _STR(a) | ||
29 | |||
30 | #define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) | ||
31 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) | ||
32 | |||
33 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | ||
34 | |||
35 | typedef char color_t[]; | ||
36 | |||
37 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; | ||
38 | void *xmalloc(size_t s); | ||
39 | void color(color_t c); | ||
40 | void enable_color(bool enable); | ||
41 | |||
42 | #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) | ||
43 | |||
44 | #define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0) | ||
45 | |||
46 | #endif /* __MISC_H__ */ | ||
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c new file mode 100644 index 0000000000..73303e72d3 --- /dev/null +++ b/utils/nwztools/upgtools/upgtool.c | |||
@@ -0,0 +1,542 @@ | |||
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 <stdio.h> | ||
22 | #include <stdint.h> | ||
23 | #include <stdbool.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #include <getopt.h> | ||
27 | #include <stdarg.h> | ||
28 | #include <ctype.h> | ||
29 | #include "misc.h" | ||
30 | #include "elf.h" | ||
31 | #include <sys/stat.h> | ||
32 | #include <openssl/md5.h> | ||
33 | #include "crypt.h" | ||
34 | #include "fwp.h" | ||
35 | #include "keysig_search.h" | ||
36 | |||
37 | #ifndef MIN | ||
38 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
39 | #endif | ||
40 | |||
41 | bool g_debug = false; | ||
42 | static char *g_out_prefix = NULL; | ||
43 | static char *g_in_file = NULL; | ||
44 | bool g_force = false; | ||
45 | static const char *g_model = NULL; | ||
46 | static int g_model_index = -1; | ||
47 | static char *g_kas = NULL; | ||
48 | static char *g_key = NULL; | ||
49 | static char *g_sig = NULL; | ||
50 | |||
51 | enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE; | ||
52 | |||
53 | |||
54 | #define let_the_force_flow(x) do { if(!g_force) return x; } while(0) | ||
55 | #define continue_the_force(x) if(x) let_the_force_flow(x) | ||
56 | |||
57 | #define check_field(v_exp, v_have, str_ok, str_bad) \ | ||
58 | if((v_exp) != (v_have)) \ | ||
59 | { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \ | ||
60 | else { cprintf(RED, str_ok); } | ||
61 | |||
62 | static void print_hex(void *p, int size, int unit) | ||
63 | { | ||
64 | uint8_t *p8 = p; | ||
65 | uint16_t *p16 = p; | ||
66 | uint32_t *p32 = p; | ||
67 | for(int i = 0; i < size; i += unit, p8++, p16++, p32++) | ||
68 | { | ||
69 | if(i != 0 && (i % 16) == 0) | ||
70 | printf("\n"); | ||
71 | if(unit == 1) | ||
72 | printf(" %02x", *p8); | ||
73 | else if(unit == 2) | ||
74 | printf(" %04x", *p16); | ||
75 | else | ||
76 | printf(" %08x", *p32); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* key and signature */ | ||
81 | struct nwz_kas_t | ||
82 | { | ||
83 | char kas[NWZ_KAS_SIZE]; | ||
84 | }; | ||
85 | |||
86 | #define HAS_KAS (1 << 0) | ||
87 | #define HAS_KEY (1 << 1) | ||
88 | #define HAS_SIG (1 << 2) | ||
89 | #define CONFIRMED (1 << 3) | ||
90 | |||
91 | struct nwz_model_t | ||
92 | { | ||
93 | const char *model; | ||
94 | unsigned flags; | ||
95 | struct nwz_kas_t kas; | ||
96 | char key[8]; | ||
97 | char sig[8]; | ||
98 | }; | ||
99 | |||
100 | struct upg_md5_t | ||
101 | { | ||
102 | uint8_t md5[16]; | ||
103 | }__attribute__((packed)); | ||
104 | |||
105 | struct upg_header_t | ||
106 | { | ||
107 | char sig[8]; | ||
108 | uint32_t nr_files; | ||
109 | uint32_t unk; | ||
110 | } __attribute__((packed)); | ||
111 | |||
112 | struct upg_entry_t | ||
113 | { | ||
114 | uint32_t offset; | ||
115 | uint32_t size; | ||
116 | } __attribute__((packed)); | ||
117 | |||
118 | struct nwz_model_t g_model_list[] = | ||
119 | { | ||
120 | { "nwz-e463", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, {"89d813f8f966efdebd9c9e0ea98156d2"}, "eb4431eb", "4f1d9cac" }, | ||
121 | { "nwz-a86x", HAS_KEY | HAS_SIG, {""}, "c824e4e2", "7c262bb0" }, | ||
122 | { "nw-a82x", HAS_KEY | HAS_SIG, {""}, "4df06482", "07fa0b6e" }, | ||
123 | }; | ||
124 | |||
125 | static int digit_value(char c) | ||
126 | { | ||
127 | if(c >= '0' && c <= '9') return c - '0'; | ||
128 | if(c >= 'a' && c <= 'f') return c - 'a' + 10; | ||
129 | if(c >= 'A' && c <= 'F') return c - 'A' + 10; | ||
130 | return -1; | ||
131 | } | ||
132 | |||
133 | static char hex_digit(unsigned v) | ||
134 | { | ||
135 | return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x'; | ||
136 | } | ||
137 | |||
138 | static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE]) | ||
139 | { | ||
140 | uint8_t src[16]; | ||
141 | for(int i = 32; i < NWZ_KEYSIG_SIZE; i++) | ||
142 | keysig[i] = 0; | ||
143 | for(int index = 0; index < 16; index++) | ||
144 | { | ||
145 | int a = digit_value(keysig[index * 2]); | ||
146 | int b = digit_value(keysig[index * 2 + 1]); | ||
147 | if(a < 0 || b < 0) | ||
148 | { | ||
149 | cprintf(GREY, "Invalid KAS !\n"); | ||
150 | return -1; | ||
151 | } | ||
152 | src[index] = a << 4 | b; | ||
153 | } | ||
154 | fwp_setkey("ed295076"); | ||
155 | fwp_crypt(src, sizeof(src), 1); | ||
156 | memcpy(keysig + 33, src, 8); | ||
157 | memcpy(keysig + 42, src + 8, 8); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static bool upg_notify_keysig(void *user, uint8_t key[8], uint8_t sig[8]) | ||
162 | { | ||
163 | memcpy(user + 33, key, 8); | ||
164 | memcpy(user + 42, sig, 8); | ||
165 | return true; | ||
166 | } | ||
167 | |||
168 | static int do_upg(void *buf, long size) | ||
169 | { | ||
170 | struct upg_md5_t *md5 = buf; | ||
171 | cprintf(BLUE, "Preliminary\n"); | ||
172 | cprintf(GREEN, " MD5: "); | ||
173 | for(int i = 0; i < 16; i++) | ||
174 | cprintf(YELLOW, "%02x", md5->md5[i]); | ||
175 | printf(" "); | ||
176 | |||
177 | uint8_t actual_md5[MD5_DIGEST_LENGTH]; | ||
178 | { | ||
179 | MD5_CTX c; | ||
180 | MD5_Init(&c); | ||
181 | MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t)); | ||
182 | MD5_Final(actual_md5, &c); | ||
183 | } | ||
184 | check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n"); | ||
185 | |||
186 | if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL) | ||
187 | { | ||
188 | cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); | ||
189 | cprintf(GREY, "You have the following options(see hel for more details):\n"); | ||
190 | cprintf(GREY, "- select a model with a known KAS\n"); | ||
191 | cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n"); | ||
192 | cprintf(GREY, "- let me try to find the keysig(slow !)\n"); | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | struct nwz_kas_t kas; | ||
197 | char keysig[NWZ_KEYSIG_SIZE]; | ||
198 | |||
199 | memset(kas.kas, '?', NWZ_KAS_SIZE); | ||
200 | memset(keysig, '?', NWZ_KEYSIG_SIZE); | ||
201 | keysig[32] = keysig[41] = keysig[50] = 0; | ||
202 | |||
203 | if(g_kas) | ||
204 | { | ||
205 | if(strlen(g_kas) != NWZ_KAS_SIZE) | ||
206 | { | ||
207 | cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); | ||
208 | return 4; | ||
209 | } | ||
210 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
211 | decrypt_keysig(keysig); | ||
212 | g_kas = keysig; | ||
213 | g_key = keysig + 33; | ||
214 | g_sig = keysig + 42; | ||
215 | } | ||
216 | else if(g_key) | ||
217 | { | ||
218 | if(strlen(g_key) != 8) | ||
219 | { | ||
220 | cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); | ||
221 | return 4; | ||
222 | } | ||
223 | if(g_sig && strlen(g_sig) != 8) | ||
224 | { | ||
225 | cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); | ||
226 | return 5; | ||
227 | } | ||
228 | |||
229 | memcpy(keysig + 33, g_key, 8); | ||
230 | if(!g_sig) | ||
231 | cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n"); | ||
232 | else | ||
233 | memcpy(keysig + 42, g_sig, 8); | ||
234 | g_key = keysig + 33; | ||
235 | if(g_sig) | ||
236 | g_sig = keysig + 42; | ||
237 | } | ||
238 | else if(g_model_index == -1) | ||
239 | { | ||
240 | cprintf(BLUE, "keysig Search\n"); | ||
241 | cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name); | ||
242 | bool ok = keysig_search_desc[g_keysig_search].fn((void *)(md5 + 1), &upg_notify_keysig, keysig); | ||
243 | cprintf(GREEN, " Result: "); | ||
244 | cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found"); | ||
245 | if(!ok) | ||
246 | return 2; | ||
247 | g_key = keysig + 33; | ||
248 | g_sig = keysig + 42; | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | if(g_model_list[g_model_index].flags & HAS_KAS) | ||
253 | g_kas = g_model_list[g_model_index].kas.kas; | ||
254 | if(g_model_list[g_model_index].flags & HAS_KEY) | ||
255 | g_key = g_model_list[g_model_index].key; | ||
256 | if(g_model_list[g_model_index].flags & HAS_SIG) | ||
257 | g_sig = g_model_list[g_model_index].sig; | ||
258 | |||
259 | if(g_kas) | ||
260 | { | ||
261 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
262 | decrypt_keysig(keysig); | ||
263 | g_kas = keysig; | ||
264 | g_key = keysig + 33; | ||
265 | g_sig = keysig + 42; | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | if(g_key) | ||
270 | { | ||
271 | memcpy(keysig + 33, g_key, 8); | ||
272 | g_key = keysig + 33; | ||
273 | } | ||
274 | if(g_sig) | ||
275 | { | ||
276 | memcpy(keysig + 42, g_sig, 8); | ||
277 | g_sig = keysig + 42; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if(!g_kas) | ||
283 | { | ||
284 | g_kas = keysig; | ||
285 | fwp_setkey("ed295076"); | ||
286 | if(g_key) | ||
287 | { | ||
288 | memcpy(kas.kas, g_key, 8); | ||
289 | fwp_crypt(kas.kas, 8, 0); | ||
290 | for(int i = 0; i < 8; i++) | ||
291 | { | ||
292 | g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf); | ||
293 | g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf); | ||
294 | } | ||
295 | } | ||
296 | if(g_sig) | ||
297 | { | ||
298 | memcpy(kas.kas + 8, g_sig, 8); | ||
299 | fwp_crypt(kas.kas + 8, 8, 0); | ||
300 | for(int i = 8; i < 16; i++) | ||
301 | { | ||
302 | g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf); | ||
303 | g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf); | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | |||
308 | cprintf(BLUE, "Keys\n"); | ||
309 | cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); | ||
310 | cprintf_field(" Key: ", "%s\n", g_key); | ||
311 | if(g_sig) | ||
312 | cprintf_field(" Sig: ", "%s\n", g_sig); | ||
313 | |||
314 | struct upg_header_t *hdr = (void *)(md5 + 1); | ||
315 | int ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key); | ||
316 | if(ret) | ||
317 | return ret; | ||
318 | |||
319 | cprintf(BLUE, "Header\n"); | ||
320 | cprintf_field(" Signature:", " "); | ||
321 | for(int i = 0; i < 8; i++) | ||
322 | cprintf(YELLOW, "%c", isprint(hdr->sig[i]) ? hdr->sig[i] : '.'); | ||
323 | if(g_sig) | ||
324 | { | ||
325 | check_field(memcmp(hdr->sig, g_sig, 8), 0, " OK\n", " Mismatch\n"); | ||
326 | } | ||
327 | else | ||
328 | cprintf(RED, " Can't check\n"); | ||
329 | cprintf_field(" Files: ", "%d\n", hdr->nr_files); | ||
330 | cprintf_field(" Unk: ", "0x%x\n", hdr->unk); | ||
331 | |||
332 | cprintf(BLUE, "Files\n"); | ||
333 | struct upg_entry_t *entry = (void *)(hdr + 1); | ||
334 | for(unsigned i = 0; i < hdr->nr_files; i++, entry++) | ||
335 | { | ||
336 | int ret = fwp_read(entry, sizeof(struct upg_entry_t), entry, (void *)g_key); | ||
337 | if(ret) | ||
338 | return ret; | ||
339 | cprintf(GREY, " File"); | ||
340 | cprintf(RED, " %d\n", i); | ||
341 | cprintf_field(" Offset: ", "0x%x\n", entry->offset); | ||
342 | cprintf_field(" Size: ", "0x%x\n", entry->size); | ||
343 | |||
344 | if(g_out_prefix) | ||
345 | { | ||
346 | char *str = malloc(strlen(g_out_prefix) + 32); | ||
347 | sprintf(str, "%s/%d.bin", g_out_prefix, i); | ||
348 | FILE *f = fopen(str, "wb"); | ||
349 | if(f) | ||
350 | { | ||
351 | int ret = fwp_read(buf + entry->offset, entry->size, | ||
352 | buf + entry->offset, (void *)g_key); | ||
353 | if(ret) | ||
354 | return ret; | ||
355 | fwrite(buf + entry->offset, 1, entry->size, f); | ||
356 | |||
357 | fclose(f); | ||
358 | } | ||
359 | else | ||
360 | cprintf(GREY, "Cannot open '%s' for writing\n", str); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static void usage(void) | ||
368 | { | ||
369 | color(OFF); | ||
370 | printf("Usage: upgtool [options] firmware\n"); | ||
371 | printf("Options:\n"); | ||
372 | printf(" -o <prefix>\t\tSet output prefix\n"); | ||
373 | printf(" -f/--force\t\tForce to continue on errors\n"); | ||
374 | printf(" -?/--help\t\tDisplay this message\n"); | ||
375 | printf(" -d/--debug\t\tDisplay debug messages\n"); | ||
376 | printf(" -c/--no-color\t\tDisable color output\n"); | ||
377 | printf(" -m/--model <model>\tSelect model (or ? to list them)\n"); | ||
378 | printf(" -l/--search <method>\tTry to find the keysig\n"); | ||
379 | printf(" -a/--kas <kas>\tForce KAS\n"); | ||
380 | printf(" -k/--key <key>\tForce key\n"); | ||
381 | printf(" -s/--sig <sig>\tForce sig\n"); | ||
382 | printf("keysig search method:\n"); | ||
383 | for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) | ||
384 | printf(" %s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment); | ||
385 | exit(1); | ||
386 | } | ||
387 | |||
388 | int main(int argc, char **argv) | ||
389 | { | ||
390 | while(1) | ||
391 | { | ||
392 | static struct option long_options[] = | ||
393 | { | ||
394 | {"help", no_argument, 0, '?'}, | ||
395 | {"debug", no_argument, 0, 'd'}, | ||
396 | {"no-color", no_argument, 0, 'c'}, | ||
397 | {"force", no_argument, 0, 'f'}, | ||
398 | {"model", required_argument, 0, 'm'}, | ||
399 | {"search", required_argument, 0, 'l'}, | ||
400 | {"kas", required_argument, 0, 'a'}, | ||
401 | {"key", required_argument, 0, 'k'}, | ||
402 | {"sig", required_argument, 0, 's'}, | ||
403 | {0, 0, 0, 0} | ||
404 | }; | ||
405 | |||
406 | int c = getopt_long(argc, argv, "?dcfo:m:l:a:k:s:", long_options, NULL); | ||
407 | if(c == -1) | ||
408 | break; | ||
409 | switch(c) | ||
410 | { | ||
411 | case -1: | ||
412 | break; | ||
413 | case 'c': | ||
414 | enable_color(false); | ||
415 | break; | ||
416 | case 'd': | ||
417 | g_debug = true; | ||
418 | break; | ||
419 | case 'f': | ||
420 | g_force = true; | ||
421 | break; | ||
422 | case '?': | ||
423 | usage(); | ||
424 | break; | ||
425 | case 'o': | ||
426 | g_out_prefix = optarg; | ||
427 | break; | ||
428 | case 'm': | ||
429 | g_model = optarg; | ||
430 | break; | ||
431 | case 'l': | ||
432 | g_keysig_search = KEYSIG_SEARCH_NONE; | ||
433 | for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) | ||
434 | if(strcmp(keysig_search_desc[i].name, optarg) == 0) | ||
435 | g_keysig_search = i; | ||
436 | if(g_keysig_search == KEYSIG_SEARCH_NONE) | ||
437 | { | ||
438 | cprintf(GREY, "Unknown keysig search method '%s'\n", optarg); | ||
439 | return 1; | ||
440 | } | ||
441 | break; | ||
442 | case 'a': | ||
443 | g_kas = optarg; | ||
444 | break; | ||
445 | case 'k': | ||
446 | g_key = optarg; | ||
447 | break; | ||
448 | case 's': | ||
449 | g_sig = optarg; | ||
450 | break; | ||
451 | default: | ||
452 | abort(); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | if(g_model && strcmp(g_model, "?") == 0) | ||
457 | { | ||
458 | cprintf(BLUE, "Model list:\n"); | ||
459 | for(unsigned i = 0; i < sizeof(g_model_list) / sizeof(g_model_list[0]); i++) | ||
460 | { | ||
461 | cprintf(GREEN, " %s:", g_model_list[i].model); | ||
462 | if(g_model_list[i].flags & HAS_KAS) | ||
463 | { | ||
464 | cprintf(RED, " kas="); | ||
465 | cprintf(YELLOW, "%."STR(NWZ_KAS_SIZE)"s", g_model_list[i].kas.kas); | ||
466 | } | ||
467 | if(g_model_list[i].flags & HAS_KEY) | ||
468 | { | ||
469 | cprintf(RED, " key="); | ||
470 | cprintf(YELLOW, "%.8s", g_model_list[i].key); | ||
471 | } | ||
472 | if(g_model_list[i].flags & HAS_SIG) | ||
473 | { | ||
474 | cprintf(RED, " sig="); | ||
475 | cprintf(YELLOW, "%.8s", g_model_list[i].sig); | ||
476 | } | ||
477 | if(g_model_list[i].flags & CONFIRMED) | ||
478 | cprintf(RED, " confirmed"); | ||
479 | else | ||
480 | cprintf(RED, " guessed"); | ||
481 | printf("\n"); | ||
482 | } | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | if(g_model) | ||
487 | { | ||
488 | for(unsigned i = 0; i < sizeof(g_model_list) / sizeof(g_model_list[0]); i++) | ||
489 | if(strcmp(g_model, g_model_list[i].model) == 0) | ||
490 | g_model_index = i; | ||
491 | if(g_model_index == -1) | ||
492 | cprintf(GREY, "Warning: unknown model %s\n", g_model); | ||
493 | } | ||
494 | |||
495 | if(argc - optind != 1) | ||
496 | { | ||
497 | usage(); | ||
498 | return 1; | ||
499 | } | ||
500 | |||
501 | g_in_file = argv[optind]; | ||
502 | FILE *fin = fopen(g_in_file, "r"); | ||
503 | if(fin == NULL) | ||
504 | { | ||
505 | perror("Cannot open boot file"); | ||
506 | return 1; | ||
507 | } | ||
508 | fseek(fin, 0, SEEK_END); | ||
509 | long size = ftell(fin); | ||
510 | fseek(fin, 0, SEEK_SET); | ||
511 | |||
512 | void *buf = malloc(size); | ||
513 | if(buf == NULL) | ||
514 | { | ||
515 | perror("Cannot allocate memory"); | ||
516 | return 1; | ||
517 | } | ||
518 | |||
519 | if(fread(buf, size, 1, fin) != 1) | ||
520 | { | ||
521 | perror("Cannot read file"); | ||
522 | return 1; | ||
523 | } | ||
524 | |||
525 | fclose(fin); | ||
526 | |||
527 | int ret = do_upg(buf, size); | ||
528 | if(ret != 0) | ||
529 | { | ||
530 | cprintf(GREY, "Error: %d", ret); | ||
531 | if(!g_force) | ||
532 | cprintf(GREY, " (use --force to force processing)"); | ||
533 | printf("\n"); | ||
534 | ret = 2; | ||
535 | } | ||
536 | free(buf); | ||
537 | |||
538 | color(OFF); | ||
539 | |||
540 | return ret; | ||
541 | } | ||
542 | |||