Add support for using a keyfile
This commit is contained in:
parent
60b483c499
commit
ccc0706caa
6 changed files with 89 additions and 22 deletions
|
@ -26,6 +26,7 @@
|
||||||
{
|
{
|
||||||
size_t _length;
|
size_t _length;
|
||||||
OFString *_site;
|
OFString *_site;
|
||||||
|
OFData *_keyfile;
|
||||||
const char *_passphrase;
|
const char *_passphrase;
|
||||||
unsigned char *_output;
|
unsigned char *_output;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
#import "LegacyPasswordGenerator.h"
|
#import "LegacyPasswordGenerator.h"
|
||||||
|
|
||||||
@implementation LegacyPasswordGenerator
|
@implementation LegacyPasswordGenerator
|
||||||
@synthesize site = _site, passphrase = _passphrase, output = _output;
|
@synthesize site = _site, keyfile = _keyfile, passphrase = _passphrase;
|
||||||
|
@synthesize output = _output;
|
||||||
|
|
||||||
+ (instancetype)generator
|
+ (instancetype)generator
|
||||||
{
|
{
|
||||||
|
@ -55,6 +56,9 @@
|
||||||
- (void)derivePassword
|
- (void)derivePassword
|
||||||
{
|
{
|
||||||
OFSHA256Hash *siteHash = [OFSHA256Hash cryptoHash];
|
OFSHA256Hash *siteHash = [OFSHA256Hash cryptoHash];
|
||||||
|
size_t passphraseLength, combinedPassphraseLength;
|
||||||
|
char *combinedPassphrase;
|
||||||
|
|
||||||
[siteHash updateWithBuffer: [_site UTF8String]
|
[siteHash updateWithBuffer: [_site UTF8String]
|
||||||
length: [_site UTF8StringLength]];
|
length: [_site UTF8StringLength]];
|
||||||
|
|
||||||
|
@ -65,9 +69,32 @@
|
||||||
|
|
||||||
_output = [self allocMemoryWithSize: _length + 1];
|
_output = [self allocMemoryWithSize: _length + 1];
|
||||||
|
|
||||||
|
passphraseLength = combinedPassphraseLength = strlen(_passphrase);
|
||||||
|
if (_keyfile != nil) {
|
||||||
|
if (SIZE_MAX - combinedPassphraseLength < [_keyfile count])
|
||||||
|
@throw [OFOutOfRangeException exception];
|
||||||
|
|
||||||
|
combinedPassphraseLength += [_keyfile count];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((combinedPassphrase = malloc(combinedPassphraseLength)) == NULL)
|
||||||
|
@throw [OFOutOfMemoryException
|
||||||
|
exceptionWithRequestedSize: combinedPassphraseLength];
|
||||||
|
@try {
|
||||||
|
memcpy(combinedPassphrase, _passphrase, passphraseLength);
|
||||||
|
|
||||||
|
if (_keyfile != nil)
|
||||||
|
memcpy(combinedPassphrase + passphraseLength,
|
||||||
|
[_keyfile items], [_keyfile count]);
|
||||||
|
|
||||||
of_scrypt(8, 524288, 2, [siteHash digest],
|
of_scrypt(8, 524288, 2, [siteHash digest],
|
||||||
[[siteHash class] digestSize], _passphrase, strlen(_passphrase),
|
[[siteHash class] digestSize], combinedPassphrase,
|
||||||
_output, _length);
|
combinedPassphraseLength, _output, _length);
|
||||||
|
} @finally {
|
||||||
|
of_explicit_memset(combinedPassphrase, 0,
|
||||||
|
combinedPassphraseLength);
|
||||||
|
free(combinedPassphrase);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This has a bias, however, this is what scrypt-genpass does and the
|
* This has a bias, however, this is what scrypt-genpass does and the
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
{
|
{
|
||||||
size_t _length;
|
size_t _length;
|
||||||
OFString *_site;
|
OFString *_site;
|
||||||
|
OFData *_keyfile;
|
||||||
const char *_passphrase;
|
const char *_passphrase;
|
||||||
unsigned char *_output;
|
unsigned char *_output;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
#import "NewPasswordGenerator.h"
|
#import "NewPasswordGenerator.h"
|
||||||
|
|
||||||
@implementation NewPasswordGenerator
|
@implementation NewPasswordGenerator
|
||||||
@synthesize length = _length, site = _site, passphrase = _passphrase;
|
@synthesize length = _length, site = _site, keyfile = _keyfile;
|
||||||
@synthesize output = _output;
|
@synthesize passphrase = _passphrase, output = _output;
|
||||||
|
|
||||||
+ (instancetype)generator
|
+ (instancetype)generator
|
||||||
{
|
{
|
||||||
|
@ -43,6 +43,9 @@
|
||||||
- (void)derivePassword
|
- (void)derivePassword
|
||||||
{
|
{
|
||||||
OFSHA384Hash *siteHash = [OFSHA384Hash cryptoHash];
|
OFSHA384Hash *siteHash = [OFSHA384Hash cryptoHash];
|
||||||
|
size_t passphraseLength, combinedPassphraseLength;
|
||||||
|
char *combinedPassphrase;
|
||||||
|
|
||||||
[siteHash updateWithBuffer: [_site UTF8String]
|
[siteHash updateWithBuffer: [_site UTF8String]
|
||||||
length: [_site UTF8StringLength]];
|
length: [_site UTF8StringLength]];
|
||||||
|
|
||||||
|
@ -53,9 +56,32 @@
|
||||||
|
|
||||||
_output = [self allocMemoryWithSize: _length + 1];
|
_output = [self allocMemoryWithSize: _length + 1];
|
||||||
|
|
||||||
|
passphraseLength = combinedPassphraseLength = strlen(_passphrase);
|
||||||
|
if (_keyfile != nil) {
|
||||||
|
if (SIZE_MAX - combinedPassphraseLength < [_keyfile count])
|
||||||
|
@throw [OFOutOfRangeException exception];
|
||||||
|
|
||||||
|
combinedPassphraseLength += [_keyfile count];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((combinedPassphrase = malloc(combinedPassphraseLength)) == NULL)
|
||||||
|
@throw [OFOutOfMemoryException
|
||||||
|
exceptionWithRequestedSize: combinedPassphraseLength];
|
||||||
|
@try {
|
||||||
|
memcpy(combinedPassphrase, _passphrase, passphraseLength);
|
||||||
|
|
||||||
|
if (_keyfile != nil)
|
||||||
|
memcpy(combinedPassphrase + passphraseLength,
|
||||||
|
[_keyfile items], [_keyfile count]);
|
||||||
|
|
||||||
of_scrypt(8, 524288, 2, [siteHash digest],
|
of_scrypt(8, 524288, 2, [siteHash digest],
|
||||||
[[siteHash class] digestSize], _passphrase, strlen(_passphrase),
|
[[siteHash class] digestSize], combinedPassphrase,
|
||||||
_output, _length);
|
combinedPassphraseLength, _output, _length);
|
||||||
|
} @finally {
|
||||||
|
of_explicit_memset(combinedPassphrase, 0,
|
||||||
|
combinedPassphraseLength);
|
||||||
|
free(combinedPassphrase);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _length; i++)
|
for (size_t i = 0; i < _length; i++)
|
||||||
_output[i] =
|
_output[i] =
|
||||||
|
|
|
@ -23,10 +23,11 @@
|
||||||
#import <ObjFW/ObjFW.h>
|
#import <ObjFW/ObjFW.h>
|
||||||
|
|
||||||
@protocol PasswordGenerator
|
@protocol PasswordGenerator
|
||||||
@property size_t length;
|
@property (nonatomic) size_t length;
|
||||||
@property (nonatomic, copy) OFString *site;
|
@property (copy, nonatomic) OFString *site;
|
||||||
@property const char *passphrase;
|
@property (retain, nonatomic) OFData *keyfile;
|
||||||
@property (readonly) unsigned char *output;
|
@property (nonatomic) const char *passphrase;
|
||||||
|
@property (readonly, nonatomic) unsigned char *output;
|
||||||
|
|
||||||
+ (instancetype)generator;
|
+ (instancetype)generator;
|
||||||
- (void)derivePassword;
|
- (void)derivePassword;
|
||||||
|
|
|
@ -39,6 +39,7 @@ showHelp(OFStream *output, bool verbose)
|
||||||
@"\n"
|
@"\n"
|
||||||
@"Options:\n"
|
@"Options:\n"
|
||||||
@" -h --help Show this help\n"
|
@" -h --help Show this help\n"
|
||||||
|
@" -k --keyfile Use the specified key file\n"
|
||||||
@" -l --length Length for the derived password\n"
|
@" -l --length Length for the derived password\n"
|
||||||
@" -L --legacy Use the legacy algorithm "
|
@" -L --legacy Use the legacy algorithm "
|
||||||
@"(compatible with scrypt-genpass)\n"
|
@"(compatible with scrypt-genpass)\n"
|
||||||
|
@ -48,10 +49,11 @@ showHelp(OFStream *output, bool verbose)
|
||||||
@implementation ScryptPWGen
|
@implementation ScryptPWGen
|
||||||
- (void)applicationDidFinishLaunching
|
- (void)applicationDidFinishLaunching
|
||||||
{
|
{
|
||||||
OFString *lengthStr;
|
OFString *keyfilePath, *lengthString;
|
||||||
const of_options_parser_option_t options[] = {
|
const of_options_parser_option_t options[] = {
|
||||||
{ 'h', @"help", 0, NULL, NULL },
|
{ '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 },
|
{ 'L', @"legacy", 0, &_legacy, NULL },
|
||||||
{ 'r', @"repeat", 0, &_repeat, NULL },
|
{ 'r', @"repeat", 0, &_repeat, NULL },
|
||||||
{ '\0', nil, 0, NULL, NULL }
|
{ '\0', nil, 0, NULL, NULL }
|
||||||
|
@ -59,8 +61,10 @@ showHelp(OFStream *output, bool verbose)
|
||||||
OFOptionsParser *optionsParser =
|
OFOptionsParser *optionsParser =
|
||||||
[OFOptionsParser parserWithOptions: options];
|
[OFOptionsParser parserWithOptions: options];
|
||||||
of_unichar_t option;
|
of_unichar_t option;
|
||||||
char *passphrase;
|
OFMutableData *keyfile = nil;
|
||||||
OFString *prompt;
|
OFString *prompt;
|
||||||
|
const char *promptCString;
|
||||||
|
char *passphrase;
|
||||||
|
|
||||||
while ((option = [optionsParser nextOption]) != '\0') {
|
while ((option = [optionsParser nextOption]) != '\0') {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
|
@ -112,11 +116,11 @@ showHelp(OFStream *output, bool verbose)
|
||||||
: [NewPasswordGenerator generator]);
|
: [NewPasswordGenerator generator]);
|
||||||
generator.site = [[optionsParser remainingArguments] firstObject];
|
generator.site = [[optionsParser remainingArguments] firstObject];
|
||||||
|
|
||||||
if (lengthStr != nil) {
|
if (lengthString != nil) {
|
||||||
bool invalid = false;
|
bool invalid = false;
|
||||||
|
|
||||||
@try {
|
@try {
|
||||||
generator.length = (size_t)[lengthStr decimalValue];
|
generator.length = (size_t)[lengthString decimalValue];
|
||||||
} @catch (OFInvalidFormatException *e) {
|
} @catch (OFInvalidFormatException *e) {
|
||||||
invalid = true;
|
invalid = true;
|
||||||
} @catch (OFOutOfRangeException *e) {
|
} @catch (OFOutOfRangeException *e) {
|
||||||
|
@ -126,17 +130,20 @@ showHelp(OFStream *output, bool verbose)
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
[of_stderr writeFormat:
|
[of_stderr writeFormat:
|
||||||
@"%@: Invalid length: %@\n",
|
@"%@: Invalid length: %@\n",
|
||||||
[OFApplication programName], lengthStr];
|
[OFApplication programName], lengthString];
|
||||||
|
|
||||||
[OFApplication terminateWithStatus: 1];
|
[OFApplication terminateWithStatus: 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prompt = [OFString stringWithFormat: @"Passphrase for site \"%@\": ",
|
prompt = [OFString stringWithFormat: @"Passphrase for site \"%@\": ",
|
||||||
generator.site];
|
generator.site];
|
||||||
passphrase = getpass(
|
promptCString = [prompt cStringWithEncoding: [OFLocalization encoding]];
|
||||||
[prompt cStringWithEncoding: [OFLocalization encoding]]);
|
|
||||||
|
if (keyfilePath != nil)
|
||||||
|
keyfile = [OFMutableData dataWithContentsOfFile: keyfilePath];
|
||||||
|
|
||||||
|
passphrase = getpass(promptCString);
|
||||||
@try {
|
@try {
|
||||||
if (_repeat) {
|
if (_repeat) {
|
||||||
char *passphraseCopy = of_strdup(passphrase);
|
char *passphraseCopy = of_strdup(passphrase);
|
||||||
|
@ -166,6 +173,7 @@ showHelp(OFStream *output, bool verbose)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generator.keyfile = keyfile;
|
||||||
generator.passphrase = passphrase;
|
generator.passphrase = passphrase;
|
||||||
|
|
||||||
[generator derivePassword];
|
[generator derivePassword];
|
||||||
|
@ -180,6 +188,9 @@ showHelp(OFStream *output, bool verbose)
|
||||||
}
|
}
|
||||||
} @finally {
|
} @finally {
|
||||||
of_explicit_memset(passphrase, 0, strlen(passphrase));
|
of_explicit_memset(passphrase, 0, strlen(passphrase));
|
||||||
|
|
||||||
|
if (keyfile != nil)
|
||||||
|
of_explicit_memset([keyfile items], 0, [keyfile count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[OFApplication terminate];
|
[OFApplication terminate];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue