]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/elftosb/keygen/keygen.cpp
merged tx6dl-devel into denx master branch
[karo-tx-uboot.git] / tools / elftosb / keygen / keygen.cpp
1 /*
2  * File:        keygen.cpp
3  *
4  * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
5  * See included license file for license details.
6  */
7
8 #include "stdafx.h"
9 #include <iostream>
10 #include <fstream>
11 #include <sstream>
12 #include <stdlib.h>
13 #include <stdexcept>
14 #include <string>
15 #include <vector>
16 #include "options.h"
17 #include "smart_ptr.h"
18 #include "Logging.h"
19 #include "AESKey.h"
20
21 //! The tool's name.
22 const char k_toolName[] = "keygen";
23
24 //! Current version number for the tool.
25 const char k_version[] = "1.0";
26
27 //! Copyright string.
28 const char k_copyright[] = "Copyright (c) 2006-2009 Freescale Semiconductor, Inc.\nAll rights reserved.";
29
30 //! Definition of command line options.
31 static const char * k_optionsDefinition[] = {
32         "?|help",
33         "v|version",
34         "q|quiet",
35         "V|verbose",
36         "n:number <int>",
37         NULL
38 };
39
40 //! Help string.
41 const char k_usageText[] = "\nOptions:\n\
42   -?/--help                    Show this help\n\
43   -v/--version                 Display tool version\n\
44   -q/--quiet                   Output only warnings and errors\n\
45   -V/--verbose                 Print extra detailed log information\n\
46   -n/--number <int>            Number of keys to generate per file (default=1)\n\n";
47
48 //! An array of strings.
49 typedef std::vector<std::string> string_vector_t;
50
51 // prototypes
52 int main(int argc, char* argv[], char* envp[]);
53
54 /*!
55  * \brief Class that encapsulates the keygen interface.
56  *
57  * A single global logger instance is created during object construction. It is
58  * never freed because we need it up to the last possible minute, when an
59  * exception could be thrown.
60  */
61 class keygen
62 {
63 protected:
64         int m_argc;                                                     //!< Number of command line arguments.
65         char ** m_argv;                                         //!< String value for each command line argument.
66         StdoutLogger * m_logger;                        //!< Singleton logger instance.
67         string_vector_t m_positionalArgs;       //!< Arguments coming after explicit options.
68         bool m_isVerbose;                                       //!< Whether the verbose flag was turned on.
69         int m_keyCount;                                         //!< Number of keys to generate.
70         
71 public:
72         /*!
73          * Constructor.
74          *
75          * Creates the singleton logger instance.
76          */
77         keygen(int argc, char * argv[])
78         :       m_argc(argc),
79                 m_argv(argv),
80                 m_logger(0),
81                 m_positionalArgs(),
82                 m_isVerbose(false),
83                 m_keyCount(1)
84         {
85                 // create logger instance
86                 m_logger = new StdoutLogger();
87                 m_logger->setFilterLevel(Logger::INFO);
88                 Log::setLogger(m_logger);
89         }
90         
91         /*!
92          * Destructor.
93          */
94         ~keygen()
95         {
96         }
97         
98         /*!
99          * Reads the command line options passed into the constructor.
100          *
101          * This method can return a return code to its caller, which will cause the
102          * tool to exit immediately with that return code value. Normally, though, it
103          * will return -1 to signal that the tool should continue to execute and
104          * all options were processed successfully.
105          *
106          * The Options class is used to parse command line options. See
107          * #k_optionsDefinition for the list of options and #k_usageText for the
108          * descriptive help for each option.
109          *
110          * \retval -1 The options were processed successfully. Let the tool run normally.
111          * \return A zero or positive result is a return code value that should be
112          *              returned from the tool as it exits immediately.
113          */
114         int processOptions()
115         {
116                 Options options(*m_argv, k_optionsDefinition);
117                 OptArgvIter iter(--m_argc, ++m_argv);
118                 
119                 // process command line options
120                 int optchar;
121                 const char * optarg;
122                 while (optchar = options(iter, optarg))
123                 {
124                         switch (optchar)
125                         {
126                                 case '?':
127                                         printUsage(options);
128                                         return 0;
129                                 
130                                 case 'v':
131                                         printf("%s %s\n%s\n", k_toolName, k_version, k_copyright);
132                                         return 0;
133                                         
134                                 case 'd':
135                                         Log::getLogger()->setFilterLevel(Logger::DEBUG);
136                                         break;
137                                         
138                                 case 'q':
139                                         Log::getLogger()->setFilterLevel(Logger::WARNING);
140                                         break;
141                                         
142                                 case 'V':
143                                         m_isVerbose = true;
144                                         break;
145                                 
146                                 case 'n':
147                                         m_keyCount = strtol(optarg, NULL, 0);
148                                         break;
149                                 
150                                 default:
151                                         Log::log(Logger::ERROR, "error: unrecognized option\n\n");
152                                         printUsage(options);
153                                         return 1;
154                         }
155                 }
156                 
157                 // handle positional args
158                 if (iter.index() < m_argc)
159                 {
160 //                      Log::SetOutputLevel leveler(Logger::DEBUG);
161 //                      Log::log("positional args:\n");
162                         int i;
163                         for (i = iter.index(); i < m_argc; ++i)
164                         {
165 //                              Log::log("%d: %s\n", i - iter.index(), m_argv[i]);
166                                 m_positionalArgs.push_back(m_argv[i]);
167                         }
168                 }
169                 
170                 // all is well
171                 return -1;
172         }
173
174         /*!
175          * Prints help for the tool.
176          */
177         void printUsage(Options & options)
178         {
179                 options.usage(std::cout, "key-files...");
180                 printf(k_usageText, k_toolName);
181         }
182         
183         /*!
184          * Core of the tool. Calls processOptions() to handle command line options
185          * before performing the real work the tool does.
186          */
187         int run()
188         {
189                 try
190                 {
191                         // read command line options
192                         int result;
193                         if ((result = processOptions()) != -1)
194                         {
195                                 return result;
196                         }
197                         
198                         // set verbose logging
199                         setVerboseLogging();
200                         
201                         // make sure a file was provided
202                         if (m_positionalArgs.size() < 1)
203                         {
204                                 throw std::runtime_error("no output file path was provided");
205                         }
206                         
207                         // generate key files
208                         string_vector_t::const_iterator it = m_positionalArgs.begin();
209                         for (; it != m_positionalArgs.end(); ++it)
210                         {
211                                 generateKeyFile(*it);
212                         }
213                 }
214                 catch (std::exception & e)
215                 {
216                         Log::log(Logger::ERROR, "error: %s\n", e.what());
217                         return 1;
218                 }
219                 catch (...)
220                 {
221                         Log::log(Logger::ERROR, "error: unexpected exception\n");
222                         return 1;
223                 }
224                 
225                 return 0;
226         }
227         
228         /*!
229          * \brief Turns on verbose logging.
230          */
231         void setVerboseLogging()
232         {
233                 if (m_isVerbose)
234                 {
235                         // verbose only affects the INFO and DEBUG filter levels
236                         // if the user has selected quiet mode, it overrides verbose
237                         switch (Log::getLogger()->getFilterLevel())
238                         {
239                                 case Logger::INFO:
240                                         Log::getLogger()->setFilterLevel(Logger::INFO2);
241                                         break;
242                                 case Logger::DEBUG:
243                                         Log::getLogger()->setFilterLevel(Logger::DEBUG2);
244                                         break;
245                         }
246                 }
247         }
248         
249         /*!
250          * \brief Opens the file at \a path and writes a random key file.
251          *
252          * Each key file will have #m_keyCount number of keys written into it,
253          * each on a line by itself.
254          */
255         void generateKeyFile(const std::string & path)
256         {
257                 std::ofstream outputStream(path.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
258                 if (outputStream.is_open())
259                 {
260                         int i;
261                         for (i = 0; i < m_keyCount; ++i)
262                         {
263                                 AESKey<128> key;
264                                 key.randomize();
265                                 key.writeToStream(outputStream);
266                                 
267                                 // put a newline after the key
268                                 outputStream.write("\n", 1);
269                                 
270                                 // dump it
271                                 dumpKey(key);
272                         }
273                         
274                         Log::log(Logger::INFO, "wrote key file %s\n", path.c_str());
275                 }
276                 else
277                 {
278                         throw std::runtime_error("could not open output file");
279                 }
280         }
281         
282         /*!
283          * \brief Write the value of each byte of the \a key to the log.
284          */
285         void dumpKey(const AESKey<128> & key)
286         {
287                 // dump key bytes
288                 Log::log(Logger::INFO2, "key bytes: ");
289                 AESKey<128>::key_t the_key;
290                 key.getKey(&the_key);
291                 int q;
292                 for (q=0; q<16; q++)
293                 {
294                         Log::log(Logger::INFO2, "%02x ", the_key[q]);
295                 }
296                 Log::log(Logger::INFO2, "\n");
297         }
298         
299         /*!
300          * \brief Log an array of bytes as hex.
301          */
302         void logHexArray(Logger::log_level_t level, const uint8_t * bytes, unsigned count)
303         {
304                 Log::SetOutputLevel leveler(level);
305 //              Log::log("    ");
306                 unsigned i;
307                 for (i = 0; i < count; ++i, ++bytes)
308                 {
309                         if ((i % 16 == 0) && (i < count - 1))
310                         {
311                                 if (i != 0)
312                                 {
313                                         Log::log("\n");
314                                 }
315                                 Log::log("    0x%04x: ", i);
316                         }
317                         Log::log("%02x ", *bytes & 0xff);
318                 }
319                 
320                 Log::log("\n");
321         }
322
323 };
324
325 /*!
326  * Main application entry point. Creates an sbtool instance and lets it take over.
327  */
328 int main(int argc, char* argv[], char* envp[])
329 {
330         try
331         {
332                 return keygen(argc, argv).run();
333         }
334         catch (...)
335         {
336                 Log::log(Logger::ERROR, "error: unexpected exception\n");
337                 return 1;
338         }
339
340         return 0;
341 }
342
343
344
345
346