FS#8961 - Anti-Aliased Fonts.
[kugel-rb/myfork.git] / utils / zenutils / source / zen_crypt / main.cpp
blobf379c8e9a13f4131cca8724ee9b3008998c0764c
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
19 #include <iostream>
20 #include <getpot/GetPot>
21 #include <cenc.h>
22 #include <crypt.h>
23 #include <file.h>
24 #include <firmware.h>
25 #include <utils.h>
28 namespace {
29 enum command_t
31 cmd_none = 0,
32 cmd_sign,
33 cmd_verify,
34 cmd_encrypt,
35 cmd_decrypt
38 enum mode_t
40 mode_none = 0,
41 mode_cenc,
42 mode_fresc,
43 mode_tl
46 struct player_info_t
48 const char* name;
49 const char* null_key; /* HMAC-SHA1 key */
50 const char* fresc_key; /* BlowFish key */
51 const char* tl_key; /* BlowFish key */
52 bool big_endian;
54 }; /* namespace */
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"
72 "VP-HD0004)";
73 static const char tl_zen_key[] = "1sN0TM3D az u~may th1nk*"
74 "Creative ZEN";
75 static const char tl_zenxf_key[] = "1sN0TM3D az u~may th1nk*"
76 "Creative ZEN X-Fi";
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*"
84 "Creative Zen Micro";
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*"
88 "Creative Zen Sleek";
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*"
92 "Creative Zen Touch";
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*"
96 "Creative ZEN V";
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()))
129 return &players[i];
132 return NULL;
135 void print_version()
137 std::cout
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;
144 void print_help()
146 print_version();
147 std::cout << std::endl
148 << "Usage: zen_crypt [command] [options]" << std::endl
149 << 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
161 << 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
176 << std::endl
178 std::cout << " Players:" << std::endl;
179 for (int i = 0; players[i].name != NULL; i++)
181 std::cout << " " << players[i].name;
182 if (!i)
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))
192 return 0;
193 index -= 20 + 8;
194 for (int i = 0; i < 7; i++)
196 if (*(dword*)&data[index-i] == 'NULL' ||
197 *(dword*)&data[index-i] == 'LLUN')
199 return index-i;
202 return 0;
206 bool sign(shared::bytes& data, player_info_t* pi, const std::string& file,
207 bool verbose)
209 if (verbose)
210 std::cout << "[*] Checking for the presence of an existing"
211 " NULL signature..." << std::endl;
212 size_t index = find_null_signature(data);
213 if (index)
215 if (verbose)
216 std::cout << "[*] Found NULL signature at: 0x"
217 << std::hex << index << std::endl;
219 if (verbose)
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,
225 &digest[0], NULL))
227 std::cerr << "Failed to compute digest." << std::endl;
228 return false;
231 if (verbose)
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;
237 return false;
240 if (verbose)
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;
246 return false;
249 else
251 if (verbose)
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;
260 return false;
264 zen::firmware_header_t header = {'NULL', 20};
265 if (pi->big_endian)
267 header.tag = shared::swap(header.tag);
268 header.size = shared::swap(header.size);
270 memcpy(&signature[0], &header, sizeof(zen::firmware_header_t));
272 if (verbose)
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;
278 return false;
281 if (verbose)
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;
287 return false;
290 if (verbose)
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;
296 if (align)
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;
302 return false;
307 return true;
310 bool verify(shared::bytes& data, player_info_t* pi, bool verbose)
312 if (verbose)
313 std::cout << "[*] Checking for the presence of an existing"
314 " NULL signature..." << std::endl;
315 size_t index = find_null_signature(data);
316 if (!index)
318 std::cerr << "No NULL signature present in the input file."
319 << std::endl;
320 return false;
322 if (verbose)
323 std::cout << "[*] Found NULL signature at: 0x"
324 << std::hex << index << std::endl;
326 if (verbose)
327 std::cout << "[*] Computing digest..." << std::endl;
329 byte digest[20];
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;
334 return false;
337 if (verbose)
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."
343 << std::endl;
344 return false;
347 return true;
350 bool encrypt(shared::bytes& data, int mode, player_info_t* pi,
351 const std::string& file, bool verbose)
353 if (mode == mode_cenc)
355 if (verbose)
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());
360 if (!len)
362 std::cerr << "Failed to encode the input file." << std::endl;
363 return false;
366 if (verbose)
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;
374 return false;
377 if (verbose)
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;
383 return false;
386 else if (mode == mode_fresc)
388 if (verbose)
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;
397 return false;
400 if (verbose)
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;
406 return false;
409 else if (mode == mode_tl)
411 if (verbose)
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));
419 if (!len)
421 std::cerr << "Failed to encode the input file." << std::endl;
422 return false;
424 len += sizeof(dword);
426 int align = len % 8;
427 align = align ? (8 - align) : 0;
428 len += align;
430 if (verbose)
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;
438 return false;
441 if (verbose)
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;
447 return false;
450 else
452 std::cerr << "Invalid mode specified." << std::endl;
453 return false;
456 return true;
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;
467 if (verbose)
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),
472 &outbuf[0], length))
474 std::cerr << "Failed to decode the input file." << std::endl;
475 return false;
478 if (verbose)
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;
484 return false;
487 else if (mode == mode_fresc)
489 if (verbose)
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;
498 return false;
501 if (*(dword*)&data[0] != 'EDOC' &&
502 *(dword*)&data[0] != 'CODE')
504 std::cerr << "Failed to decode the input file." << std::endl;
505 return false;
508 if (verbose)
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;
514 return false;
517 else if (mode == mode_tl)
519 if (verbose)
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;
527 return false;
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;
537 return false;
540 if (verbose)
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),
545 &outbuf[0], length))
547 std::cerr << "Failed to decode the input file." << std::endl;
548 return false;
551 if (verbose)
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;
557 return false;
560 else
562 std::cerr << "Invalid mode specified." << std::endl;
563 return false;
566 return true;
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"))
580 print_help();
581 return 1;
584 int command = cmd_none;
585 if (cl.search(2, "-s", "--sign"))
586 command = cmd_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;
597 return 2;
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."
607 << std::endl;
608 return 3;
610 std::string name = cl.next("");
611 if (!name.empty())
613 if (!strcasecmp(name.c_str(), "CENC"))
614 mode = mode_cenc;
615 else if (!strcasecmp(name.c_str(), "FRESC"))
616 mode = mode_fresc;
617 else if (!strcasecmp(name.c_str(), "TL"))
618 mode = mode_tl;
620 if (mode == mode_none)
622 std::cerr << "Invalid mode specified." << std::endl;
623 return 4;
627 bool verbose = false;
628 if (cl.search(2, "-V", "--verbose"))
629 verbose = true;
631 bool big_endian = false;
632 if (cl.search(2, "-b", "--big-endian"))
633 big_endian = true;
635 std::string infile;
636 if (cl.search(2, "-i", "--input"))
637 infile = cl.next("");
638 if (infile.empty())
640 std::cerr << "An input file must be specified." << std::endl;
641 return 5;
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];
649 std::string key;
650 if (cl.search(2, "-k", "--key"))
651 key = cl.next("");
652 if (!key.empty())
654 player_info_t* pitmp = find_player_info(key);
655 if (pitmp != NULL)
656 pi = pitmp;
657 else
659 static player_info_t player = {
660 NULL, key.c_str(), key.c_str(), key.c_str(), false
662 pi = &player;
665 if (big_endian)
666 pi->big_endian = big_endian;
670 --------------------------------------------------------------------
671 Read the input file.
672 --------------------------------------------------------------------
675 if (verbose)
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;
682 return 6;
687 --------------------------------------------------------------------
688 Process the input file.
689 --------------------------------------------------------------------
692 switch (command)
694 case cmd_sign:
695 if (verbose)
696 std::cout << "[*] Signing input file..." << std::endl;
697 if (!sign(buffer, pi, outfile, verbose))
698 return 7;
699 std::cout << "Successfully signed the input file." << std::endl;
700 break;
701 case cmd_verify:
702 if (verbose)
703 std::cout << "[*] Verifying signature on input file..."
704 << std::endl;
705 if (!verify(buffer, pi, verbose))
706 return 8;
707 std::cout << "Successfully verified the input file signature."
708 << std::endl;
709 break;
710 case cmd_encrypt:
711 if (verbose)
712 std::cout << "[*] Encrypting input file..." << std::endl;
713 if (!encrypt(buffer, mode, pi, outfile, verbose))
714 return 9;
715 std::cout << "Successfully encrypted the input file." << std::endl;
716 break;
717 case cmd_decrypt:
718 if (verbose)
719 std::cout << "[*] Decrypting input file..." << std::endl;
720 if (!decrypt(buffer, mode, pi, outfile, verbose))
721 return 10;
722 std::cout << "Successfully decrypted the input file." << std::endl;
723 break;
726 return 0;
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;
738 return -1;
740 catch (...)
742 std::cerr << "Unknown exception caught." << std::endl;
743 return -2;
745 return -3;