summaryrefslogtreecommitdiff
path: root/utils/zenutils/source/zen_crypt
diff options
context:
space:
mode:
Diffstat (limited to 'utils/zenutils/source/zen_crypt')
-rwxr-xr-xutils/zenutils/source/zen_crypt/CMakeLists.txt4
-rwxr-xr-xutils/zenutils/source/zen_crypt/main.cpp687
2 files changed, 691 insertions, 0 deletions
diff --git a/utils/zenutils/source/zen_crypt/CMakeLists.txt b/utils/zenutils/source/zen_crypt/CMakeLists.txt
new file mode 100755
index 0000000000..e88e8951a5
--- /dev/null
+++ b/utils/zenutils/source/zen_crypt/CMakeLists.txt
@@ -0,0 +1,4 @@
1ADD_EXECUTABLE(zen_crypt main.cpp)
2
3TARGET_LINK_LIBRARIES(zen_crypt shared)
4TARGET_LINK_LIBRARIES(zen_crypt beecrypt)
diff --git a/utils/zenutils/source/zen_crypt/main.cpp b/utils/zenutils/source/zen_crypt/main.cpp
new file mode 100755
index 0000000000..8301cbbea5
--- /dev/null
+++ b/utils/zenutils/source/zen_crypt/main.cpp
@@ -0,0 +1,687 @@
1/* zenutils - Utilities for working with creative firmwares.
2 * Copyright 2007 (c) Rasmus Ry <rasmus.ry{at}gmail.com>
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include <iostream>
20#include <getpot/getpot.hpp>
21#include <cenc.h>
22#include <crypt.h>
23#include <file.h>
24#include <firmware.h>
25#include <utils.h>
26
27
28namespace {
29enum command_t
30{
31 cmd_none = 0,
32 cmd_sign,
33 cmd_verify,
34 cmd_encrypt,
35 cmd_decrypt
36};
37
38enum mode_t
39{
40 mode_none = 0,
41 mode_cenc,
42 mode_fresc,
43 mode_tl
44};
45
46struct player_info_t
47{
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;
53};
54}; //namespace
55
56
57static const char VERSION[] = "0.1";
58
59static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN.";
60static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP.";
61
62static const char fresc_key[] = "Copyright (C) CTL. -"
63 " zN0MAD iz v~p0wderful!";
64
65static const char tl_zvm_key[] = "1sN0TM3D az u~may th1nk*"
66 "Creative Zen Vision:M";
67static const char tl_zvw_key[] = "1sN0TM3D az u~may th1nk*"
68 "Creative ZEN Vision W";
69static const char tl_zm_key[] = "1sN0TM3D az u~may th1nk*"
70 "Creative Zen Micro";
71static const char tl_zmp_key[] = "1sN0TM3D az u~may th1nk*"
72 "Creative Zen MicroPhoto";
73static const char tl_zs_key[] = "1sN0TM3D az u~may th1nk*"
74 "Creative Zen Sleek";
75static const char tl_zsp_key[] = "1sN0TM3D az u~may th1nk*"
76 "Creative Zen Sleek Photo";
77static const char tl_zt_key[] = "1sN0TM3D az u~may th1nk*"
78 "Creative Zen Touch";
79static const char tl_zx_key[] = "1sN0TM3D az u~may th1nk*"
80 "NOMAD Jukebox Zen Xtra";
81
82player_info_t players[] = {
83 {"Vision:M", null_key_v2, fresc_key, tl_zvm_key, false},
84 {"Vision W", null_key_v2, fresc_key, tl_zvw_key, false},
85 {"Micro", null_key_v1, fresc_key, tl_zm_key, true},
86 {"MicroPhoto", null_key_v1, fresc_key, tl_zmp_key, true},
87 {"Sleek", null_key_v1, fresc_key, tl_zs_key, true},
88 {"SleekPhoto", null_key_v1, fresc_key, tl_zsp_key, true},
89 {"Touch", null_key_v1, fresc_key, tl_zt_key, true},
90 {"Xtra", null_key_v1, fresc_key, tl_zx_key, true},
91 {NULL, NULL, NULL, NULL, false}
92};
93
94
95player_info_t* find_player_info(std::string player)
96{
97 for (int i = 0; players[i].name != NULL; i++)
98 {
99 if (!stricmp(players[i].name, player.c_str()))
100 {
101 return &players[i];
102 }
103 }
104 return NULL;
105}
106
107void print_version()
108{
109 std::cout
110 << "zen_crypt - A utility for encrypting, decrypting or signing"
111 " Creative firmwares." << std::endl
112 << "Version " << VERSION << std::endl
113 << "Copyright (c) 2007 Rasmus Ry" << std::endl;
114}
115
116void print_help()
117{
118 print_version();
119 std::cout << std::endl
120 << "Usage: zen_crypt [command] [options]" << std::endl
121 << std::endl
122 << " Commands:" << std::endl
123 << " -h,--help" << std::endl
124 << " prints this message." << std::endl
125 << " -s,--sign" << std::endl
126 << " signs a given input file." << std::endl
127 << " -v,--verify" << std::endl
128 << " verifies a signed input file." << std::endl
129 << " -e,--encrypt" << std::endl
130 << " encrypts a given input file." << std::endl
131 << " -d,--decrypt" << std::endl
132 << " decrypts a given input file." << std::endl
133 << std::endl
134 << " Options:" << std::endl
135 << " -V,--verbose" << std::endl
136 << " prints verbose messages." << std::endl
137 << " -b,--big-endian" << std::endl
138 << " specifies that the input is big-endian, default is"
139 " little-endian." << std::endl
140 << " -i,--input [file]" << std::endl
141 << " specifies the input file." << std::endl
142 << " -o,--output [file]" << std::endl
143 << " specifies the output file." << std::endl
144 << " -m,--mode [CENC|FRESC|TL]" << std::endl
145 << " specifies which algorithm to use." << std::endl
146 << " -k,--key [player|key]" << std::endl
147 << " specifies which key to use." << std::endl
148 << std::endl
149 ;
150 std::cout << " Players:" << std::endl;
151 for (int i = 0; players[i].name != NULL; i++)
152 {
153 std::cout << " " << players[i].name;
154 if (!i)
155 std::cout << " (default)";
156 std::cout << std::endl;
157 }
158}
159
160size_t find_null_signature(shared::bytes& data)
161{
162 size_t index = data.size();
163 if (index < (20 + 8 + 7))
164 return 0;
165 index -= 20 + 8;
166 for (int i = 0; i < 7; i++)
167 {
168 if (*(dword*)&data[index-i] == 'NULL' ||
169 *(dword*)&data[index-i] == 'LLUN')
170 {
171 return index-i;
172 }
173 }
174 return 0;
175}
176
177
178bool sign(shared::bytes& data, player_info_t* pi, const std::string& file,
179 bool verbose)
180{
181 if (verbose)
182 std::cout << "[*] Checking for the presence of an existing"
183 " NULL signature..." << std::endl;
184 size_t index = find_null_signature(data);
185 if (index)
186 {
187 if (verbose)
188 std::cout << "[*] Found NULL signature at: "
189 << std::hex << index << std::endl;
190
191 if (verbose)
192 std::cout << "[*] Computing digest..." << std::endl;
193
194 shared::bytes digest(20);
195 if (!zen::hmac_sha1_calc((const byte*)pi->null_key,
196 strlen(pi->null_key)+1, &data[0], index,
197 &digest[0], NULL))
198 {
199 std::cerr << "Failed to compute digest." << std::endl;
200 return false;
201 }
202
203 if (verbose)
204 std::cout << "[*] Writing file data..." << std::endl;
205
206 if (!shared::write_file(file, data, true))
207 {
208 std::cerr << "Failed to write file data." << std::endl;
209 return false;
210 }
211
212 if (verbose)
213 std::cout << "[*] Writing digest data..." << std::endl;
214
215 if (!shared::write_file(file, digest, false, index+8))
216 {
217 std::cerr << "Failed to write digest data." << std::endl;
218 return false;
219 }
220 }
221 else
222 {
223 if (verbose)
224 std::cout << "[*] Computing digest..." << std::endl;
225
226 shared::bytes signature(20+8);
227 if (!zen::hmac_sha1_calc((const byte*)pi->null_key,
228 strlen(pi->null_key)+1, &data[0], data.size(),
229 &signature[8], NULL))
230 {
231 std::cerr << "Failed to compute digest." << std::endl;
232 return false;
233 }
234
235
236 zen::firmware_header_t header = {'NULL', 20};
237 if (pi->big_endian)
238 {
239 header.tag = shared::swap(header.tag);
240 header.size = shared::swap(header.size);
241 }
242 memcpy(&signature[0], &header, sizeof(zen::firmware_header_t));
243
244 if (verbose)
245 std::cout << "[*] Writing file data..." << std::endl;
246
247 if (!shared::write_file(file, data, true))
248 {
249 std::cerr << "Failed to write file data." << std::endl;
250 return false;
251 }
252
253 if (verbose)
254 std::cout << "[*] Writing signature data..." << std::endl;
255
256 if (!shared::write_file(file, signature, false, data.size()))
257 {
258 std::cerr << "Failed to write signature data." << std::endl;
259 return false;
260 }
261
262 if (verbose)
263 std::cout << "[*] Ensuring that the file length is"
264 " 32-bit aligned..." << std::endl;
265
266 int length = data.size() + signature.size();
267 int align = length % 4;
268 if (align)
269 {
270 shared::bytes padding(4 - align, 0);
271 if (!shared::write_file(file, padding, false, length))
272 {
273 std::cerr << "Failed to write padding data." << std::endl;
274 return false;
275 }
276 }
277 }
278
279 return true;
280}
281
282bool verify(shared::bytes& data, player_info_t* pi, bool verbose)
283{
284 if (verbose)
285 std::cout << "[*] Checking for the presence of an existing"
286 " NULL signature..." << std::endl;
287 size_t index = find_null_signature(data);
288 if (!index)
289 {
290 std::cerr << "No NULL signature present in the input file."
291 << std::endl;
292 return false;
293 }
294 if (verbose)
295 std::cout << "[*] Found NULL signature at: "
296 << std::hex << index << std::endl;
297
298 if (verbose)
299 std::cout << "[*] Computing digest..." << std::endl;
300
301 byte digest[20];
302 if (!zen::hmac_sha1_calc((const byte*)pi->null_key, strlen(pi->null_key)+1,
303 &data[0], index, digest, NULL))
304 {
305 std::cerr << "Failed to compute digest." << std::endl;
306 return false;
307 }
308
309 if (verbose)
310 std::cout << "[*] Verifying NULL signature digest..." << std::endl;
311
312 if (memcmp(&digest[0], &data[index+8], 20))
313 {
314 std::cerr << "The NULL signature contains an incorrect digest."
315 << std::endl;
316 return false;
317 }
318
319 return true;
320}
321
322bool encrypt(shared::bytes& data, int mode, player_info_t* pi,
323 const std::string& file, bool verbose)
324{
325 if (mode == mode_cenc)
326 {
327 if (verbose)
328 std::cout << "[*] Encoding input file..." << std::endl;
329
330 shared::bytes outbuf(data.size() * 2);
331 int len = zen::cenc_encode(&data[0], data.size(), &outbuf[0], outbuf.size());
332 if (!len)
333 {
334 std::cerr << "Failed to encode the input file." << std::endl;
335 return false;
336 }
337
338 if (verbose)
339 std::cout << "[*] Writing decoded length to file..." << std::endl;
340
341 shared::bytes length(sizeof(dword));
342 *(dword*)&length[0] = pi->big_endian ? shared::swap(data.size()) : data.size();
343 if (!shared::write_file(file, length, true))
344 {
345 std::cerr << "Failed to write the file data." << std::endl;
346 return false;
347 }
348
349 if (verbose)
350 std::cout << "[*] Writing file data..." << std::endl;
351
352 if (!shared::write_file(file, outbuf, sizeof(dword), len))
353 {
354 std::cerr << "Failed to write the file data." << std::endl;
355 return false;
356 }
357 }
358 else if (mode == mode_fresc)
359 {
360 std::cerr << "FRESC mode is not supported." << std::endl;
361 return false;
362 }
363 else if (mode == mode_tl)
364 {
365 if (verbose)
366 std::cout << "[*] Encoding input file..." << std::endl;
367
368 shared::bytes outbuf(data.size() * 2);
369 *(dword*)&outbuf[0] = pi->big_endian ? shared::swap(data.size()) : data.size();
370 int len = zen::cenc_encode(&data[0], data.size(),
371 &outbuf[sizeof(dword)],
372 outbuf.size()-sizeof(dword));
373 if (!len)
374 {
375 std::cerr << "Failed to encode the input file." << std::endl;
376 return false;
377 }
378 len += sizeof(dword);
379
380 int align = len % 8;
381 align = align ? (8 - align) : 0;
382 len += align;
383
384 if (verbose)
385 std::cout << "[*] Encrypting encoded data..." << std::endl;
386
387 dword iv[2] = {0, shared::swap(len)};
388 if (!zen::bf_cbc_encrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1,
389 &outbuf[0], len, (const byte*)iv))
390 {
391 std::cerr << "Failed to decrypt the input file." << std::endl;
392 return false;
393 }
394
395 if (verbose)
396 std::cout << "[*] Writing file data..." << std::endl;
397
398 if (!shared::write_file(file, outbuf, true, 0, len))
399 {
400 std::cerr << "Failed to save the output file." << std::endl;
401 return false;
402 }
403 }
404 else
405 {
406 std::cerr << "Invalid mode specified." << std::endl;
407 return false;
408 }
409
410 return true;
411}
412
413bool decrypt(shared::bytes& data, int mode, player_info_t* pi,
414 const std::string& file, bool verbose)
415{
416 if (mode == mode_cenc)
417 {
418 dword length = *(dword*)&data[0];
419 length = pi->big_endian ? shared::swap(length) : length;
420
421 if (verbose)
422 std::cout << "[*] Decoding input file..." << std::endl;
423
424 shared::bytes outbuf(length);
425 if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword),
426 &outbuf[0], length))
427 {
428 std::cerr << "Failed to decode the input file." << std::endl;
429 return false;
430 }
431
432 if (verbose)
433 std::cout << "[*] Writing file data..." << std::endl;
434
435 if (!shared::write_file(file, outbuf, true))
436 {
437 std::cerr << "Failed to write the file data." << std::endl;
438 return false;
439 }
440 }
441 else if (mode == mode_fresc)
442 {
443 if (verbose)
444 std::cout << "[*] Decrypting input file..." << std::endl;
445
446 dword iv[2] = {shared::swap(data.size()), 0};
447 if (!zen::bf_cbc_decrypt((const byte*)pi->fresc_key,
448 strlen(pi->fresc_key)+1, &data[0],
449 data.size(), (const byte*)iv))
450 {
451 std::cerr << "Failed to decrypt the input file." << std::endl;
452 return false;
453 }
454
455 if (verbose)
456 std::cout << "[*] Writing file data..." << std::endl;
457
458 if (!shared::write_file(file, data, true))
459 {
460 std::cerr << "Failed to save the output file." << std::endl;
461 return false;
462 }
463 }
464 else if (mode == mode_tl)
465 {
466 if (verbose)
467 std::cout << "[*] Decrypting input file..." << std::endl;
468
469 dword iv[2] = {0, shared::swap(data.size())};
470 if (!zen::bf_cbc_decrypt((const byte*)pi->tl_key, strlen(pi->tl_key)+1,
471 &data[0], data.size(), (const byte*)iv))
472 {
473 std::cerr << "Failed to decrypt the input file." << std::endl;
474 return false;
475 }
476
477 dword length = *(dword*)&data[0];
478 length = pi->big_endian ? shared::swap(length) : length;
479 if (length > (data.size() * 3))
480 {
481 std::cerr << "Decrypted length is unexpectedly large: "
482 << std::hex << length
483 << " Check the endian and key settings." << std::endl;
484 return false;
485 }
486
487 if (verbose)
488 std::cout << "[*] Decoding decrypted data..." << std::endl;
489
490 shared::bytes outbuf(length);
491 if (!zen::cenc_decode(&data[sizeof(dword)], data.size()-sizeof(dword),
492 &outbuf[0], length))
493 {
494 std::cerr << "Failed to decode the input file." << std::endl;
495 return false;
496 }
497
498 if (verbose)
499 std::cout << "[*] Writing file data..." << std::endl;
500
501 if (!shared::write_file(file, outbuf, true))
502 {
503 std::cerr << "Failed to save the output file." << std::endl;
504 return false;
505 }
506 }
507 else
508 {
509 std::cerr << "Invalid mode specified." << std::endl;
510 return false;
511 }
512
513 return true;
514}
515
516int process_arguments(int argc, char*argv[])
517{
518 //--------------------------------------------------------------------
519 // Parse input variables.
520 //--------------------------------------------------------------------
521
522 GetPot cl(argc, argv);
523 if (cl.size() == 1 || cl.search(2, "-h", "--help"))
524 {
525 print_help();
526 return 1;
527 }
528
529 int command = cmd_none;
530 if (cl.search(2, "-s", "--sign"))
531 command = cmd_sign;
532 else if (cl.search(2, "-v", "--verify"))
533 command = cmd_verify;
534 else if (cl.search(2, "-e", "--encrypt"))
535 command = cmd_encrypt;
536 else if (cl.search(2, "-d", "--decrypt"))
537 command = cmd_decrypt;
538
539 if (command == cmd_none)
540 {
541 std::cerr << "No command specified." << std::endl;
542 return 2;
543 }
544
545 int mode = mode_none;
546 if (command == cmd_encrypt || command == cmd_decrypt)
547 {
548 if (!cl.search(2, "-m", "--mode"))
549 {
550 std::cerr << "The specified command requires that"
551 " a mode is specified."
552 << std::endl;
553 return 3;
554 }
555 std::string name = cl.next("");
556 if (!name.empty())
557 {
558 if (!stricmp(name.c_str(), "CENC"))
559 mode = mode_cenc;
560 else if (!stricmp(name.c_str(), "FRESC"))
561 mode = mode_fresc;
562 else if (!stricmp(name.c_str(), "TL"))
563 mode = mode_tl;
564 }
565 if (mode == mode_none)
566 {
567 std::cerr << "Invalid mode specified." << std::endl;
568 return 4;
569 }
570 }
571
572 bool verbose = false;
573 if (cl.search(2, "-V", "--verbose"))
574 verbose = true;
575
576 bool big_endian = false;
577 if (cl.search(2, "-b", "--big-endian"))
578 big_endian = true;
579
580 std::string infile;
581 if (cl.search(2, "-i", "--input"))
582 infile = cl.next("");
583 if (infile.empty())
584 {
585 std::cerr << "An input file must be specified." << std::endl;
586 return 5;
587 }
588
589 std::string outfile = infile;
590 if (cl.search(2, "-o", "--output"))
591 outfile = cl.next(outfile.c_str());
592
593 player_info_t* pi = &players[0];
594 std::string key;
595 if (cl.search(2, "-k", "--key"))
596 key = cl.next("");
597 if (!key.empty())
598 {
599 player_info_t* pitmp = find_player_info(key);
600 if (pitmp != NULL)
601 pi = pitmp;
602 else
603 {
604 static player_info_t player = {
605 NULL, key.c_str(), key.c_str(), key.c_str(), false
606 };
607 pi = &player;
608 }
609 }
610 if (big_endian)
611 pi->big_endian = big_endian;
612
613
614 //--------------------------------------------------------------------
615 // Read the input file.
616 //--------------------------------------------------------------------
617
618 if (verbose)
619 std::cout << "[*] Reading input file..." << std::endl;
620
621 shared::bytes buffer;
622 if (!shared::read_file(infile, buffer))
623 {
624 std::cerr << "Failed to read the input file." << std::endl;
625 return 6;
626 }
627
628
629 //--------------------------------------------------------------------
630 // Process the input file.
631 //--------------------------------------------------------------------
632
633 switch (command)
634 {
635 case cmd_sign:
636 if (verbose)
637 std::cout << "[*] Signing input file..." << std::endl;
638 if (!sign(buffer, pi, outfile, verbose))
639 return 7;
640 std::cout << "Successfully signed the input file." << std::endl;
641 break;
642 case cmd_verify:
643 if (verbose)
644 std::cout << "[*] Verifying signature on input file..."
645 << std::endl;
646 if (!verify(buffer, pi, verbose))
647 return 8;
648 std::cout << "Successfully verified the input file signature."
649 << std::endl;
650 break;
651 case cmd_encrypt:
652 if (verbose)
653 std::cout << "[*] Encrypting input file..." << std::endl;
654 if (!encrypt(buffer, mode, pi, outfile, verbose))
655 return 9;
656 std::cout << "Successfully encrypted the input file." << std::endl;
657 break;
658 case cmd_decrypt:
659 if (verbose)
660 std::cout << "[*] Decrypting input file..." << std::endl;
661 if (!decrypt(buffer, mode, pi, outfile, verbose))
662 return 10;
663 std::cout << "Successfully decrypted the input file." << std::endl;
664 break;
665 };
666
667 return 0;
668}
669
670int main(int argc, char* argv[])
671{
672 try
673 {
674 return process_arguments(argc, argv);
675 }
676 catch (const std::exception& xcpt)
677 {
678 std::cerr << "Exception caught: " << xcpt.what() << std::endl;
679 return -1;
680 }
681 catch (...)
682 {
683 std::cerr << "Unknown exception caught." << std::endl;
684 return -2;
685 }
686 return -3;
687}