@@ -37,32 +37,36 @@ if (verbose) [output writeString: @"\n" @"Options:\n" @" -h --help Show this help\n" + @" -k --keyfile Use the specified key file\n" @" -l --length Length for the derived password\n" @" -L --legacy Use the legacy algorithm " @"(compatible with scrypt-genpass)\n" @" -r --repeat Repeat input\n"]; } @implementation ScryptPWGen - (void)applicationDidFinishLaunching { - OFString *lengthStr; + OFString *keyfilePath, *lengthString; const of_options_parser_option_t options[] = { { 'h', @"help", 0, NULL, NULL }, - { 'l', @"length", 1, NULL, &lengthStr }, + { 'k', @"keyfile", 1, NULL, &keyfilePath }, + { 'l', @"length", 1, NULL, &lengthString }, { 'L', @"legacy", 0, &_legacy, NULL }, { 'r', @"repeat", 0, &_repeat, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = [OFOptionsParser parserWithOptions: options]; of_unichar_t option; - char *passphrase; + OFMutableData *keyfile = nil; OFString *prompt; + const char *promptCString; + char *passphrase; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case 'h': showHelp(of_stdout, true); @@ -110,35 +114,38 @@ id generator = (_legacy ? [LegacyPasswordGenerator generator] : [NewPasswordGenerator generator]); generator.site = [[optionsParser remainingArguments] firstObject]; - if (lengthStr != nil) { + if (lengthString != nil) { bool invalid = false; @try { - generator.length = (size_t)[lengthStr decimalValue]; + generator.length = (size_t)[lengthString decimalValue]; } @catch (OFInvalidFormatException *e) { invalid = true; } @catch (OFOutOfRangeException *e) { invalid = true; } if (invalid) { [of_stderr writeFormat: @"%@: Invalid length: %@\n", - [OFApplication programName], lengthStr]; + [OFApplication programName], lengthString]; [OFApplication terminateWithStatus: 1]; } } - prompt = [OFString stringWithFormat: @"Passphrase for site \"%@\": ", generator.site]; - passphrase = getpass( - [prompt cStringWithEncoding: [OFLocalization encoding]]); + promptCString = [prompt cStringWithEncoding: [OFLocalization encoding]]; + + if (keyfilePath != nil) + keyfile = [OFMutableData dataWithContentsOfFile: keyfilePath]; + + passphrase = getpass(promptCString); @try { if (_repeat) { char *passphraseCopy = of_strdup(passphrase); if (passphraseCopy == NULL) @@ -164,10 +171,11 @@ strlen(passphraseCopy)); free(passphraseCopy); } } + generator.keyfile = keyfile; generator.passphrase = passphrase; [generator derivePassword]; @try { [of_stdout writeBuffer: generator.output @@ -178,10 +186,13 @@ of_explicit_memset(generator.output, 0, generator.length); } } @finally { of_explicit_memset(passphrase, 0, strlen(passphrase)); + + if (keyfile != nil) + of_explicit_memset([keyfile items], 0, [keyfile count]); } [OFApplication terminate]; } @end