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