#include #include #import "ScryptPWGen.h" OF_APPLICATION_DELEGATE(ScryptPWGen) static void showHelp(OFStream *output, bool verbose) { [output writeFormat: @"Usage: %@ [-hlr] site\n", [OFApplication programName]]; if (verbose) [output writeString: @"\n" @"Options:\n" @" -h --help Show this help\n" @" -l --length Length for the derived password\n" @" -r --repeat Repeat input\n"]; } @implementation ScryptPWGen - (void)applicationDidFinishLaunching { OFString *lengthStr; const of_options_parser_option_t options[] = { { 'h', @"help", 0, NULL, NULL }, { 'l', @"length", 1, NULL, &lengthStr }, { 'r', @"repeat", 0, &_repeat, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = [OFOptionsParser parserWithOptions: options]; of_unichar_t option; OFString *site, *prompt; char *passphrase; OFSHA256Hash *siteHash; unsigned char *output; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case 'h': showHelp(of_stdout, true); [OFApplication terminate]; break; case ':': if (optionsParser.lastLongOption != nil) [of_stderr writeFormat: @"%@: Argument for option --%@ missing\n", [OFApplication programName], optionsParser.lastLongOption]; else [of_stderr writeFormat: @"%@: Argument for option -%C missing\n", [OFApplication programName], optionsParser.lastOption]; [OFApplication terminateWithStatus: 1]; break; case '?': if (optionsParser.lastLongOption != nil) [of_stderr writeFormat: @"%@: Unknown option: --%@\n", [OFApplication programName], optionsParser.lastLongOption]; else [of_stderr writeFormat: @"%@: Unknown option: -%C\n", [OFApplication programName], optionsParser.lastOption]; [OFApplication terminateWithStatus: 1]; break; } } if (lengthStr != nil) { @try { _length = (size_t)[lengthStr decimalValue]; if (_length < 3) @throw [OFInvalidFormatException exception]; } @catch (OFInvalidFormatException *e) { [of_stderr writeFormat: @"%@: Invalid length: %@\n", [OFApplication programName], lengthStr]; [OFApplication terminateWithStatus: 1]; } } else _length = 16; if ([[optionsParser remainingArguments] count] != 1) { showHelp(of_stderr, false); [OFApplication terminateWithStatus: 1]; } site = [[optionsParser remainingArguments] firstObject]; siteHash = [OFSHA256Hash cryptoHash]; [siteHash updateWithBuffer: [site UTF8String] length: [site UTF8StringLength]]; prompt = [OFString stringWithFormat: @"Passphrase for site \"%@\": ", site]; passphrase = getpass([prompt cStringWithEncoding: [OFSystemInfo native8BitEncoding]]); output = [self allocMemoryWithSize: _length + 1]; of_scrypt(8, 524288, 2, [siteHash digest], [[siteHash class] digestSize], passphrase, strlen(passphrase), output, _length); of_explicit_memset(passphrase, 0, strlen(passphrase)); /* * This has a bias, but is what scrypt-genpass does. This should be * compatible to passwords generated by scrypt-genpass for now to allow * an easy migration. * * This will be replaced with something better later on and the current * code only available in legacy mode (which can be enabled using a * flag). */ output[0] = "abcdefghijklmnopqrstuvwxyz"[output[0] % 26]; output[1] = "0123456789"[output[1] % 10]; output[2] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[output[2] % 26]; for (size_t i = 3; i < _length; i++) output[i] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"[output[i] % (26 + 26 + 10)]; output[_length] = '\n'; [of_stdout writeBuffer: output length: _length + 1]; of_explicit_memset(output, 0, _length + 1); [OFApplication terminate]; } @end