xref: /netbsd-src/external/bsd/elftosb/dist/keygen/keygen.cpp (revision 616728154accb2da0d5a0126e1280ca29f8ba569)
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 	 */
keygen(int argc,char * argv[])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 	 */
~keygen()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 	 */
processOptions()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 	 */
printUsage(Options & options)177 	void printUsage(Options & options)
178 	{
179 		options.usage(std::cout, "key-files...");
180 		printf("%s", k_usageText);
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 	 */
run()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 	 */
setVerboseLogging()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 	 */
generateKeyFile(const std::string & path)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 	 */
dumpKey(const AESKey<128> & key)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 	 */
logHexArray(Logger::log_level_t level,const uint8_t * bytes,unsigned count)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  */
main(int argc,char * argv[],char * envp[])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 
347