1 /* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <getpot/GetPot>
49 const char* null_key
; /* HMAC-SHA1 key */
50 const char* fresc_key
; /* BlowFish key */
51 const char* tl_key
; /* BlowFish key */
57 static const char VERSION
[] = "0.2";
59 static const char null_key_v1
[] = "CTL:N0MAD|PDE0.SIGN.";
60 static const char null_key_v2
[] = "CTL:N0MAD|PDE0.DPMP.";
61 static const char null_key_v3
[] = "CTL:N0MAD|PDE0.DPFP.";
62 static const char null_key_v4
[] = "CTL:Z3N07|PDE0.DPMP.";
64 static const char fresc_key_v1
[] = "Copyright (C) CTL. -"
65 " zN0MAD iz v~p0wderful!";
66 static const char fresc_key_v2
[] = ""; /* Unknown atm */
68 static const char tl_zvm_key
[] = "1sN0TM3D az u~may th1nk*"
69 "Creative Zen Vision:M";
70 static const char tl_zvm60_key
[] = "1sN0TM3D az u~may th1nk*"
71 "Creative Zen Vision:M (D"
73 static const char tl_zen_key
[] = "1sN0TM3D az u~may th1nk*"
75 static const char tl_zenxf_key
[] = "1sN0TM3D az u~may th1nk*"
77 static const char tl_zenmo_key
[] = "1sN0TM3D az u~may th1nk*"
78 "Creative ZEN Mozaic";
79 static const char tl_zv_key
[] = "1sN0TM3D az u~may th1nk*"
80 "Creative Zen Vision";
81 static const char tl_zvw_key
[] = "1sN0TM3D az u~may th1nk*"
82 "Creative ZEN Vision W";
83 static const char tl_zm_key
[] = "1sN0TM3D az u~may th1nk*"
85 static const char tl_zmp_key
[] = "1sN0TM3D az u~may th1nk*"
86 "Creative Zen MicroPhoto";
87 static const char tl_zs_key
[] = "1sN0TM3D az u~may th1nk*"
89 static const char tl_zsp_key
[] = "1sN0TM3D az u~may th1nk*"
90 "Creative Zen Sleek Photo";
91 static const char tl_zt_key
[] = "1sN0TM3D az u~may th1nk*"
93 static const char tl_zx_key
[] = "1sN0TM3D az u~may th1nk*"
94 "NOMAD Jukebox Zen Xtra";
95 static const char tl_zenv_key
[] = "1sN0TM3D az u~may th1nk*"
97 static const char tl_zenvp_key
[] = "1sN0TM3D az u~may th1nk*"
98 "Creative ZEN V Plus";
99 static const char tl_zenvv_key
[] = "1sN0TM3D az u~may th1nk*"
100 "Creative ZEN V (Video)";
102 player_info_t players
[] = {
103 {"Zen Vision:M", null_key_v2
, fresc_key_v1
, tl_zvm_key
, false},
104 {"Zen Vision:M 60GB", null_key_v2
, fresc_key_v1
, tl_zvm60_key
, false},
105 {"ZEN", null_key_v4
, fresc_key_v2
, tl_zen_key
, false},
106 {"ZEN X-Fi", null_key_v4
, fresc_key_v2
, tl_zenxf_key
, false},
107 {"ZEN Mozaic", null_key_v4
, fresc_key_v2
, tl_zenmo_key
, false},
108 {"Zen Vision", null_key_v2
, fresc_key_v1
, tl_zv_key
, false},
109 {"Zen Vision W", null_key_v2
, fresc_key_v1
, tl_zvw_key
, false},
110 {"Zen Micro", null_key_v1
, fresc_key_v1
, tl_zm_key
, true},
111 {"Zen MicroPhoto", null_key_v1
, fresc_key_v1
, tl_zmp_key
, true},
112 {"Zen Sleek", null_key_v1
, fresc_key_v1
, tl_zs_key
, true},
113 {"Zen SleekPhoto", null_key_v1
, fresc_key_v1
, tl_zsp_key
, true},
114 {"Zen Touch", null_key_v1
, fresc_key_v1
, tl_zt_key
, true},
115 {"Zen Xtra", null_key_v1
, fresc_key_v1
, tl_zx_key
, true},
116 {"Zen V", null_key_v3
, fresc_key_v1
, tl_zenv_key
, false},
117 {"Zen V Plus", null_key_v3
, fresc_key_v1
, tl_zenvp_key
, false},
118 {"Zen V Video", null_key_v3
, fresc_key_v1
, tl_zenvv_key
, false},
119 {NULL
, NULL
, NULL
, NULL
, false}
123 player_info_t
* find_player_info(std::string player
)
125 for (int i
= 0; players
[i
].name
!= NULL
; i
++)
127 if (!strcasecmp(players
[i
].name
, player
.c_str()))
138 << "zen_crypt - A utility for encrypting, decrypting or signing"
139 " Creative firmwares." << std::endl
140 << "Version " << VERSION
<< std::endl
141 << "Copyright (c) 2007 Rasmus Ry" << std::endl
;
147 std::cout
<< std::endl
148 << "Usage: zen_crypt [command] [options]" << std::endl
150 << " Commands:" << std::endl
151 << " -h,--help" << std::endl
152 << " prints this message." << std::endl
153 << " -s,--sign" << std::endl
154 << " signs a given input file." << std::endl
155 << " -v,--verify" << std::endl
156 << " verifies a signed input file." << std::endl
157 << " -e,--encrypt" << std::endl
158 << " encrypts a given input file." << std::endl
159 << " -d,--decrypt" << std::endl
160 << " decrypts a given input file." << std::endl
162 << " Options:" << std::endl
163 << " -V,--verbose" << std::endl
164 << " prints verbose messages." << std::endl
165 << " -b,--big-endian" << std::endl
166 << " specifies that the input is big-endian, default is"
167 " little-endian." << std::endl
168 << " -i,--input [file]" << std::endl
169 << " specifies the input file." << std::endl
170 << " -o,--output [file]" << std::endl
171 << " specifies the output file." << std::endl
172 << " -m,--mode [CENC|FRESC|TL]" << std::endl
173 << " specifies which algorithm to use." << std::endl
174 << " -k,--key [player|key]" << std::endl
175 << " specifies which key to use." << std::endl
178 std::cout
<< " Players:" << std::endl
;
179 for (int i
= 0; players
[i
].name
!= NULL
; i
++)
181 std::cout
<< " " << players
[i
].name
;
183 std::cout
<< " (default)";
184 std::cout
<< std::endl
;
188 size_t find_null_signature(shared::bytes
& data
)
190 size_t index
= data
.size();
191 if (index
< (20 + 8 + 7))
194 for (int i
= 0; i
< 7; i
++)
196 if (*(dword
*)&data
[index
-i
] == 'NULL' ||
197 *(dword
*)&data
[index
-i
] == 'LLUN')
206 bool sign(shared::bytes
& data
, player_info_t
* pi
, const std::string
& file
,
210 std::cout
<< "[*] Checking for the presence of an existing"
211 " NULL signature..." << std::endl
;
212 size_t index
= find_null_signature(data
);
216 std::cout
<< "[*] Found NULL signature at: 0x"
217 << std::hex
<< index
<< std::endl
;
220 std::cout
<< "[*] Computing digest..." << std::endl
;
222 shared::bytes
digest(20);
223 if (!zen::hmac_sha1_calc((const byte
*)pi
->null_key
,
224 strlen(pi
->null_key
)+1, &data
[0], index
,
227 std::cerr
<< "Failed to compute digest." << std::endl
;
232 std::cout
<< "[*] Writing file data..." << std::endl
;
234 if (!shared::write_file(file
, data
, true))
236 std::cerr
<< "Failed to write file data." << std::endl
;
241 std::cout
<< "[*] Writing digest data..." << std::endl
;
243 if (!shared::write_file(file
, digest
, false, index
+8))
245 std::cerr
<< "Failed to write digest data." << std::endl
;
252 std::cout
<< "[*] Computing digest..." << std::endl
;
254 shared::bytes
signature(20+8);
255 if (!zen::hmac_sha1_calc((const byte
*)pi
->null_key
,
256 strlen(pi
->null_key
)+1, &data
[0], data
.size(),
257 &signature
[8], NULL
))
259 std::cerr
<< "Failed to compute digest." << std::endl
;
264 zen::firmware_header_t header
= {'NULL', 20};
267 header
.tag
= shared::swap(header
.tag
);
268 header
.size
= shared::swap(header
.size
);
270 memcpy(&signature
[0], &header
, sizeof(zen::firmware_header_t
));
273 std::cout
<< "[*] Writing file data..." << std::endl
;
275 if (!shared::write_file(file
, data
, true))
277 std::cerr
<< "Failed to write file data." << std::endl
;
282 std::cout
<< "[*] Writing signature data..." << std::endl
;
284 if (!shared::write_file(file
, signature
, false, data
.size()))
286 std::cerr
<< "Failed to write signature data." << std::endl
;
291 std::cout
<< "[*] Ensuring that the file length is"
292 " 32-bit aligned..." << std::endl
;
294 int length
= data
.size() + signature
.size();
295 int align
= length
% 4;
298 shared::bytes
padding(4 - align
, 0);
299 if (!shared::write_file(file
, padding
, false, length
))
301 std::cerr
<< "Failed to write padding data." << std::endl
;
310 bool verify(shared::bytes
& data
, player_info_t
* pi
, bool verbose
)
313 std::cout
<< "[*] Checking for the presence of an existing"
314 " NULL signature..." << std::endl
;
315 size_t index
= find_null_signature(data
);
318 std::cerr
<< "No NULL signature present in the input file."
323 std::cout
<< "[*] Found NULL signature at: 0x"
324 << std::hex
<< index
<< std::endl
;
327 std::cout
<< "[*] Computing digest..." << std::endl
;
330 if (!zen::hmac_sha1_calc((const byte
*)pi
->null_key
, strlen(pi
->null_key
)+1,
331 &data
[0], index
, digest
, NULL
))
333 std::cerr
<< "Failed to compute digest." << std::endl
;
338 std::cout
<< "[*] Verifying NULL signature digest..." << std::endl
;
340 if (memcmp(&digest
[0], &data
[index
+8], 20))
342 std::cerr
<< "The NULL signature contains an incorrect digest."
350 bool encrypt(shared::bytes
& data
, int mode
, player_info_t
* pi
,
351 const std::string
& file
, bool verbose
)
353 if (mode
== mode_cenc
)
356 std::cout
<< "[*] Encoding input file..." << std::endl
;
358 shared::bytes
outbuf(data
.size() * 2);
359 int len
= zen::cenc_encode(&data
[0], data
.size(), &outbuf
[0], outbuf
.size());
362 std::cerr
<< "Failed to encode the input file." << std::endl
;
367 std::cout
<< "[*] Writing decoded length to file..." << std::endl
;
369 shared::bytes
length(sizeof(dword
));
370 *(dword
*)&length
[0] = pi
->big_endian
? shared::swap(data
.size()) : data
.size();
371 if (!shared::write_file(file
, length
, true))
373 std::cerr
<< "Failed to write the file data." << std::endl
;
378 std::cout
<< "[*] Writing file data..." << std::endl
;
380 if (!shared::write_file(file
, outbuf
, sizeof(dword
), len
))
382 std::cerr
<< "Failed to write the file data." << std::endl
;
386 else if (mode
== mode_fresc
)
389 std::cout
<< "[*] Encrypting input file..." << std::endl
;
391 dword iv
[2] = {shared::swap(data
.size()), 0};
392 if (!zen::bf_cbc_encrypt((const byte
*)pi
->fresc_key
,
393 strlen(pi
->fresc_key
)+1, &data
[0],
394 data
.size(), (const byte
*)iv
))
396 std::cerr
<< "Failed to encrypt the input file." << std::endl
;
401 std::cout
<< "[*] Writing file data..." << std::endl
;
403 if (!shared::write_file(file
, data
, true))
405 std::cerr
<< "Failed to save the output file." << std::endl
;
409 else if (mode
== mode_tl
)
412 std::cout
<< "[*] Encoding input file..." << std::endl
;
414 shared::bytes
outbuf(data
.size() * 2);
415 *(dword
*)&outbuf
[0] = pi
->big_endian
? shared::swap(data
.size()) : data
.size();
416 int len
= zen::cenc_encode(&data
[0], data
.size(),
417 &outbuf
[sizeof(dword
)],
418 outbuf
.size()-sizeof(dword
));
421 std::cerr
<< "Failed to encode the input file." << std::endl
;
424 len
+= sizeof(dword
);
427 align
= align
? (8 - align
) : 0;
431 std::cout
<< "[*] Encrypting encoded data..." << std::endl
;
433 dword iv
[2] = {0, shared::swap(len
)};
434 if (!zen::bf_cbc_encrypt((const byte
*)pi
->tl_key
, strlen(pi
->tl_key
)+1,
435 &outbuf
[0], len
, (const byte
*)iv
))
437 std::cerr
<< "Failed to encrypt the input file." << std::endl
;
442 std::cout
<< "[*] Writing file data..." << std::endl
;
444 if (!shared::write_file(file
, outbuf
, true, 0, len
))
446 std::cerr
<< "Failed to save the output file." << std::endl
;
452 std::cerr
<< "Invalid mode specified." << std::endl
;
459 bool decrypt(shared::bytes
& data
, int mode
, player_info_t
* pi
,
460 const std::string
& file
, bool verbose
)
462 if (mode
== mode_cenc
)
464 dword length
= *(dword
*)&data
[0];
465 length
= pi
->big_endian
? shared::swap(length
) : length
;
468 std::cout
<< "[*] Decoding input file..." << std::endl
;
470 shared::bytes
outbuf(length
);
471 if (!zen::cenc_decode(&data
[sizeof(dword
)], data
.size()-sizeof(dword
),
474 std::cerr
<< "Failed to decode the input file." << std::endl
;
479 std::cout
<< "[*] Writing file data..." << std::endl
;
481 if (!shared::write_file(file
, outbuf
, true))
483 std::cerr
<< "Failed to write the file data." << std::endl
;
487 else if (mode
== mode_fresc
)
490 std::cout
<< "[*] Decrypting input file..." << std::endl
;
492 dword iv
[2] = {shared::swap(data
.size()), 0};
493 if (!zen::bf_cbc_decrypt((const byte
*)pi
->fresc_key
,
494 strlen(pi
->fresc_key
)+1, &data
[0],
495 data
.size(), (const byte
*)iv
))
497 std::cerr
<< "Failed to decrypt the input file." << std::endl
;
501 if (*(dword
*)&data
[0] != 'EDOC' &&
502 *(dword
*)&data
[0] != 'CODE')
504 std::cerr
<< "Failed to decode the input file." << std::endl
;
509 std::cout
<< "[*] Writing file data..." << std::endl
;
511 if (!shared::write_file(file
, data
, true))
513 std::cerr
<< "Failed to save the output file." << std::endl
;
517 else if (mode
== mode_tl
)
520 std::cout
<< "[*] Decrypting input file..." << std::endl
;
522 dword iv
[2] = {0, shared::swap(data
.size())};
523 if (!zen::bf_cbc_decrypt((const byte
*)pi
->tl_key
, strlen(pi
->tl_key
)+1,
524 &data
[0], data
.size(), (const byte
*)iv
))
526 std::cerr
<< "Failed to decrypt the input file." << std::endl
;
530 dword length
= *(dword
*)&data
[0];
531 length
= pi
->big_endian
? shared::swap(length
) : length
;
532 if (length
> (data
.size() * 3))
534 std::cerr
<< "Decrypted length is unexpectedly large: "
535 << std::hex
<< length
536 << " Check the endian and key settings." << std::endl
;
541 std::cout
<< "[*] Decoding decrypted data..." << std::endl
;
543 shared::bytes
outbuf(length
);
544 if (!zen::cenc_decode(&data
[sizeof(dword
)], data
.size()-sizeof(dword
),
547 std::cerr
<< "Failed to decode the input file." << std::endl
;
552 std::cout
<< "[*] Writing file data..." << std::endl
;
554 if (!shared::write_file(file
, outbuf
, true))
556 std::cerr
<< "Failed to save the output file." << std::endl
;
562 std::cerr
<< "Invalid mode specified." << std::endl
;
569 int process_arguments(int argc
, char*argv
[])
572 --------------------------------------------------------------------
573 Parse input variables.
574 --------------------------------------------------------------------
577 GetPot
cl(argc
, argv
);
578 if (cl
.size() == 1 || cl
.search(2, "-h", "--help"))
584 int command
= cmd_none
;
585 if (cl
.search(2, "-s", "--sign"))
587 else if (cl
.search(2, "-v", "--verify"))
588 command
= cmd_verify
;
589 else if (cl
.search(2, "-e", "--encrypt"))
590 command
= cmd_encrypt
;
591 else if (cl
.search(2, "-d", "--decrypt"))
592 command
= cmd_decrypt
;
594 if (command
== cmd_none
)
596 std::cerr
<< "No command specified." << std::endl
;
600 int mode
= mode_none
;
601 if (command
== cmd_encrypt
|| command
== cmd_decrypt
)
603 if (!cl
.search(2, "-m", "--mode"))
605 std::cerr
<< "The specified command requires that"
606 " a mode is specified."
610 std::string name
= cl
.next("");
613 if (!strcasecmp(name
.c_str(), "CENC"))
615 else if (!strcasecmp(name
.c_str(), "FRESC"))
617 else if (!strcasecmp(name
.c_str(), "TL"))
620 if (mode
== mode_none
)
622 std::cerr
<< "Invalid mode specified." << std::endl
;
627 bool verbose
= false;
628 if (cl
.search(2, "-V", "--verbose"))
631 bool big_endian
= false;
632 if (cl
.search(2, "-b", "--big-endian"))
636 if (cl
.search(2, "-i", "--input"))
637 infile
= cl
.next("");
640 std::cerr
<< "An input file must be specified." << std::endl
;
644 std::string outfile
= infile
;
645 if (cl
.search(2, "-o", "--output"))
646 outfile
= cl
.next(outfile
.c_str());
648 player_info_t
* pi
= &players
[0];
650 if (cl
.search(2, "-k", "--key"))
654 player_info_t
* pitmp
= find_player_info(key
);
659 static player_info_t player
= {
660 NULL
, key
.c_str(), key
.c_str(), key
.c_str(), false
666 pi
->big_endian
= big_endian
;
670 --------------------------------------------------------------------
672 --------------------------------------------------------------------
676 std::cout
<< "[*] Reading input file..." << std::endl
;
678 shared::bytes buffer
;
679 if (!shared::read_file(infile
, buffer
))
681 std::cerr
<< "Failed to read the input file." << std::endl
;
687 --------------------------------------------------------------------
688 Process the input file.
689 --------------------------------------------------------------------
696 std::cout
<< "[*] Signing input file..." << std::endl
;
697 if (!sign(buffer
, pi
, outfile
, verbose
))
699 std::cout
<< "Successfully signed the input file." << std::endl
;
703 std::cout
<< "[*] Verifying signature on input file..."
705 if (!verify(buffer
, pi
, verbose
))
707 std::cout
<< "Successfully verified the input file signature."
712 std::cout
<< "[*] Encrypting input file..." << std::endl
;
713 if (!encrypt(buffer
, mode
, pi
, outfile
, verbose
))
715 std::cout
<< "Successfully encrypted the input file." << std::endl
;
719 std::cout
<< "[*] Decrypting input file..." << std::endl
;
720 if (!decrypt(buffer
, mode
, pi
, outfile
, verbose
))
722 std::cout
<< "Successfully decrypted the input file." << std::endl
;
729 int main(int argc
, char* argv
[])
733 return process_arguments(argc
, argv
);
735 catch (const std::exception
& xcpt
)
737 std::cerr
<< "Exception caught: " << xcpt
.what() << std::endl
;
742 std::cerr
<< "Unknown exception caught." << std::endl
;