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