From 9e18d0deaf44db69308c5f78a13cc877a6948887 Mon Sep 17 00:00:00 2001 From: Jonathan Schleifer Date: Sun, 2 Oct 2016 00:37:43 +0200 Subject: [PATCH] Initial commit --- Makefile | 2 + ScryptPWGen.h | 8 +++ ScryptPWGen.m | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 Makefile create mode 100644 ScryptPWGen.h create mode 100644 ScryptPWGen.m diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e0163d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +all: + @objfw-compile -o scrypt-pwgen *.m diff --git a/ScryptPWGen.h b/ScryptPWGen.h new file mode 100644 index 0000000..55bed65 --- /dev/null +++ b/ScryptPWGen.h @@ -0,0 +1,8 @@ +#import + +@interface ScryptPWGen: OFObject +{ + size_t _length; + bool _repeat; +} +@end diff --git a/ScryptPWGen.m b/ScryptPWGen.m new file mode 100644 index 0000000..7bc45ed --- /dev/null +++ b/ScryptPWGen.m @@ -0,0 +1,148 @@ +#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