summaryrefslogtreecommitdiff
path: root/utils/zenutils/source
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2008-07-11 15:50:46 +0000
committerMaurus Cuelenaere <mcuelenaere@gmail.com>2008-07-11 15:50:46 +0000
commit14c7f45cdae826f88dc539c8c38dd95caf305731 (patch)
tree832da054b7cfb2dc6fd63339af736625f31d21aa /utils/zenutils/source
parent7c84ede3781c27db73403bd6302f320c76a58c8c (diff)
downloadrockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.tar.gz
rockbox-14c7f45cdae826f88dc539c8c38dd95caf305731.zip
Add zook's ZenUtils to SVN
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18010 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/zenutils/source')
-rwxr-xr-xutils/zenutils/source/CMakeLists.txt6
-rwxr-xr-xutils/zenutils/source/firmware_extract/CMakeLists.txt3
-rwxr-xr-xutils/zenutils/source/firmware_extract/main.cpp243
-rwxr-xr-xutils/zenutils/source/firmware_make/CMakeLists.txt3
-rwxr-xr-xutils/zenutils/source/firmware_make/main.cpp261
-rwxr-xr-xutils/zenutils/source/shared/CMakeLists.txt16
-rwxr-xr-xutils/zenutils/source/shared/cenc.cpp333
-rwxr-xr-xutils/zenutils/source/shared/cenc.h29
-rwxr-xr-xutils/zenutils/source/shared/crypt.cpp91
-rwxr-xr-xutils/zenutils/source/shared/crypt.h30
-rwxr-xr-xutils/zenutils/source/shared/file.cpp106
-rwxr-xr-xutils/zenutils/source/shared/file.h36
-rwxr-xr-xutils/zenutils/source/shared/firmware.cpp387
-rwxr-xr-xutils/zenutils/source/shared/firmware.h92
-rwxr-xr-xutils/zenutils/source/shared/pe.cpp128
-rwxr-xr-xutils/zenutils/source/shared/pe.h142
-rwxr-xr-xutils/zenutils/source/shared/shared.cpp0
-rwxr-xr-xutils/zenutils/source/shared/updater.cpp151
-rwxr-xr-xutils/zenutils/source/shared/updater.h32
-rwxr-xr-xutils/zenutils/source/shared/utils.cpp211
-rwxr-xr-xutils/zenutils/source/shared/utils.h68
-rwxr-xr-xutils/zenutils/source/update_extract/CMakeLists.txt3
-rwxr-xr-xutils/zenutils/source/update_extract/main.cpp279
-rwxr-xr-xutils/zenutils/source/update_patch/CMakeLists.txt3
-rwxr-xr-xutils/zenutils/source/update_patch/main.cpp409
-rwxr-xr-xutils/zenutils/source/zen_crypt/CMakeLists.txt4
-rwxr-xr-xutils/zenutils/source/zen_crypt/main.cpp687
27 files changed, 3753 insertions, 0 deletions
diff --git a/utils/zenutils/source/CMakeLists.txt b/utils/zenutils/source/CMakeLists.txt
new file mode 100755
index 0000000000..e3d44fd036
--- /dev/null
+++ b/utils/zenutils/source/CMakeLists.txt
@@ -0,0 +1,6 @@
1ADD_SUBDIRECTORY(firmware_extract)
2ADD_SUBDIRECTORY(firmware_make)
3ADD_SUBDIRECTORY(shared)
4ADD_SUBDIRECTORY(update_extract)
5ADD_SUBDIRECTORY(update_patch)
6ADD_SUBDIRECTORY(zen_crypt)
diff --git a/utils/zenutils/source/firmware_extract/CMakeLists.txt b/utils/zenutils/source/firmware_extract/CMakeLists.txt
new file mode 100755
index 0000000000..3814f03612
--- /dev/null
+++ b/utils/zenutils/source/firmware_extract/CMakeLists.txt
@@ -0,0 +1,3 @@
1ADD_EXECUTABLE(firmware_extract main.cpp)
2
3TARGET_LINK_LIBRARIES(firmware_extract shared)
diff --git a/utils/zenutils/source/firmware_extract/main.cpp b/utils/zenutils/source/firmware_extract/main.cpp
new file mode 100755
index 0000000000..c677a91a75
--- /dev/null
+++ b/utils/zenutils/source/firmware_extract/main.cpp
@@ -0,0 +1,243 @@
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 <ctime>
21#include <getpot/getpot.hpp>
22#include <utils.h>
23#include <firmware.h>
24
25
26static const char VERSION[] = "0.1";
27
28
29void print_version()
30{
31 std::cout
32 << "firmware_extract - Extracts files from a Creative firmware."
33 << std::endl
34 << "Version " << VERSION << std::endl
35 << "Copyright (c) 2007 Rasmus Ry" << std::endl;
36}
37
38void print_help()
39{
40 print_version();
41 std::cout
42 << "Usage: firmware_extract [command] [options]" << std::endl
43 << std::endl
44 << " Commands:" << std::endl
45 << " -h,--help" << std::endl
46 << " prints this message." << std::endl
47 << " -f,--firmware [file]" << std::endl
48 << " specifies the firmware arhive file name." << std::endl
49 << std::endl
50 << " Options:" << std::endl
51 << " -V,--verbose" << std::endl
52 << " prints verbose messages." << std::endl
53 << " -p,--prefix [prefix]" << std::endl
54 << " specifies a file name prefix for the extracted files." << std::endl
55 << std::endl
56 ;
57}
58
59
60struct save_entry_functor
61{
62 save_entry_functor(const std::string& fileprefix)
63 : _fileprefix(fileprefix) {}
64
65 bool operator()(const zen::firmware_entry& entry)
66 {
67 std::string filename = _fileprefix + entry.get_content_name();
68 std::ofstream ofs;
69 ofs.open(filename.c_str(), std::ios::binary);
70 if (!ofs)
71 false;
72
73 size_t off = entry.get_content_offset();
74 std::streamsize size = entry.get_bytes().size() - off;
75 ofs.write((const char*)&entry.get_bytes()[off], size);
76
77 return ofs.good();
78 }
79
80 const std::string& _fileprefix;
81}; //struct save_entry_functor
82
83struct print_entry_functor
84{
85 print_entry_functor(std::ostream& os, const std::string& fileprefix)
86 : _os(os), _fileprefix(fileprefix), num(0) {}
87
88 bool operator()(const zen::firmware_entry& entry)
89 {
90 std::string filename = _fileprefix + entry.get_content_name();
91 if (!num)
92 _os << "[./" << num++ << "]" << std::endl;
93 else
94 _os << "[../" << num++ << "]" << std::endl;
95 _os << "tag = " << entry.get_name() << std::endl;
96
97 if (entry.get_content_offset())
98 _os << "name = " << entry.get_content_name() << std::endl;
99
100 _os << "file = \'" << shared::double_quote(filename) << "\'"
101 << std::endl;
102
103 return _os.good();
104 }
105
106 std::ostream& _os;
107 const std::string& _fileprefix;
108 int num;
109}; //struct print_entry_functor
110
111
112int process_arguments(int argc, char* argv[])
113{
114 //--------------------------------------------------------------------
115 // Parse input variables.
116 //--------------------------------------------------------------------
117
118 GetPot cl(argc, argv);
119 if (cl.size() == 1 || cl.search(2, "-h", "--help"))
120 {
121 print_help();
122 return 1;
123 }
124
125 std::string firmwarename;
126 if (cl.search("-f") || cl.search("--firmware"))
127 firmwarename = cl.next("");
128 if (firmwarename.empty())
129 {
130 std::cerr << "Firmware archive must be specified." << std::endl;
131 return 2;
132 }
133
134 bool verbose = false;
135 if (cl.search("-V") || cl.search("--verbose"))
136 verbose = true;
137
138 std::string prefixname = shared::remove_extension(firmwarename) + "_";
139 if (cl.search("-p") || cl.search("--prefix"))
140 prefixname = cl.next(prefixname.c_str());
141
142
143 //--------------------------------------------------------------------
144 // Read the firmware archive.
145 //--------------------------------------------------------------------
146
147 if (verbose)
148 std::cout << "[*] Reading firmware archive..." << std::endl;
149
150 zen::firmware_archive archive(false);
151 std::ifstream ifs;
152 ifs.open(firmwarename.c_str(), std::ios::binary);
153 if (!ifs)
154 {
155 std::cerr << "Failed to open the firmware archive." << std::endl;
156 return 3;
157 }
158
159 if (!archive.read(ifs))
160 {
161 std::cerr << "Failed to read the firmware archive." << std::endl;
162 return 4;
163 }
164
165
166 //--------------------------------------------------------------------
167 // Generate a make file for the extracted firmware archive.
168 //--------------------------------------------------------------------
169
170 // Get make filename for the given input file.
171 std::string makefile = shared::replace_extension(firmwarename, ".mk");
172
173 if (verbose)
174 std::cout << "[*] Producing make file..." << std::endl;
175
176
177 // Produce make file for the given input file.
178 std::ofstream ofs;
179 ofs.open(makefile.c_str(), std::ios::binary);
180 if (!ofs)
181 {
182 std::cerr << "Failed to create firmware archive make file."
183 << std::endl;
184 return 5;
185 }
186
187 time_t timeval = time(NULL);
188 ofs << "# Make file generated at: " << ctime(&timeval);
189 ofs << "endian = " << (archive.is_big_endian() ? "big" : "little")
190 << std::endl;
191 ofs << "signed = " << (archive.is_signed() ? "true" : "false")
192 << std::endl;
193
194 ofs << "[children]" << std::endl;
195 ofs << "count = " << archive.get_children().size() << std::endl;
196
197 std::for_each(archive.get_children().begin(),
198 archive.get_children().end(),
199 print_entry_functor(ofs, prefixname));
200
201 ofs << "[neighbours]" << std::endl;
202 ofs << "count = " << archive.get_neighbours().size() << std::endl;
203 std::for_each(archive.get_neighbours().begin(),
204 archive.get_neighbours().end(),
205 print_entry_functor(ofs, prefixname));
206
207
208 //--------------------------------------------------------------------
209 // Save firmware entries.
210 //--------------------------------------------------------------------
211
212 if (verbose)
213 std::cout << "[*] Saving firmware entries..." << std::endl;
214
215 std::for_each(archive.get_children().begin(),
216 archive.get_children().end(),
217 save_entry_functor(prefixname));
218
219 std::for_each(archive.get_neighbours().begin(),
220 archive.get_neighbours().end(),
221 save_entry_functor(prefixname));
222
223 return 0;
224}
225
226int main(int argc, char* argv[])
227{
228 try
229 {
230 return process_arguments(argc, argv);
231 }
232 catch (const std::exception& xcpt)
233 {
234 std::cerr << "Exception caught: " << xcpt.what() << std::endl;
235 return -1;
236 }
237 catch (...)
238 {
239 std::cerr << "Unknown exception caught." << std::endl;
240 return -2;
241 }
242 return -3;
243}
diff --git a/utils/zenutils/source/firmware_make/CMakeLists.txt b/utils/zenutils/source/firmware_make/CMakeLists.txt
new file mode 100755
index 0000000000..518a008730
--- /dev/null
+++ b/utils/zenutils/source/firmware_make/CMakeLists.txt
@@ -0,0 +1,3 @@
1ADD_EXECUTABLE(firmware_make main.cpp)
2
3TARGET_LINK_LIBRARIES (firmware_make shared)
diff --git a/utils/zenutils/source/firmware_make/main.cpp b/utils/zenutils/source/firmware_make/main.cpp
new file mode 100755
index 0000000000..b0602b6ffe
--- /dev/null
+++ b/utils/zenutils/source/firmware_make/main.cpp
@@ -0,0 +1,261 @@
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 <sstream>
21#include <getpot/getpot.hpp>
22#include <file.h>
23#include <firmware.h>
24#include <utils.h>
25
26
27static const char VERSION[] = "0.1";
28
29void print_version()
30{
31 std::cout
32 << "firmware_make - Creates a Creative firmware archive." << std::endl
33 << "Version " << VERSION << std::endl
34 << "Copyright (c) 2007 Rasmus Ry" << std::endl;
35}
36
37void print_help()
38{
39 print_version();
40 std::cout << std::endl
41 << "Usage: firmware_make [command] [options]" << std::endl
42 << std::endl
43 << " Commands:" << std::endl
44 << " -h,--help" << std::endl
45 << " prints this message." << std::endl
46 << " -m,--makefile [file]" << std::endl
47 << " specifies the .mk file to build the firmware archive from."
48 << std::endl << std::endl
49 << " Options:" << std::endl
50 << " -V,--verbose" << std::endl
51 << " prints verbose messages." << std::endl
52 << " -f,--firmware [file]" << std::endl
53 << " specifies the output firmware file name" << std::endl
54 << std::endl
55 ;
56}
57
58dword get_tag_value(std::string tag)
59{
60 if (tag[0] == '0' && tag[1] == 'x')
61 {
62 dword val = 0;
63 if (sscanf(tag.c_str(), "0x%08X", &val) == 1)
64 return val;
65 if (sscanf(tag.c_str(), "0x%08x", &val) == 1)
66 return val;
67 }
68 else
69 {
70 return shared::swap(*(dword*)&tag[0]);
71 }
72 return 0;
73}
74
75bool process_child(const GetPot& mkfile, const std::string& root, int index,
76 zen::firmware_entry& entry)
77{
78 std::stringstream sstm;
79 sstm << root << "/" << index;
80 std::string var = sstm.str() + "/tag";
81 std::string tag = mkfile(var.c_str(), "");
82 var = sstm.str() + "/name";
83 std::string name = mkfile(var.c_str(), "");
84 var = sstm.str() + "/file";
85 std::string file = mkfile(var.c_str(), "");
86
87 if (file.empty() || tag.empty())
88 {
89 std::cerr << "Invalid file or tag for var: " << sstm.str()
90 << std::endl;
91 return false;
92 }
93
94 shared::bytes buffer;
95 if (!shared::read_file(file, buffer))
96 {
97 std::cerr << "Failed to read the file: " << file << std::endl;
98 return false;
99 }
100
101 entry.get_bytes().clear();
102 entry.get_header().tag = get_tag_value(tag);
103 size_t contoff = entry.get_content_offset();
104 if (contoff)
105 {
106 entry.get_bytes().resize(contoff, 0);
107 if (!name.empty())
108 {
109 size_t endoff = entry.is_big_endian() ? 1 : 0;
110 for (int i = 0; i < name.size(); ++i)
111 entry.get_bytes()[i * 2 + endoff] = name[i];
112 }
113 }
114 entry.get_bytes().insert(entry.get_bytes().end(), buffer.begin(),
115 buffer.end());
116
117 entry.get_header().size = entry.get_bytes().size();
118
119 return true;
120}
121
122int process_arguments(int argc, char* argv[])
123{
124 //--------------------------------------------------------------------
125 // Parse input variables.
126 //--------------------------------------------------------------------
127
128 GetPot cl(argc, argv);
129 if (cl.size() == 1 || cl.search(2, "-h", "--help"))
130 {
131 print_help();
132 return 1;
133 }
134
135 std::string makefile;
136 if (cl.search("-m") || cl.search("--makefile"))
137 makefile = cl.next("");
138 if (makefile.empty())
139 {
140 std::cerr << "Makefile must be specified." << std::endl;
141 return 2;
142 }
143
144 std::string firmware;
145 if (cl.search("-f") || cl.search("--firmware"))
146 firmware = cl.next("");
147 if (firmware.empty())
148 {
149 std::cerr << "Firmware must be specified." << std::endl;
150 return 3;
151 }
152
153 bool verbose = false;
154 if (cl.search("-V") || cl.search("--verbose"))
155 verbose = true;
156
157 GetPot mkfile(makefile.c_str());
158 if (verbose)
159 mkfile.print();
160
161 bool big_endian;
162 std::string endian = mkfile("endian", "little");
163 if (endian == "little")
164 {
165 big_endian = false;
166 }
167 else if (endian == "big")
168 {
169 big_endian = true;
170 }
171 else
172 {
173 std::cerr << "Invalid value of 'endian'" << std::endl;
174 return 4;
175 }
176
177 zen::firmware_archive archive(big_endian);
178 int childcount = mkfile("children/count", 0);
179 if (!childcount)
180 {
181 std::cerr << "A firmware archive must have at least one child entry."
182 << std::endl;
183 return 5;
184 }
185
186 for (int i = 0; i < childcount; i++)
187 {
188 zen::firmware_entry entry(big_endian);
189 if (!process_child(mkfile, "children", i, entry))
190 {
191 return 6;
192 }
193 archive.get_children().push_back(entry);
194 }
195
196 int neighbourcount = mkfile("neighbours/count", 0);
197 for (int i = 0; i < neighbourcount; i++)
198 {
199 zen::firmware_entry entry(big_endian);
200 if (!process_child(mkfile, "neighbours", i, entry))
201 {
202 return 7;
203 }
204 archive.get_neighbours().push_back(entry);
205 }
206
207 std::ofstream ofs;
208 ofs.open(firmware.c_str(), std::ios::out|std::ios::binary|std::ios::trunc);
209 if (!ofs)
210 {
211 std::cerr << "Failed to create the firmware file." << std::endl;
212 return 8;
213 }
214
215 if (!archive.write(ofs))
216 {
217 std::cerr << "Failed to save the firmware archive." << std::endl;
218 return 9;
219 }
220 ofs.close();
221
222 size_t length = archive.calc_size();
223 if (!length)
224 {
225 std::cerr << "Failed to determine the size of the firmware archive."
226 << std::endl;
227 return 10;
228 }
229
230 int align = length % 4;
231 if (align)
232 {
233 shared::bytes padding(4 - align, 0);
234 if (!shared::write_file(firmware, padding, false, length))
235 {
236 std::cerr << "Failed to write padding data." << std::endl;
237 return 11;
238 }
239 }
240
241 return 0;
242}
243
244int main(int argc, char* argv[])
245{
246 try
247 {
248 return process_arguments(argc, argv);
249 }
250 catch (const std::exception& xcpt)
251 {
252 std::cerr << "Exception caught: " << xcpt.what() << std::endl;
253 return -1;
254 }
255 catch (...)
256 {
257 std::cerr << "Unknown exception caught." << std::endl;
258 return -2;
259 }
260 return -3;
261}
diff --git a/utils/zenutils/source/shared/CMakeLists.txt b/utils/zenutils/source/shared/CMakeLists.txt
new file mode 100755
index 0000000000..2e42dbbe74
--- /dev/null
+++ b/utils/zenutils/source/shared/CMakeLists.txt
@@ -0,0 +1,16 @@
1PROJECT(shared)
2
3# source files for shared
4SET(shared_srcs
5 cenc.cpp
6 crypt.cpp
7 file.cpp
8 firmware.cpp
9 pe.cpp
10 updater.cpp
11 utils.cpp
12)
13
14ADD_LIBRARY(shared ${shared_srcs})
15TARGET_LINK_LIBRARIES(shared pelib)
16TARGET_LINK_LIBRARIES(shared zlib)
diff --git a/utils/zenutils/source/shared/cenc.cpp b/utils/zenutils/source/shared/cenc.cpp
new file mode 100755
index 0000000000..932bee4625
--- /dev/null
+++ b/utils/zenutils/source/shared/cenc.cpp
@@ -0,0 +1,333 @@
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 "cenc.h"
20#include <firmware.h>
21#include <stdexcept>
22
23
24namespace {
25const byte CODE_MASK = 0xC0;
26const byte ARGS_MASK = 0x3F;
27
28const byte REPEAT_CODE = 0x00;
29const byte BLOCK_CODE = 0x40;
30const byte LONG_RUN_CODE = 0x80;
31const byte SHORT_RUN_CODE = 0xC0;
32
33const byte BLOCK_ARGS = 0x1F;
34const byte BLOCK_MODE = 0x20;
35
36
37void decode_run(byte* dst, word len, byte val,
38 int& dstidx)
39{
40 memset(dst + dstidx, val, len);
41 dstidx += len;
42}
43
44void decode_pattern(byte* src, byte* dst,
45 word len, int& srcidx, int& dstidx,
46 bool bdecode, int npasses)
47{
48 for (int i = 0; i < npasses; i++)
49 {
50 if (bdecode)
51 {
52 for (int j = 0; j < len; j++)
53 {
54 word c, d;
55 c = src[srcidx + j];
56 d = (c >> 5) & 7;
57 c = (c << 3) & 0xF8;
58 src[srcidx + j] = static_cast<byte>(c | d);
59 }
60 bdecode = false;
61 }
62 memcpy(dst + dstidx, src + srcidx, len);
63 dstidx += len;
64 }
65 srcidx += len;
66}
67}; //namespace
68
69int zen::cenc_decode(byte* src, int srclen, byte* dst, int dstlen)
70{
71 if (!src || !srclen || !dst || !dstlen)
72 {
73 throw std::invalid_argument("Invalid argument(s).");
74 }
75
76 int i = 0, j = 0;
77 do
78 {
79 word c, d, e;
80 c = src[i++];
81 switch (c & CODE_MASK)
82 {
83 case REPEAT_CODE: // 2 bytes
84 d = src[i++];
85 d = d + 2;
86
87 e = (c & ARGS_MASK) + 2;
88
89 decode_pattern(src, dst, e, i, j, false, d);
90 break;
91
92 case BLOCK_CODE: // 1/2/3 bytes
93 d = c & BLOCK_ARGS;
94 if (!(c & BLOCK_MODE))
95 {
96 e = src[i++];
97 e = (d << 8) + (e + 0x21);
98
99 d = static_cast<word>(i ^ j);
100 }
101 else
102 {
103 e = d + 1;
104
105 d = static_cast<word>(i ^ j);
106 }
107 if (d & 1)
108 {
109 i++;
110 }
111
112 decode_pattern(src, dst, e, i, j, true, 1);
113 break;
114
115 case LONG_RUN_CODE: // 3 bytes
116 d = src[i++];
117 e = ((c & ARGS_MASK) << 8) + (d + 0x42);
118
119 d = src[i++];
120 d = ((d & 7) << 5) | ((d >> 3) & 0x1F);
121
122 decode_run(dst, e, static_cast<byte>(d), j);
123 break;
124
125 case SHORT_RUN_CODE: // 2 bytes
126 d = src[i++];
127 d = ((d & 3) << 6) | ((d >> 2) & 0x3F);
128
129 e = (c & ARGS_MASK) + 2;
130
131 decode_run(dst, e, static_cast<byte>(d), j);
132 break;
133 };
134 } while (i < srclen && j < dstlen);
135
136 return j;
137}
138
139namespace {
140int encode_run(byte* dst, int& dstidx, byte val, int len, int dstlen)
141{
142 if (len < 2)
143 throw std::invalid_argument("Length is too small.");
144
145 int ret = 0;
146 if (len <= 0x41)
147 {
148 if ((dstidx + 2) > dstlen)
149 throw std::runtime_error("Not enough space to store run.");
150
151 dst[dstidx++] = SHORT_RUN_CODE | (((len - 2) & ARGS_MASK));
152 dst[dstidx++] = ((val >> 6) & 3) | ((val & 0x3F) << 2);
153
154 ret = 2;
155 }
156 else if (len <= 0x4041)
157 {
158 if ((dstidx + 3) > dstlen)
159 throw std::runtime_error("Not enough space to store run.");
160
161 byte b1 = (len - 0x42) >> 8;
162 byte b2 = (len - 0x42) & 0xFF;
163
164 dst[dstidx++] = LONG_RUN_CODE | ((b1 & ARGS_MASK));
165 dst[dstidx++] = b2;
166 dst[dstidx++] = ((val >> 5) & 7) | ((val & 0x1F) << 3);
167
168 ret = 3;
169 }
170 else
171 {
172 int long_count = len / 0x4041;
173 int short_len = len % 0x4041;
174 bool toosmall = short_len == 1;
175
176 int run_len = 0x4041;
177 for (int i = 0; i < long_count; i++)
178 {
179 if (toosmall && (i == (long_count-1)))
180 {
181 run_len--;
182 toosmall = false;
183 }
184 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
185 if (!tmp) return 0;
186 ret += tmp;
187 len -= run_len;
188 }
189
190 if (len)
191 {
192 int short_count = len / 0x41;
193 int short_rest = short_count ? (len % 0x41) : 0;
194 toosmall = short_rest == 1;
195
196 run_len = 0x41;
197 for (int i = 0; i < short_count; i++)
198 {
199 if (toosmall && (i == (short_count-1)))
200 {
201 run_len--;
202 toosmall = false;
203 }
204 int tmp = encode_run(dst, dstidx, val, run_len, dstlen);
205 if (!tmp) return 0;
206 ret += tmp;
207 len -= run_len;
208 }
209 int tmp = encode_run(dst, dstidx, val, len, dstlen);
210 if (!tmp) return 0;
211 ret += tmp;
212 len -= len;
213 }
214 }
215
216 return ret;
217}
218
219int encode_block(byte* dst, int& dstidx, byte* src, int& srcidx, int len,
220 int dstlen)
221{
222 if (len < 1)
223 throw std::invalid_argument("Length is too small.");
224
225 int startidx = dstidx;
226 if (len < 0x21)
227 {
228 if ((dstidx + 2 + len) > dstlen)
229 throw std::runtime_error("Not enough space to store block.");
230
231 dst[dstidx++] = BLOCK_CODE | BLOCK_MODE | ((len - 1) & BLOCK_ARGS);
232 if ((dstidx ^ srcidx) & 1)
233 dst[dstidx++] = 0;
234
235 for (int i = 0; i < len; i++)
236 {
237 byte c = src[srcidx++];
238 byte d = (c & 7) << 5;
239 c = (c & 0xF8) >> 3;
240 dst[dstidx++] = c | d;
241 }
242 }
243 else if (len < 0x2021)
244 {
245 if ((dstidx + 3 + len) > dstlen)
246 throw std::runtime_error("Not enough space to store block.");
247
248 dst[dstidx++] = BLOCK_CODE | (((len - 0x21) >> 8) & BLOCK_ARGS);
249 dst[dstidx++] = (len - 0x21) & 0xFF;
250 if ((dstidx ^ srcidx) & 1)
251 dst[dstidx++] = 0;
252
253 for (int i = 0; i < len; i++)
254 {
255 byte c = src[srcidx++];
256 byte d = (c & 7) << 5;
257 c = (c & 0xF8) >> 3;
258 dst[dstidx++] = c | d;
259 }
260 }
261 else
262 {
263 int longblocks = len / 0x2020;
264 int rest = len % 0x2020;
265 for (int i = 0; i < longblocks; i++)
266 {
267 int tmp = encode_block(dst, dstidx, src, srcidx, 0x2020, dstlen);
268 if (!tmp) return 0;
269 }
270 if (rest)
271 {
272 int shortblocks = rest / 0x20;
273 for (int i = 0; i < shortblocks; i++)
274 {
275 int tmp = encode_block(dst, dstidx, src, srcidx, 0x20, dstlen);
276 if (!tmp) return 0;
277 }
278 rest = rest % 0x20;
279 int tmp = encode_block(dst, dstidx, src, srcidx, rest, dstlen);
280 if (!tmp) return 0;
281 }
282 }
283
284 return (dstidx - startidx);
285}
286}; //namespace
287
288int zen::cenc_encode(byte* src, int srclen, byte* dst, int dstlen)
289{
290 if (!src || !srclen || !dst || !dstlen)
291 {
292 throw std::invalid_argument("Invalid argument(s).");
293 }
294
295 int i = 0, j = 0, k = 0;
296 word c, d, e;
297 int runlen = 0;
298 while (i < srclen && j < dstlen)
299 {
300 k = i;
301 c = src[i++];
302 runlen = 1;
303 while (i < srclen && src[i] == c)
304 {
305 runlen++;
306 i++;
307 }
308 if (runlen >= 2)
309 {
310 if (!encode_run(dst, j, c, runlen, dstlen))
311 return 0;
312 }
313 else
314 {
315 runlen = 0;
316 i = k;
317 while (i < (srclen - 1) && (src[i] != src[i + 1]))
318 {
319 runlen++;
320 i++;
321 }
322 if (i == (srclen - 1))
323 {
324 runlen++;
325 i++;
326 }
327 if (!encode_block(dst, j, src, k, runlen, dstlen))
328 return 0;
329 }
330 }
331
332 return j;
333}
diff --git a/utils/zenutils/source/shared/cenc.h b/utils/zenutils/source/shared/cenc.h
new file mode 100755
index 0000000000..12a7c92516
--- /dev/null
+++ b/utils/zenutils/source/shared/cenc.h
@@ -0,0 +1,29 @@
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#ifndef ZEN_CENC_H_INCLUDED
20#define ZEN_CENC_H_INCLUDED
21
22#include <utils.h>
23
24namespace zen {
25 int cenc_decode(byte* src, int srclen, byte* dst, int dstlen);
26 int cenc_encode(byte* src, int srclen, byte* dst, int dstlen);
27}; //namespace zen
28
29#endif //CENC_H_INCLUDED
diff --git a/utils/zenutils/source/shared/crypt.cpp b/utils/zenutils/source/shared/crypt.cpp
new file mode 100755
index 0000000000..9c2d33870c
--- /dev/null
+++ b/utils/zenutils/source/shared/crypt.cpp
@@ -0,0 +1,91 @@
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 "crypt.h"
20#include <stdexcept>
21#include <beecrypt/hmacsha1.h>
22#include <beecrypt/blockmode.h>
23#include <beecrypt/blowfish.h>
24
25
26bool zen::hmac_sha1_calc(const byte* key, size_t keylen, const byte* data,
27 size_t datalen, byte* sig, size_t* siglen)
28{
29 hmacsha1Param param;
30 if (hmacsha1Setup(&param, key, keylen * 8))
31 return false;
32 if (hmacsha1Update(&param, data, datalen))
33 return false;
34 if (hmacsha1Digest(&param, sig))
35 return false;
36 return true;
37}
38
39bool zen::bf_cbc_encrypt(const byte* key, size_t keylen, byte* data,
40 size_t datalen, const byte* iv)
41{
42 if (datalen % blowfish.blocksize)
43 throw std::invalid_argument(
44 "The length must be aligned on a 8 byte boundary.");
45
46 blowfishParam param;
47 if (blowfishSetup(&param, key, keylen * 8, ENCRYPT))
48 return false;
49 if (blowfishSetIV(&param, iv))
50 return false;
51
52 byte* plain = new byte[datalen];
53 memcpy(plain, data, datalen);
54
55 unsigned int nblocks = datalen / blowfish.blocksize;
56 if (blockEncryptCBC(&blowfish, &param, (uint32_t*)data, (uint32_t*)plain,
57 nblocks))
58 {
59 delete [] plain;
60 return false;
61 }
62
63 return true;
64}
65
66bool zen::bf_cbc_decrypt(const byte* key, size_t keylen, byte* data,
67 size_t datalen, const byte* iv)
68{
69 if (datalen % blowfish.blocksize)
70 throw std::invalid_argument(
71 "The length must be aligned on a 8 byte boundary.");
72
73 blowfishParam param;
74 if (blowfishSetup(&param, key, keylen * 8, ENCRYPT))
75 return false;
76 if (blowfishSetIV(&param, iv))
77 return false;
78
79 byte* cipher = new byte[datalen];
80 memcpy(cipher, data, datalen);
81
82 unsigned int nblocks = datalen / blowfish.blocksize;
83 if (blockDecryptCBC(&blowfish, &param, (uint32_t*)data, (uint32_t*)cipher,
84 nblocks))
85 {
86 delete [] cipher;
87 return false;
88 }
89
90 return true;
91}
diff --git a/utils/zenutils/source/shared/crypt.h b/utils/zenutils/source/shared/crypt.h
new file mode 100755
index 0000000000..a057055b70
--- /dev/null
+++ b/utils/zenutils/source/shared/crypt.h
@@ -0,0 +1,30 @@
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#ifndef ZEN_CRYPT_H_INCLUDED
20#define ZEN_CRYPT_H_INCLUDED
21
22#include <utils.h>
23
24namespace zen {
25 bool hmac_sha1_calc(const byte* key, size_t keylen, const byte* data, size_t datalen, byte* sig, size_t* siglen);
26 bool bf_cbc_encrypt(const byte* key, size_t keylen, byte* data, size_t datalen, const byte* iv);
27 bool bf_cbc_decrypt(const byte* key, size_t keylen, byte* data, size_t datalen, const byte* iv);
28}; //namespace zen
29
30#endif //ZEN_CRYPT_H_INCLUDED
diff --git a/utils/zenutils/source/shared/file.cpp b/utils/zenutils/source/shared/file.cpp
new file mode 100755
index 0000000000..2c31498972
--- /dev/null
+++ b/utils/zenutils/source/shared/file.cpp
@@ -0,0 +1,106 @@
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 "file.h"
20#include <fstream>
21
22
23bool shared::read_file(const std::string& filename, bytes& buffer,
24 std::streampos offset, std::streamsize count)
25{
26 std::ifstream ifs;
27 ifs.open(filename.c_str(), std::ios::binary);
28 if (!ifs)
29 {
30 return false;
31 }
32
33 std::ifstream::pos_type startpos = offset;
34 ifs.seekg(offset, std::ios::beg);
35 if (count == -1)
36 ifs.seekg(0, std::ios::end);
37 else
38 ifs.seekg(count, std::ios::cur);
39 std::ifstream::pos_type endpos = ifs.tellg();
40
41 buffer.resize(endpos-startpos);
42 ifs.seekg(offset, std::ios::beg);
43
44 ifs.read((char*)&buffer[0], endpos-startpos);
45
46 ifs.close();
47 return ifs.good();
48}
49
50
51bool shared::write_file(const std::string& filename, bytes& buffer,
52 bool truncate, std::streampos offset,
53 std::streamsize count)
54{
55 std::ios::openmode mode = std::ios::in|std::ios::out|std::ios::binary;
56 if (truncate)
57 mode |= std::ios::trunc;
58
59 std::fstream ofs;
60 ofs.open(filename.c_str(), mode);
61 if (!ofs)
62 {
63 return false;
64 }
65
66 if (count == -1)
67 count = buffer.size();
68 else if (count > buffer.size())
69 return false;
70
71 ofs.seekg(offset, std::ios::beg);
72
73 ofs.write((char*)&buffer[0], count);
74
75 ofs.close();
76 return ofs.good();
77}
78
79bool shared::file_exists(const std::string& filename)
80{
81 std::ifstream ifs;
82 ifs.open(filename.c_str(), std::ios::in);
83 if (ifs.is_open())
84 {
85 ifs.close();
86 return true;
87 }
88 return false;
89}
90
91bool shared::copy_file(const std::string& srcname, const std::string& dstname)
92{
93 bytes buffer;
94 if (!read_file(srcname, buffer))
95 return false;
96 return write_file(dstname, buffer, true);
97}
98
99bool shared::backup_file(const std::string& filename, bool force)
100{
101 std::string backupname = filename + ".bak";
102 if (!force)
103 if (file_exists(backupname))
104 return true;
105 return copy_file(filename, backupname);
106}
diff --git a/utils/zenutils/source/shared/file.h b/utils/zenutils/source/shared/file.h
new file mode 100755
index 0000000000..8fa533c981
--- /dev/null
+++ b/utils/zenutils/source/shared/file.h
@@ -0,0 +1,36 @@
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#ifndef SHARED_FILE_H_INCLUDED
20#define SHARED_FILE_H_INCLUDED
21
22#include <string>
23#include <iostream>
24#include "utils.h"
25
26namespace shared {
27 bool read_file(const std::string& filename, bytes& buffer,
28 std::streampos offset = 0, std::streamsize count = -1);
29 bool write_file(const std::string& filename, bytes& buffer, bool truncate,
30 std::streampos offset = 0, std::streamsize count = -1);
31 bool file_exists(const std::string& filename);
32 bool copy_file(const std::string& srcname, const std::string& dstname);
33 bool backup_file(const std::string& filename, bool force = false);
34}; //namespace shared
35
36#endif //SHARED_FILE_H_INCLUDED
diff --git a/utils/zenutils/source/shared/firmware.cpp b/utils/zenutils/source/shared/firmware.cpp
new file mode 100755
index 0000000000..7767b55d8f
--- /dev/null
+++ b/utils/zenutils/source/shared/firmware.cpp
@@ -0,0 +1,387 @@
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 "firmware.h"
20#include <iostream>
21#include <stdexcept>
22
23
24zen::firmware_entry::firmware_entry(bool big_endian)
25 : _big_endian(big_endian)
26{
27}
28
29zen::firmware_entry::firmware_entry(const firmware_entry& copy)
30{
31 assign(copy);
32}
33
34zen::firmware_entry& zen::firmware_entry::operator=(const firmware_entry& right)
35{
36 assign(right);
37 return *this;
38}
39
40
41bool zen::firmware_entry::read(std::istream& is)
42{
43 // Read the header.
44 is.read((char*)&_header, sizeof(firmware_header_t));
45 if (!is.good())
46 return false;
47
48 // If the firmware is big-endian, swap the header values to little-endian.
49 if (_big_endian)
50 {
51 _header.tag = shared::swap(_header.tag);
52 if (_header.tag != 'NULL')
53 {
54 _header.size = shared::swap(_header.size);
55 }
56 }
57
58 // Resize the bytes buffer to the size specified in the header.
59 _bytes.resize(_header.size);
60
61 // Read the entry contents.
62 is.read(reinterpret_cast<char*>(&_bytes[0]),
63 _header.size);
64
65 return is.good();
66}
67
68bool zen::firmware_entry::write(std::ostream& os) const
69{
70 // Form a header using the current size of the bytes buffer.
71 firmware_header_t header = {
72 _header.tag,
73 static_cast<dword>(_bytes.size())
74 };
75
76 // If the firmware is big-endian, swap the header values back into big-endian.
77 if (_big_endian)
78 {
79 if (header.tag != 'NULL')
80 {
81 header.size = shared::swap(header.size);
82 }
83 header.tag = shared::swap(header.tag);
84 }
85
86 // Write the header.
87 os.write((const char*)&header, sizeof(firmware_header_t));
88 if (!os.good())
89 return false;
90
91 // Write the entry contents.
92 os.write(reinterpret_cast<const char*>(&_bytes[0]),
93 static_cast<std::streamsize>(_bytes.size()));
94
95 return os.good();
96}
97
98
99bool zen::firmware_entry::is_big_endian() const
100{
101 return _big_endian;
102}
103
104const zen::firmware_header_t& zen::firmware_entry::get_header() const
105{
106 return _header;
107}
108zen::firmware_header_t& zen::firmware_entry::get_header()
109{
110 return _header;
111}
112
113const shared::bytes& zen::firmware_entry::get_bytes() const
114{
115 return _bytes;
116}
117shared::bytes& zen::firmware_entry::get_bytes()
118{
119 return _bytes;
120}
121
122
123std::string zen::firmware_entry::get_name() const
124{
125 char name[5];
126 *(dword*)name = shared::swap(_header.tag);
127 name[4] = '\0';
128
129 // Determine if all characters in the tag are printable.
130 bool isprintable = true;
131 for (int i = 0; i < 4; i++)
132 {
133 if (!isprint((byte)name[i]))
134 {
135 isprintable = false;
136 break;
137 }
138 }
139
140 // If they are, simply return the tag as a string.
141 if (isprintable)
142 {
143 return std::string(name);
144 }
145
146 // Otherwise, encode the tag into a hexadecimal string.
147 char buffer[11];
148 sprintf(buffer, "0x%08x", _header.tag);
149 return std::string(buffer);
150}
151
152std::string zen::firmware_entry::get_content_name() const
153{
154 std::string name = get_name();
155 if (name == "DATA")
156 {
157 name = "";
158 int nameoff = is_big_endian() ? 1 : 0;
159 for (int i = 0; i < 16; i++)
160 {
161 char c = get_bytes()[i * 2 + nameoff];
162 if (!c)
163 break;
164 name += c;
165 }
166 }
167 else if (name == "EXT0")
168 {
169 name = "";
170 int nameoff = is_big_endian() ? 1 : 0;
171 for (int i = 0; i < 12; i++)
172 {
173 char c = get_bytes()[i * 2 + nameoff];
174 if (!c)
175 break;
176 name += c;
177 }
178 }
179 return name;
180}
181
182size_t zen::firmware_entry::get_content_offset() const
183{
184 std::string name = get_name();
185 if (name == "DATA")
186 {
187 return 32;
188 }
189 else if (name == "EXT0")
190 {
191 return 24;
192 }
193 return 0;
194}
195
196size_t zen::firmware_entry::calc_size() const
197{
198 return _bytes.size() + sizeof(firmware_header_t);
199}
200
201
202void zen::firmware_entry::assign(const firmware_entry& copy)
203{
204 _big_endian = copy._big_endian;
205 _header.tag = copy._header.tag;
206 _header.size = copy._header.size;
207 _bytes.assign(copy._bytes.begin(), copy._bytes.end());
208}
209
210
211
212zen::firmware_archive::firmware_archive(bool big_endian)
213 : _big_endian(big_endian)
214{
215}
216
217zen::firmware_archive::firmware_archive(const firmware_archive& copy)
218{
219 assign(copy);
220}
221
222zen::firmware_archive& zen::firmware_archive::operator=(const firmware_archive& right)
223{
224 assign(right);
225 return *this;
226}
227
228
229bool zen::firmware_archive::read(std::istream& is)
230{
231 // Read the root entry's header.
232 firmware_header_t root;
233 is.read((char*)&root, sizeof(firmware_header_t));
234 if (!is.good())
235 return false;
236
237 if ((root.tag != 'CIFF') && (root.tag != 'FFIC'))
238 {
239 throw std::runtime_error("Invalid firmware archive format!");
240 }
241
242 _big_endian = root.tag == 'FFIC' ? true : false;
243 if (_big_endian)
244 {
245 root.tag = shared::swap(root.tag);
246 root.size = shared::swap(root.size);
247 }
248
249 // Save the current stream position.
250 std::istream::pos_type endpos = is.tellg();
251 std::istream::pos_type curpos = endpos;
252 endpos += std::istream::pos_type(root.size);
253
254 // Read untill the end of the root entry contents.
255 while (curpos < endpos)
256 {
257 firmware_entry entry(_big_endian);
258 if (!entry.read(is))
259 return false;
260
261 _children.push_back(entry);
262 curpos = is.tellg();
263 }
264
265 curpos = is.tellg();
266 is.seekg(0, std::ios::end);
267 endpos = is.tellg();
268 is.seekg(curpos);
269
270 // Read untill the end of the file.
271 while (((size_t)curpos + sizeof(firmware_header_t)) < endpos)
272 {
273 firmware_entry entry(_big_endian);
274 if (!entry.read(is))
275 return false;
276
277 _neighbours.push_back(entry);
278 curpos = is.tellg();
279 }
280
281 return true;
282}
283
284bool zen::firmware_archive::write(std::ostream& os) const
285{
286 // Read the root entry's header.
287 firmware_header_t root = {'CIFF', 0};
288
289 // Calculate the total size of all the children entries.
290 for (firmware_entries::const_iterator i = _children.begin();
291 i != _children.end(); ++i)
292 {
293 root.size += i->calc_size();
294 }
295
296 // If the firmware is big-endian, swap the header values back into big-endian.
297 if (_big_endian)
298 {
299 root.tag = shared::swap(root.tag);
300 root.size = shared::swap(root.size);
301 }
302
303 // Write the header.
304 os.write((const char*)&root, sizeof(firmware_header_t));
305 if (!os.good())
306 return false;
307
308 // Write all the child entries.
309 for (firmware_entries::const_iterator i = _children.begin();
310 i != _children.end(); ++i)
311 {
312 if (!i->write(os))
313 return false;
314 }
315
316 // Write all the neighbour entries.
317 for (firmware_entries::const_iterator i = _neighbours.begin();
318 i != _neighbours.end(); ++i)
319 {
320 if (!i->write(os))
321 return false;
322 }
323
324 return true;
325}
326
327
328bool zen::firmware_archive::is_big_endian() const
329{
330 return _big_endian;
331}
332
333const zen::firmware_entries& zen::firmware_archive::get_children() const
334{
335 return _children;
336}
337zen::firmware_entries& zen::firmware_archive::get_children()
338{
339 return _children;
340}
341
342const zen::firmware_entries& zen::firmware_archive::get_neighbours() const
343{
344 return _neighbours;
345}
346zen::firmware_entries& zen::firmware_archive::get_neighbours()
347{
348 return _neighbours;
349}
350
351bool zen::firmware_archive::is_signed() const
352{
353 for (firmware_entries::const_iterator i = _neighbours.begin();
354 i != _neighbours.end(); i++)
355 {
356 if (i->get_name() == "NULL")
357 return true;
358 }
359 return false;
360}
361
362size_t zen::firmware_archive::calc_size() const
363{
364 size_t size = sizeof(firmware_header_t);
365
366 for (firmware_entries::const_iterator i = _children.begin();
367 i != _children.end(); i++)
368 {
369 size += i->calc_size();
370 }
371
372 for (firmware_entries::const_iterator i = _neighbours.begin();
373 i != _neighbours.end(); i++)
374 {
375 size += i->calc_size();
376 }
377
378 return size;
379}
380
381
382void zen::firmware_archive::assign(const firmware_archive& copy)
383{
384 _big_endian = copy._big_endian;
385 _children.assign(copy._children.begin(), copy._children.end());
386 _neighbours.assign(copy._neighbours.begin(), copy._neighbours.end());
387}
diff --git a/utils/zenutils/source/shared/firmware.h b/utils/zenutils/source/shared/firmware.h
new file mode 100755
index 0000000000..3542186590
--- /dev/null
+++ b/utils/zenutils/source/shared/firmware.h
@@ -0,0 +1,92 @@
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#ifndef ZEN_FIRMWARE_H_INCLUDED
20#define ZEN_FIRMWARE_H_INCLUDED
21
22#include <list>
23#include <utils.h>
24
25namespace zen {
26 struct firmware_header_t
27 {
28 dword tag;
29 dword size;
30 }; //struct firmware_header_t
31
32 class firmware_entry
33 {
34 public:
35 firmware_entry(bool big_endian);
36 firmware_entry(const firmware_entry& copy);
37 firmware_entry& operator=(const firmware_entry& right);
38
39 bool read(std::istream& is);
40 bool write(std::ostream& os) const;
41
42 bool is_big_endian() const;
43 const firmware_header_t& get_header() const;
44 firmware_header_t& get_header();
45 const shared::bytes& get_bytes() const;
46 shared::bytes& get_bytes();
47
48 std::string get_name() const;
49 std::string get_content_name() const;
50 size_t get_content_offset() const;
51 size_t calc_size() const;
52
53 protected:
54 void assign(const firmware_entry& copy);
55
56 private:
57 bool _big_endian;
58 firmware_header_t _header;
59 shared::bytes _bytes;
60 }; //class firmware_entry
61
62 typedef std::list<firmware_entry> firmware_entries;
63
64 class firmware_archive
65 {
66 public:
67 firmware_archive(bool big_endian);
68 firmware_archive(const firmware_archive& copy);
69 firmware_archive& operator=(const firmware_archive& right);
70
71 bool read(std::istream& is);
72 bool write(std::ostream& os) const;
73
74 bool is_big_endian() const;
75 const firmware_entries& get_children() const;
76 firmware_entries& get_children();
77 const firmware_entries& get_neighbours() const;
78 firmware_entries& get_neighbours();
79 bool is_signed() const;
80 size_t calc_size() const;
81
82 protected:
83 void assign(const firmware_archive& copy);
84
85 private:
86 firmware_entries _children;
87 firmware_entries _neighbours;
88 bool _big_endian;
89 }; //class firmware_archive
90}; //namespace zen
91
92#endif //ZEN_FIRMWARE_ARCHIVE_H_INCLUDED
diff --git a/utils/zenutils/source/shared/pe.cpp b/utils/zenutils/source/shared/pe.cpp
new file mode 100755
index 0000000000..c86ec6c8cc
--- /dev/null
+++ b/utils/zenutils/source/shared/pe.cpp
@@ -0,0 +1,128 @@
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 "pe.h"
20
21
22shared::pe_file::pe_file(PeLib::PeFile* pef) : _pef(pef)
23{
24}
25shared::pe_file::~pe_file()
26{
27 if (_pef != NULL)
28 delete _pef;
29}
30
31bool shared::pe_file::is_valid() const
32{
33 if (_pef->getBits() == 32)
34 {
35 PeLib::PeHeader32& pef32 = static_cast<PeLib::PeFile32*>(_pef)->peHeader();
36 if (!pef32.isValid())
37 return false;
38 return true;
39 }
40 else if (_pef->getBits() == 64)
41 {
42 PeLib::PeHeader64& pef64 = static_cast<PeLib::PeFile64*>(_pef)->peHeader();
43 if (!pef64.isValid())
44 return false;
45 return true;
46 }
47 return false;
48}
49
50bool shared::pe_file::read(const std::string& filename)
51{
52 if (_pef != NULL)
53 {
54 delete _pef;
55 _pef = NULL;
56 }
57
58 _pef = PeLib::openPeFile(filename);
59 if (!_pef)
60 {
61 return false;
62 }
63 if (_pef->readMzHeader())
64 {
65 delete _pef;
66 return false;
67 }
68 if (!_pef->mzHeader().isValid())
69 {
70 delete _pef;
71 return false;
72 }
73 if (_pef->readPeHeader())
74 {
75 delete _pef;
76 return false;
77 }
78 if (!is_valid())
79 {
80 delete _pef;
81 return false;
82 }
83 return true;
84}
85
86bool shared::pe_file::find_section(const std::string& name, section_info& info) const
87{
88 if (_pef->getBits() == 32)
89 return find_section(static_cast<PeLib::PeFile32*>(_pef),
90 name, info);
91 else if (_pef->getBits() == 64)
92 return find_section(static_cast<PeLib::PeFile64*>(_pef),
93 name, info);
94 return false;
95}
96
97bool shared::pe_file::add_section(const std::string& name,
98 const bytes& buffer, section_info& info)
99{
100 if (_pef->getBits() == 32)
101 {
102 return add_section(static_cast<PeLib::PeFile32*>(_pef),
103 name, buffer, info);
104 }
105 else if (_pef->getBits() == 64)
106 {
107 return add_section(static_cast<PeLib::PeFile64*>(_pef),
108 name, buffer, info);
109 }
110 return false;
111}
112
113dword shared::pe_file::get_image_base() const
114{
115 if (_pef->getBits() == 32)
116 return static_cast<PeLib::PeFile32*>(_pef)->peHeader().getImageBase();
117 else
118 return static_cast<PeLib::PeFile64*>(_pef)->peHeader().getImageBase();
119 return 0;
120}
121dword shared::pe_file::pa_to_va(dword pa) const
122{
123 if (_pef->getBits() == 32)
124 return static_cast<PeLib::PeFile32*>(_pef)->peHeader().offsetToVa(pa);
125 else
126 return static_cast<PeLib::PeFile64*>(_pef)->peHeader().offsetToVa(pa);
127 return 0;
128}
diff --git a/utils/zenutils/source/shared/pe.h b/utils/zenutils/source/shared/pe.h
new file mode 100755
index 0000000000..92a272d3c7
--- /dev/null
+++ b/utils/zenutils/source/shared/pe.h
@@ -0,0 +1,142 @@
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#ifndef SHARED_PE_H_INCLUDED
20#define SHARED_PE_H_INCLUDED
21
22#include <string>
23#include <pelib/PeLib.h>
24#include <utils.h>
25
26namespace shared {
27 struct section_info
28 {
29 word index;
30 dword virtual_address;
31 dword virtual_size;
32 dword raw_address;
33 dword raw_size;
34 dword characteristics;
35 }; //struct section_info
36
37 class pe_file
38 {
39 public:
40 pe_file(PeLib::PeFile* pef = NULL);
41 ~pe_file();
42
43 bool is_valid() const;
44 bool read(const std::string& filename);
45 bool find_section(const std::string& name, section_info& info) const;
46 bool add_section(const std::string& name, const bytes& buffer, section_info& info);
47 dword get_image_base() const;
48 dword pa_to_va(PeLib::dword pa) const;
49
50 protected:
51 template <int _Bits>
52 static bool find_section(const PeLib::PeFileT<_Bits>* pef,
53 const std::string& name, section_info& info);
54 template <int _Bits>
55 static bool add_section(PeLib::PeFileT<_Bits>* pef,
56 const std::string& name, const bytes& buffer,
57 section_info& info);
58
59 private:
60 PeLib::PeFile* _pef;
61 }; //class pe_file
62
63
64 template <int _Bits>
65 bool pe_file::find_section(const PeLib::PeFileT<_Bits>* pef,
66 const std::string& name, section_info& info)
67 {
68 for (PeLib::word i = 0; i < pef->peHeader().getNumberOfSections(); i++)
69 {
70 if (pef->peHeader().getSectionName(i) == name)
71 {
72 info.index = i;
73 info.virtual_address = pef->peHeader().getVirtualAddress(i);
74 info.virtual_size = pef->peHeader().getVirtualSize(i);
75 info.raw_address = pef->peHeader().getPointerToRawData(i);
76 info.raw_size = pef->peHeader().getSizeOfRawData(i);
77 info.characteristics = pef->peHeader().getCharacteristics(i);
78 return true;
79 }
80 }
81 return false;
82 }
83
84 template <int _Bits>
85 bool pe_file::add_section(PeLib::PeFileT<_Bits>* pef,
86 const std::string& name, const bytes& buffer,
87 section_info& info)
88 {
89 using namespace PeLib;
90
91 // Check if the last section has the same name as the one being added.
92 PeLib::word secnum = pef->peHeader().getNumberOfSections();
93 if (pef->peHeader().getSectionName(secnum-1) == name)
94 {
95 // If it is, we change the attributes of the existing section.
96 secnum = secnum - 1;
97 pef->peHeader().setSizeOfRawData(secnum,
98 alignOffset(buffer.size(),
99 pef->peHeader().getFileAlignment()));
100 pef->peHeader().setVirtualSize(secnum,
101 alignOffset(buffer.size(),
102 pef->peHeader().getSectionAlignment()));
103 PeLib::dword chars = pef->peHeader().getCharacteristics(secnum-1);
104 pef->peHeader().setCharacteristics(secnum,
105 chars | PELIB_IMAGE_SCN_MEM_WRITE | PELIB_IMAGE_SCN_MEM_READ);
106 }
107 else
108 {
109 // Otherwise we add a new section.
110 if (pef->peHeader().addSection(name, buffer.size()) != NO_ERROR)
111 {
112 return false;
113 }
114 pef->peHeader().makeValid(pef->mzHeader().getAddressOfPeHeader());
115 pef->peHeader().write(pef->getFileName(), pef->mzHeader().getAddressOfPeHeader());
116 }
117
118 // Save the section headers to the file.
119 if (pef->peHeader().writeSections(pef->getFileName()) != NO_ERROR)
120 {
121 return false;
122 }
123
124 // Save the section data to the file.
125 if (pef->peHeader().writeSectionData(pef->getFileName(), secnum, buffer) != NO_ERROR)
126 {
127 return false;
128 }
129
130 // Fill out the section information.
131 info.index = secnum;
132 info.virtual_address = pef->peHeader().getVirtualAddress(secnum);
133 info.virtual_size = pef->peHeader().getVirtualSize(secnum);
134 info.raw_address = pef->peHeader().getPointerToRawData(secnum);
135 info.raw_size = pef->peHeader().getSizeOfRawData(secnum);
136 info.characteristics = pef->peHeader().getCharacteristics(secnum);
137
138 return true;
139 }
140}; //namespace shared
141
142#endif //SHARED_PE_H_INCLUDED
diff --git a/utils/zenutils/source/shared/shared.cpp b/utils/zenutils/source/shared/shared.cpp
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/utils/zenutils/source/shared/shared.cpp
diff --git a/utils/zenutils/source/shared/updater.cpp b/utils/zenutils/source/shared/updater.cpp
new file mode 100755
index 0000000000..77d3f2876c
--- /dev/null
+++ b/utils/zenutils/source/shared/updater.cpp
@@ -0,0 +1,151 @@
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 "updater.h"
20#include <file.h>
21#include <pe.h>
22#include <utils.h>
23
24
25const char* zen::find_firmware_key(const byte* buffer, size_t len)
26{
27 char szkey1[] = "34d1";
28 size_t cchkey1 = strlen(szkey1);
29 char szkey2[] = "TbnCboEbn";
30 size_t cchkey2 = strlen(szkey2);
31 for (int i = 0; i < static_cast<int>(len); i++)
32 {
33 if (len >= cchkey1)
34 {
35 if (!strncmp((char*)&buffer[i], szkey1, cchkey1))
36 {
37 return (const char*)&buffer[i];
38 }
39 }
40 if (len >= cchkey2)
41 {
42 if (!strncmp((char*)&buffer[i], szkey2, cchkey2))
43 {
44 return (const char*)&buffer[i];
45 }
46 }
47 }
48 return NULL;
49}
50
51dword zen::find_firmware_offset(byte* buffer, size_t len)
52{
53 for (dword i = 0; i < static_cast<dword>(len); i += 0x10)
54 {
55 dword size = *(dword*)&buffer[i];
56 if (size < (i + len) && size > (len >> 1))
57 {
58 if (buffer[i + sizeof(dword)] != 0
59 && buffer[i + sizeof(dword) + 1] != 0
60 && buffer[i + sizeof(dword) + 2] != 0
61 && buffer[i + sizeof(dword) + 3] != 0)
62 {
63 return i;
64 }
65 }
66 }
67 return 0;
68}
69
70bool zen::find_firmware_archive(const std::string& filename, dword& va, dword& pa)
71{
72 shared::pe_file pef;
73 if (!pef.read(filename))
74 {
75 return false;
76 }
77 shared::section_info data_section;
78 if (!pef.find_section(".data", data_section))
79 {
80 return false;
81 }
82 shared::bytes buffer;
83 if (!shared::read_file(filename, buffer, data_section.raw_address,
84 data_section.raw_size))
85 {
86 return false;
87 }
88 dword offset = find_firmware_offset(&buffer[0], buffer.size());
89 if (!offset)
90 {
91 return false;
92 }
93 va = data_section.virtual_address + offset;
94 pa = data_section.raw_address + offset;
95
96 return true;
97}
98
99
100bool zen::crypt_firmware(const char* key, byte* buffer, size_t len)
101{
102 // Determine if the key length is dword aligned.
103 int keylen = strlen(key);
104 int keylen_rem = keylen % sizeof(dword);
105
106 // Determine how many times the key must be repeated to be dword aligned.
107 int keycycle = keylen_rem ? (sizeof(dword) / keylen_rem) : 1;
108 int keyscount = (keylen * keycycle) / sizeof(dword);
109
110 // Allocate a buffer to hold the key as an array of dwords.
111 dword* keys = new dword[keyscount];
112
113 // Copy the key into the key array, whilst mutating it.
114 for (int i = 0; i < keyscount; i++)
115 {
116 dword val;
117 int keyoffset = (i * sizeof(dword)) % keylen;
118 if ((keyoffset+sizeof(dword)) < keylen)
119 {
120 val = *(dword*)&key[keyoffset];
121 }
122 else
123 {
124 val = key[keyoffset]
125 | (key[(keyoffset + 1) % keylen] << 8)
126 | (key[(keyoffset + 2) % keylen] << 16)
127 | (key[(keyoffset + 3) % keylen] << 24);
128 }
129 keys[i] = (val - 0x01010101) | 0x80808080;
130 }
131
132 // Determine the number of dwords in the buffer.
133 int len_div = len / sizeof(dword);
134
135 // Decrypt all dwords of the buffer.
136 for (int i = 0; i < len_div; i++)
137 {
138 ((dword*)buffer)[i] ^= keys[i % keyscount];
139 }
140
141 // Determine the remaining number of bytes in the buffer.
142 int len_rem = len % sizeof(dword);
143
144 // Decrypt the remaining number of bytes in the buffer.
145 for (int i = len_div * sizeof(dword); i < len; i++)
146 {
147 buffer[i] ^= ((key[i % keylen] - 0x01) | 0x80);
148 }
149
150 return true;
151}
diff --git a/utils/zenutils/source/shared/updater.h b/utils/zenutils/source/shared/updater.h
new file mode 100755
index 0000000000..57f9979c30
--- /dev/null
+++ b/utils/zenutils/source/shared/updater.h
@@ -0,0 +1,32 @@
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#ifndef ZEN_UPDATER_H_INCLUDED
20#define ZEN_UPDATER_H_INCLUDED
21
22#include <pelib/PeLib.h>
23#include <utils.h>
24
25namespace zen {
26 const char* find_firmware_key(const byte* buffer, size_t len);
27 dword find_firmware_offset(byte* buffer, size_t len);
28 bool find_firmware_archive(const std::string& filename, dword& va, dword& pa);
29 bool crypt_firmware(const char* key, byte* buffer, size_t len);
30}; //namespace zen
31
32#endif //ZEN_UPDATER_H_INCLUDED
diff --git a/utils/zenutils/source/shared/utils.cpp b/utils/zenutils/source/shared/utils.cpp
new file mode 100755
index 0000000000..8f45de5d3f
--- /dev/null
+++ b/utils/zenutils/source/shared/utils.cpp
@@ -0,0 +1,211 @@
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 "utils.h"
20#include <fstream>
21#include <zlib/zlib.h>
22
23
24std::string shared::replace_extension(const std::string& filename, const std::string& extension)
25{
26 std::string newname;
27 const char* name = filename.c_str();
28 const char* ext = strrchr(name, '.');
29 if (ext)
30 {
31 // If an extension was found, replace it.
32 newname.assign(name, ext-name);
33 newname += extension;
34 }
35 else
36 {
37 // If an extension was not found, append it.
38 newname = name;
39 newname += extension;
40 }
41 return newname;
42}
43
44std::string shared::remove_extension(const std::string& filename)
45{
46 std::string newname;
47 const char* name = filename.c_str();
48 const char* ext = strrchr(name, '.');
49 if (ext)
50 {
51 newname.assign(name, ext-name);
52 }
53 else
54 {
55 newname = name;
56 }
57 return newname;
58}
59
60std::string shared::double_quote(const std::string& str)
61{
62 std::string out;
63 for (int i = 0, j = str.length(); i < j; i++)
64 {
65 if (str[i] == '\\')
66 out += "\\\\";
67 else
68 out += str[i];
69 }
70 return out;
71}
72
73bool shared::inflate_to_file(const bytes& buffer, const char* filename)
74{
75 // Open output file.
76 std::ofstream ofs;
77 ofs.open(filename, std::ios::binary);
78 if (!ofs)
79 {
80 return false;
81 }
82
83 // Initialize zlib.
84 z_stream d_stream; // decompression stream
85
86 d_stream.zalloc = Z_NULL;
87 d_stream.zfree = Z_NULL;
88 d_stream.opaque = Z_NULL;
89
90 d_stream.next_in = const_cast<bytes::value_type*>(&buffer[0]);
91 d_stream.avail_in = static_cast<uInt>(buffer.size());
92
93 int ret = inflateInit(&d_stream);
94 if (ret != Z_OK)
95 return false;
96
97 // Allocate buffer to hold the inflated data.
98 const size_t BUFSIZE = 1048576;
99 Bytef* infbuf = new Bytef[BUFSIZE];
100 if (!infbuf)
101 return false;
102
103 // Decompress untill the end of the input buffer.
104 uLong totalout = 0;
105 bool bLoop = true;
106 while (bLoop)
107 {
108 d_stream.next_out = infbuf;
109 d_stream.avail_out = BUFSIZE;
110
111 ret = inflate(&d_stream, Z_NO_FLUSH);
112 if (ret == Z_STREAM_END)
113 {
114 bLoop = false;
115 }
116 else if (ret != Z_OK)
117 {
118 inflateEnd(&d_stream);
119 delete [] infbuf;
120 return false;
121 }
122
123 // Write the inflated data to the output file.
124 if (!ofs.write((const char*)infbuf, d_stream.total_out-totalout))
125 {
126 inflateEnd(&d_stream);
127 delete [] infbuf;
128 return false;
129 }
130 totalout = d_stream.total_out;
131 }
132
133 // Cleanup and return.
134 inflateEnd(&d_stream);
135 delete [] infbuf;
136
137 return true;
138}
139
140bool shared::deflate_to_file(const bytes& buffer, const char* filename)
141{
142 // Open output file.
143 std::ofstream ofs;
144 ofs.open(filename, std::ios::binary);
145 if (!ofs)
146 {
147 return false;
148 }
149
150 // Initialize zlib.
151 z_stream c_stream; // compression stream.
152
153 c_stream.zalloc = Z_NULL;
154 c_stream.zfree = Z_NULL;
155 c_stream.opaque = Z_NULL;
156
157 int ret = deflateInit(&c_stream, Z_BEST_COMPRESSION);
158 if (ret != Z_OK)
159 return false;
160
161 // Allocate buffer to hold the deflated data.
162 const size_t BUFSIZE = 1048576;
163 Bytef* defbuf = new Bytef[BUFSIZE];
164 if (!defbuf)
165 return false;
166
167 c_stream.avail_in = static_cast<uInt>(buffer.size());
168 c_stream.next_in = const_cast<bytes::value_type*>(&buffer[0]);
169
170 // Compress until end of the buffer.
171 uLong totalout = 0;
172 bool bLoop = true;
173 while (bLoop)
174 {
175 c_stream.avail_out = BUFSIZE;
176 c_stream.next_out = defbuf;
177
178 ret = deflate(&c_stream, Z_NO_FLUSH); // no bad return value
179 if (ret == Z_STREAM_END)
180 {
181 bLoop = false;
182 }
183 else if (ret == Z_BUF_ERROR && !c_stream.avail_in)
184 {
185 ret = deflate(&c_stream, Z_FINISH); // no bad return value
186 bLoop = false;
187 }
188 else if (ret != Z_OK)
189 {
190 deflateEnd(&c_stream);
191 delete [] defbuf;
192 return false;
193 }
194
195 // Write the inflated data to the output file.
196 if (!ofs.write((const char*)defbuf, c_stream.total_out-totalout))
197 {
198 deflateEnd(&c_stream);
199 delete [] defbuf;
200 return false;
201 }
202
203 totalout = c_stream.total_out;
204 }
205
206 // Clean up and return.
207 deflateEnd(&c_stream);
208 delete [] defbuf;
209
210 return true;
211}
diff --git a/utils/zenutils/source/shared/utils.h b/utils/zenutils/source/shared/utils.h
new file mode 100755
index 0000000000..ca9e291514
--- /dev/null
+++ b/utils/zenutils/source/shared/utils.h
@@ -0,0 +1,68 @@
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#ifndef SHARED_UTILS_H_INCLUDED
20#define SHARED_UTILS_H_INCLUDED
21
22#include <vector>
23#include <pelib/PeLib.h>
24
25#ifndef byte
26typedef PeLib::byte byte;
27#endif
28#ifndef word
29typedef PeLib::word word;
30#endif
31#ifndef dword
32typedef PeLib::dword dword;
33#endif
34
35namespace shared {
36 typedef std::vector<byte> bytes;
37
38 inline dword swap(dword val)
39 {
40 return ((val & 0xFF) << 24)
41 | ((val & 0xFF00) << 8)
42 | ((val & 0xFF0000) >> 8)
43 | ((val & 0xFF000000) >> 24);
44 }
45
46 template <typename _Type>
47 inline void reverse(_Type* start, _Type* end)
48 {
49 while (start < end)
50 {
51 *start ^= *end;
52 *end ^= *start;
53 *start ^= *end;
54 start++;
55 end--;
56 }
57 }
58
59 std::string replace_extension(const std::string& filename, const std::string& extension);
60 std::string remove_extension(const std::string& filename);
61 std::string get_path(const std::string& filename);
62 std::string double_quote(const std::string& str);
63
64 bool inflate_to_file(const bytes& buffer, const char* filename);
65 bool deflate_to_file(const bytes& buffer, const char* filename);
66}; //namespace shared
67
68#endif //SHARED_UTILS_H_INCLUDED
diff --git a/utils/zenutils/source/update_extract/CMakeLists.txt b/utils/zenutils/source/update_extract/CMakeLists.txt
new file mode 100755
index 0000000000..813e389bed
--- /dev/null
+++ b/utils/zenutils/source/update_extract/CMakeLists.txt
@@ -0,0 +1,3 @@
1ADD_EXECUTABLE(update_extract main.cpp)
2
3TARGET_LINK_LIBRARIES (update_extract shared)
diff --git a/utils/zenutils/source/update_extract/main.cpp b/utils/zenutils/source/update_extract/main.cpp
new file mode 100755
index 0000000000..0fae29e00c
--- /dev/null
+++ b/utils/zenutils/source/update_extract/main.cpp
@@ -0,0 +1,279 @@
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 <iomanip>
21#include <ctime>
22#include <getpot/getpot.hpp>
23#include <file.h>
24#include <updater.h>
25#include <utils.h>
26
27
28static const char VERSION[] = "0.1";
29
30void print_version()
31{
32 std::cout
33 << "update_extract - Extracts a Creative firmware from an updater"
34 " executable." << std::endl
35 << "Version " << VERSION << std::endl
36 << "Copyright (c) 2007 Rasmus Ry" << std::endl;
37}
38
39void print_help()
40{
41 print_version();
42 std::cout << std::endl
43 << "Usage: update_extract [command] [options]" << std::endl
44 << std::endl
45 << " Commands:" << std::endl
46 << " -h,--help" << std::endl
47 << " prints this message." << std::endl
48 << " -u,--updater [file]" << std::endl
49 << " specifies the updater executable." << std::endl
50 << std::endl
51 << " Options:" << std::endl
52 << " -V,--verbose" << std::endl
53 << " prints verbose messages." << std::endl
54 << " -f,--firmware [file]" << std::endl
55 << " specifies the firmware arhive file name." << std::endl
56 << " -k,--key [key]" << std::endl
57 << " specifies the firmware archive key." << std::endl
58 << " -o,--offset [offset]" << std::endl
59 << " specifies the firmware archive offset in c-style"
60 " hexadecimal." << std::endl
61 << std::endl
62 ;
63}
64
65std::string options_name(const std::string& name)
66{
67 return shared::replace_extension(name, ".opt");
68}
69
70std::string default_firmware_name(const std::string& name)
71{
72 return shared::replace_extension(name, "_rk.bin");
73}
74
75int process_arguments(int argc, char* argv[])
76{
77 //--------------------------------------------------------------------
78 // Parse input variables.
79 //--------------------------------------------------------------------
80
81 GetPot cl(argc, argv);
82 if (cl.size() == 1 || cl.search(2, "-h", "--help"))
83 {
84 print_help();
85 return 1;
86 }
87
88 std::string updatername;
89 if (cl.search("-u") || cl.search("--updater"))
90 updatername = cl.next("");
91 if (updatername.empty())
92 {
93 std::cerr << "Updater executable must be specified." << std::endl;
94 return 2;
95 }
96
97 std::string firmarename = default_firmware_name(updatername);
98 if (cl.search("-f") || cl.search("--firmware"))
99 firmarename = cl.next(firmarename.c_str());
100
101 bool verbose = false;
102 if (cl.search("-V") || cl.search("--verbose"))
103 verbose = true;
104
105 // Get or find the firmware archive key.
106 std::string key;
107 if (cl.search("-k") || cl.search("--key"))
108 key = cl.next("");
109
110 if (key.empty())
111 {
112 if (verbose)
113 std::cout << "[*] Looking for firmware archive key..."
114 << std::endl;
115 shared::bytes buffer;
116 if (!shared::read_file(updatername, buffer))
117 {
118 std::cerr << "Failed to read the firmware updater executable."
119 << std::endl;
120 return 3;
121 }
122 key = zen::find_firmware_key(&buffer[0], buffer.size());
123 if (key.empty())
124 {
125 std::cerr << "Failed to find the firmware archive key."
126 << std::endl;
127 return 4;
128 }
129 }
130
131 // Get or find the firmware archive offset.
132 std::string offset;
133 dword offset_pa = 0;
134 if (cl.search("-o") || cl.search("--ofset"))
135 offset = cl.next("");
136
137 if (offset.empty())
138 {
139 if (verbose)
140 std::cout << "[*] Looking for firmware archive offset..."
141 << std::endl;
142
143 dword offset_va = 0;
144 if (!zen::find_firmware_archive(updatername, offset_va, offset_pa))
145 {
146 std::cerr << "Failed to find the firmware archive offset."
147 << std::endl;
148 return 5;
149 }
150 }
151 else
152 {
153 int offset_val;
154 if (!sscanf(offset.c_str(), "0x%x", &offset_val))
155 {
156 if (!sscanf(offset.c_str(), "0x%X", &offset_val))
157 {
158 std::cerr << "\'" << offset
159 << "\' is not a valid c-style hexadecimal value."
160 << std::endl;
161 return 6;
162 }
163 }
164 offset_pa = static_cast<dword>(offset_val);
165 }
166
167 // Read firmware archive size.
168 shared::bytes buffer;
169 if (!shared::read_file(updatername, buffer, offset_pa, sizeof(dword)))
170 {
171 std::cerr << "Failed to read the firmware archive size." << std::endl;
172 return 7;
173 }
174 dword archive_size = *(dword*)&buffer[0];
175
176 if (verbose)
177 {
178 std::cout << "[*] Printing input variables..." << std::endl;
179 std::cout << " Updater executable: " << updatername << std::endl;
180 std::cout << " Firmware archive: " << firmarename << std::endl;
181 std::cout << " Key: " << key << std::endl;
182 std::cout << " Offset: "
183 << std::hex << std::showbase << std::setw(10)
184 << std::setfill('0') << std::internal
185 << offset_pa << std::endl;
186 std::cout << " Size: "
187 << std::hex << std::showbase << std::setw(10)
188 << std::setfill('0') << std::internal
189 << archive_size << std::endl;
190 }
191
192
193 //--------------------------------------------------------------------
194 // Extract the firmware archive from the updater.
195 //--------------------------------------------------------------------
196
197 if (verbose)
198 std::cout << "[*] Reading firmware archive..." << std::endl;
199
200 // Read the firmware archive.
201 offset_pa += sizeof(dword);
202 if (!shared::read_file(updatername, buffer, offset_pa, archive_size))
203 {
204 std::cerr << "Failed to read the firmware archive." << std::endl;
205 return 8;
206 }
207
208 if (verbose)
209 std::cout << "[*] Decrypting firmware archive..." << std::endl;
210
211 // Decrypt the firmware archive.
212 if (!zen::crypt_firmware(key.c_str(), &buffer[0], buffer.size()))
213 {
214 std::cerr << "Failed to decrypt the firmware archive." << std::endl;
215 return 9;
216 }
217
218 if (verbose)
219 std::cout << "[*] Decompressing firmware archive..." << std::endl;
220
221 // Inflate the firmware archive to the output file.
222 if (!shared::inflate_to_file(buffer, firmarename.c_str()))
223 {
224 std::cerr << "Failed to decompress the firmware archive." << std::endl;
225 return 10;
226 }
227
228
229 //--------------------------------------------------------------------
230 // Generate an options file for the extracted firmware archive.
231 //--------------------------------------------------------------------
232
233 // Get options filename for the given input file.
234 std::string optionsname = options_name(updatername);
235
236 if (verbose)
237 std::cout << "[*] Producing options file..." << std::endl;
238
239 // Produce options file for the given input file.
240 std::ofstream ofs;
241 ofs.open(optionsname.c_str(), std::ios::binary);
242 if (!ofs)
243 {
244 std::cerr << "Failed to create firmware archive options file."
245 << std::endl;
246 return 11;
247 }
248
249 time_t timeval = time(NULL);
250 ofs << "# Options file generated at: " << ctime(&timeval)
251 << "updater = \'" << shared::double_quote(updatername) << "\'"
252 << std::endl
253 << "firmware = \'" << shared::double_quote(firmarename) << "\'"
254 << std::endl
255 << "offset = " << (offset_pa - sizeof(dword)) << std::endl
256 << "size = " << archive_size << std::endl
257 << "key = \'" << key << "\'" << std::endl;
258
259 return 0;
260}
261
262int main(int argc, char* argv[])
263{
264 try
265 {
266 return process_arguments(argc, argv);
267 }
268 catch (const std::exception& xcpt)
269 {
270 std::cerr << "Exception caught: " << xcpt.what() << std::endl;
271 return -1;
272 }
273 catch (...)
274 {
275 std::cerr << "Unknown exception caught." << std::endl;
276 return -2;
277 }
278 return -3;
279}
diff --git a/utils/zenutils/source/update_patch/CMakeLists.txt b/utils/zenutils/source/update_patch/CMakeLists.txt
new file mode 100755
index 0000000000..11474b7ff8
--- /dev/null
+++ b/utils/zenutils/source/update_patch/CMakeLists.txt
@@ -0,0 +1,3 @@
1ADD_EXECUTABLE(update_patch main.cpp)
2
3TARGET_LINK_LIBRARIES (update_patch shared)
diff --git a/utils/zenutils/source/update_patch/main.cpp b/utils/zenutils/source/update_patch/main.cpp
new file mode 100755
index 0000000000..d48797b46d
--- /dev/null
+++ b/utils/zenutils/source/update_patch/main.cpp
@@ -0,0 +1,409 @@
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 <iomanip>
21#include <cstdio>
22#include <getpot/getpot.hpp>
23#include <file.h>
24#include <updater.h>
25#include <utils.h>
26#include <pe.h>
27
28
29static const char VERSION[] = "0.1";
30
31void print_version()
32{
33 std::cout
34 << "update_patch - Patches a Creative firmware into an updater"
35 " executable." << std::endl
36 << "Version " << VERSION << std::endl
37 << "Copyright (c) 2007 Rasmus Ry" << std::endl;
38}
39
40void print_help()
41{
42 print_version();
43 std::cout << std::endl
44 << "Usage: update_patch [command] [options]" << std::endl
45 << std::endl
46 << " Commands:" << std::endl
47 << " -h,--help" << std::endl
48 << " prints this message." << std::endl
49 << " -u,--updater [file]" << std::endl
50 << " specifies the updater executable." << std::endl
51 << std::endl
52 << " Options:" << std::endl
53 << " -V,--verbose" << std::endl
54 << " prints verbose messages." << std::endl
55 << " -f,--firmware [file]" << std::endl
56 << " specifies the firmware arhive file name." << std::endl
57 << " -k,--key [key]" << std::endl
58 << " specifies the firmware archive key." << std::endl
59 << " -o,--offset [offset]" << std::endl
60 << " specifies the firmware archive offset in c-style"
61 " hexadecimal." << std::endl
62 << std::endl
63 ;
64}
65
66std::string options_name(const std::string& name)
67{
68 return shared::replace_extension(name, ".opt");
69}
70
71std::string default_firmware_name(const std::string& name)
72{
73 return shared::replace_extension(name, "_rk.bin");
74}
75
76int process_arguments(int argc, char* argv[])
77{
78 //--------------------------------------------------------------------
79 // Parse input variables.
80 //--------------------------------------------------------------------
81
82 GetPot cl(argc, argv);
83 if (cl.size() == 1 || cl.search(2, "-h", "--help"))
84 {
85 print_help();
86 return 1;
87 }
88
89 std::string updatername;
90 if (cl.search("-u") || cl.search("--updater"))
91 updatername = cl.next("");
92 if (updatername.empty())
93 {
94 std::cerr << "Updater executable must be specified." << std::endl;
95 return 2;
96 }
97
98 bool verbose = false;
99 if (cl.search("-V") || cl.search("--verbose"))
100 verbose = true;
101
102 if (verbose)
103 std::cout << "[*] Parsing options file..." << std::endl;
104
105 GetPot optfile(options_name(updatername.c_str()).c_str());
106 if (verbose)
107 optfile.print();
108
109 std::string firmwarename = optfile("firmware",
110 default_firmware_name(updatername).c_str());
111 dword offset_pa = optfile("offset", 0);
112 dword size = optfile("size", 0);
113 std::string key = optfile("key", "");
114
115 if (cl.search("-f") || cl.search("--firmware"))
116 firmwarename = cl.next(firmwarename.c_str());
117
118 std::string offset;
119 if (cl.search("-o") || cl.search("--offset"))
120 offset = cl.next("");
121
122 if (offset.empty() && !offset_pa)
123 {
124 if (verbose)
125 std::cout << "[*] Looking for firmware archive offset..."
126 << std::endl;
127
128 dword offset_va = 0;
129 if (!zen::find_firmware_archive(updatername, offset_va, offset_pa))
130 {
131 std::cerr << "Failed to find the firmware archive offset."
132 << std::endl;
133 return 3;
134 }
135 }
136 else if (!offset_pa)
137 {
138 int offset_val;
139 if (!sscanf(offset.c_str(), "0x%x", &offset_val))
140 {
141 if (!sscanf(offset.c_str(), "0x%X", &offset_val))
142 {
143 std::cerr << "\'" << offset
144 << "\' is not a valid c-style hexadecimal value."
145 << std::endl;
146 return 4;
147 }
148 }
149 offset_pa = static_cast<dword>(offset_val);
150 }
151
152 if (key.empty())
153 {
154 if (verbose)
155 std::cout << "[*] Looking for firmware archive key..."
156 << std::endl;
157 shared::bytes buffer;
158 if (!shared::read_file(updatername, buffer))
159 {
160 std::cerr << "Failed to read the firmware updater executable."
161 << std::endl;
162 return 5;
163 }
164 key = zen::find_firmware_key(&buffer[0], buffer.size());
165 if (key.empty())
166 {
167 std::cerr << "Failed to find the firmware archive key."
168 << std::endl;
169 return 6;
170 }
171 }
172
173 if (verbose)
174 {
175 std::cout << "[*] Printing input variables..." << std::endl;
176 std::cout << " Updater executable: " << updatername << std::endl;
177 std::cout << " Firmware archive: " << firmwarename << std::endl;
178 std::cout << " Key: " << key << std::endl;
179 std::cout << " Offset: "
180 << std::hex << std::showbase << std::setw(10)
181 << std::setfill('0') << std::internal
182 << offset_pa << std::endl;
183 std::cout << " Size: "
184 << std::hex << std::showbase << std::setw(10)
185 << std::setfill('0') << std::internal
186 << size << std::endl;
187 }
188
189
190 //--------------------------------------------------------------------
191 // Prepare the firmware archive for being patched into the updater.
192 //--------------------------------------------------------------------
193
194 if (verbose)
195 std::cout << "[*] Reading firmware archive..." << std::endl;
196
197 shared::bytes buffer;
198 if (!shared::read_file(firmwarename, buffer))
199 {
200 std::cerr << "Failed to read the firmware archive." << std::endl;
201 return 7;
202 }
203
204 if (verbose)
205 std::cout << " Bytes read: "
206 << std::hex << std::showbase << std::setw(10)
207 << std::setfill('0') << std::internal
208 << buffer.size() << std::endl;
209
210 if (verbose)
211 std::cout << "[*] Compressing firmware archive..." << std::endl;
212
213 std::string compfirmware = shared::replace_extension(firmwarename, ".def");
214 if (!shared::deflate_to_file(buffer, compfirmware.c_str()))
215 {
216 std::cerr << "Failed to compress the firmware archive." << std::endl;
217 return 8;
218 }
219
220 if (verbose)
221 std::cout << "[*] Reading compressed firmware archive..." << std::endl;
222
223 if (!shared::read_file(compfirmware, buffer))
224 {
225 std::cerr << "Failed to read the compressed firmware archive."
226 << std::endl;
227 return 9;
228 }
229
230 if (verbose)
231 std::cout << " Bytes read: "
232 << std::hex << std::showbase << std::setw(10)
233 << std::setfill('0') << std::internal
234 << buffer.size() << std::endl;
235
236 // Delete the temporary firmware file.
237 std::remove(compfirmware.c_str());
238
239 if (verbose)
240 std::cout << "[*] Encrypting compressed firmware archive..."
241 << std::endl;
242
243 if (!zen::crypt_firmware(key.c_str(), &buffer[0], buffer.size()))
244 {
245 std::cerr << "Failed to encrypt the compressed firmware archive."
246 << std::endl;
247 return 10;
248 }
249
250
251 //--------------------------------------------------------------------
252 // Backup the updater and patch the firmware archive into it.
253 //--------------------------------------------------------------------
254
255 if (verbose)
256 std::cout << "[*] Backing up the updater executable..." << std::endl;
257
258 if (!shared::backup_file(updatername))
259 {
260 std::cerr << "Failed to backup the updater executable." << std::endl;
261 return 11;
262 }
263
264 // Is there enough space within the existing firmware archive
265 // to hold the new one?
266 if (size < buffer.size())
267 {
268 // No, we need to add a new section to hold the new firmware archive.
269 if (verbose)
270 std::cout << "[*] Adding new section to the updater executable..."
271 << std::endl;
272
273 // Construct a new buffer with the archive size prepended.
274 shared::bytes newbuffer(buffer.size() + sizeof(dword));
275 *(dword*)&newbuffer[0] = static_cast<dword>(buffer.size());
276 std::copy(buffer.begin(), buffer.end(), &newbuffer[4]);
277
278 // Read the updater portable executable.
279 shared::pe_file pef;
280 if (!pef.read(updatername))
281 {
282 std::cerr << "Failed to read the updater portable executable"
283 " structure." << std::endl;
284 return 12;
285 }
286
287 // Add a new section to the updater, containing the encrypted
288 // firmware archive.
289 shared::section_info newsection;
290 if (!pef.add_section(".firm", newbuffer, newsection))
291 {
292 std::cerr << "Failed to add an extra section to the updater"
293 " executable." << std::endl;
294 return 13;
295 }
296
297 if (verbose)
298 std::cout << "[*] Relocating code references to the firmware"
299 " archive..." << std::endl;
300
301 // Locate the code section.
302 shared::section_info textsection;
303 if (!pef.find_section(".text", textsection))
304 {
305 std::cerr << "Failed to find the code section in the updater"
306 " executable." << std::endl;
307 return 14;
308 }
309
310 // Read the code section data.
311 if (!shared::read_file(updatername, buffer, textsection.raw_address,
312 textsection.raw_size))
313 {
314 std::cerr << "Failed to read the code section from the updater"
315 " executable." << std::endl;
316 return 15;
317 }
318
319 // Determine the addresses of the new and old firmware archives.
320 dword oldva = pef.pa_to_va(offset_pa);
321 dword newva = pef.pa_to_va(newsection.raw_address);
322 if (!oldva || !newva)
323 {
324 std::cerr << "Failed to compute address of the new or old"
325 " archive." << std::endl;
326 return 16;
327 }
328
329 // Relocate references to the old firmware archive.
330 dword imgbase = pef.get_image_base();
331 for (int i = 0, j = buffer.size() - sizeof(dword) + 1; i < j; i++)
332 {
333 dword val = *(dword*)&buffer[i];
334 if (val >= oldva && val <= (oldva + 3))
335 {
336 *(dword*)&buffer[i] = newva + (val - oldva);
337 if (verbose)
338 std::cout << " "
339 << std::hex << std::showbase << std::setw(10)
340 << std::setfill('0') << std::internal
341 << (imgbase + textsection.virtual_address + i)
342 << ": "
343 << std::hex << std::showbase << std::setw(10)
344 << std::setfill('0') << std::internal
345 << val
346 << " -> "
347 << std::hex << std::showbase << std::setw(10)
348 << std::setfill('0') << std::internal
349 << (newva + (val - oldva)) << std::endl;
350 }
351 }
352
353 // Write the relocated code section data.
354 if (!shared::write_file(updatername, buffer, false, textsection.raw_address,
355 buffer.size()))
356 {
357 std::cerr << "Failed to write the relocated code section to the"
358 " updater executable." << std::endl;
359 return 17;
360 }
361 } //if (size < buffer.size())
362 else
363 {
364 // Yes, overwrite the existing firmware archive.
365 if (verbose)
366 std::cout << "[*] Overwriting existing firmware archive..."
367 << std::endl;
368
369 shared::bytes archive_size(sizeof(dword));
370 *(dword*)&archive_size[0] = buffer.size();
371
372 if (!shared::write_file(updatername, archive_size, false, offset_pa,
373 archive_size.size()))
374 {
375 std::cerr << "Failed to write archive size to the updater"
376 " executable." << std::endl;
377 return 18;
378 }
379
380 if (!shared::write_file(updatername, buffer, false,
381 offset_pa+archive_size.size(), buffer.size()))
382 {
383 std::cerr << "Failed to write the new archive to the updater"
384 " exectuable." << std::endl;
385 return 19;
386 }
387 }
388
389 return 0;
390}
391
392int main(int argc, char* argv[])
393{
394 try
395 {
396 return process_arguments(argc, argv);
397 }
398 catch (const std::exception& xcpt)
399 {
400 std::cerr << "Exception caught: " << xcpt.what() << std::endl;
401 return -1;
402 }
403 catch (...)
404 {
405 std::cerr << "Unknown exception caught." << std::endl;
406 return -2;
407 }
408 return -3;
409}
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}