WIP - Initial complete C implementation that's still buggy and generates broken passwords, yay.
This commit is contained in:
parent
c4dca14800
commit
2bc357cee6
@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash -e
|
||||
gcc types.c -o types.o
|
||||
gcc -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"types.o" -l"crypto" -L"lib/scrypt" mpw.c -o mpw
|
||||
# Run with -DDEBUG to enable trace-level output.
|
||||
|
||||
gcc -c types.c -o types.o "$@"
|
||||
gcc -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"types.o" -l"crypto" -L"." -L"lib/scrypt" mpw.c -o mpw "$@"
|
||||
|
@ -63,6 +63,7 @@ int main(int argc, char *const argv[]) {
|
||||
const char *userName = getenv( MP_env_username );
|
||||
const char *masterPassword = NULL;
|
||||
const char *siteName = NULL;
|
||||
MPElementType siteType = MPElementTypeGeneratedLong;
|
||||
const char *siteTypeString = getenv( MP_env_sitetype );
|
||||
uint32_t siteCounter = 1;
|
||||
const char *siteCounterString = getenv( MP_env_sitecounter );
|
||||
@ -83,16 +84,16 @@ int main(int argc, char *const argv[]) {
|
||||
case '?':
|
||||
switch (optopt) {
|
||||
case 'u':
|
||||
fprintf (stderr, "Missing user name to option: -%c\n", optopt);
|
||||
fprintf(stderr, "Missing user name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 't':
|
||||
fprintf (stderr, "Missing type name to option: -%c\n", optopt);
|
||||
fprintf(stderr, "Missing type name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 'c':
|
||||
fprintf (stderr, "Missing counter value to option: -%c\n", optopt);
|
||||
fprintf(stderr, "Missing counter value to option: -%c\n", optopt);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unknown option: -%c\n", optopt);
|
||||
fprintf(stderr, "Unknown option: -%c\n", optopt);
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
@ -103,29 +104,36 @@ int main(int argc, char *const argv[]) {
|
||||
|
||||
// Convert and validate input.
|
||||
if (!userName) {
|
||||
fprintf (stderr, "Missing user name.\n");
|
||||
fprintf(stderr, "Missing user name.\n");
|
||||
return 1;
|
||||
}
|
||||
trc("userName: %s\n", userName);
|
||||
if (!siteName) {
|
||||
fprintf (stderr, "Missing site name.\n");
|
||||
fprintf(stderr, "Missing site name.\n");
|
||||
return 1;
|
||||
}
|
||||
trc("siteName: %s\n", siteName);
|
||||
if (siteCounterString)
|
||||
siteCounter = atoi( siteCounterString );
|
||||
if (siteCounter < 1) {
|
||||
fprintf (stderr, "Invalid site counter: %d\n", siteCounter);
|
||||
fprintf(stderr, "Invalid site counter: %d\n", siteCounter);
|
||||
return 1;
|
||||
}
|
||||
trc("siteCounter: %d\n", siteCounter);
|
||||
if (siteTypeString)
|
||||
siteType = TypeWithName( siteTypeString );
|
||||
trc("siteType: %d (%s)\n", siteType, siteTypeString);
|
||||
|
||||
// Read the master password.
|
||||
char *mpwConfigPath = homedir(".mpw");
|
||||
if (!mpwConfigPath) {
|
||||
fprintf (stderr, "Couldn't resolve path for configuration file: %d\n", errno);
|
||||
fprintf(stderr, "Couldn't resolve path for configuration file: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
trc("mpwConfigPath: %s\n", mpwConfigPath);
|
||||
FILE *mpwConfig = fopen(mpwConfigPath, "r");
|
||||
if (!mpwConfig) {
|
||||
fprintf (stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
|
||||
fprintf(stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
|
||||
return 1;
|
||||
}
|
||||
free(mpwConfigPath);
|
||||
@ -138,25 +146,26 @@ int main(int argc, char *const argv[]) {
|
||||
break;
|
||||
}
|
||||
if (!masterPassword) {
|
||||
fprintf (stderr, "Missing master password for user: %s\n", userName);
|
||||
fprintf(stderr, "Missing master password for user: %s\n", userName);
|
||||
return 1;
|
||||
}
|
||||
trc("masterPassword: %s\n", masterPassword);
|
||||
|
||||
// Calculate the master key.
|
||||
uint8_t *masterKey = malloc( MP_dkLen );
|
||||
if (!masterKey) {
|
||||
fprintf (stderr, "Could not allocate master key: %d\n", errno);
|
||||
fprintf(stderr, "Could not allocate master key: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
const uint32_t n_userNameLength = htonl(strlen(userName));
|
||||
char *masterKeySalt = NULL;
|
||||
size_t masterKeySaltLength = asprintf(&masterKeySalt, "com.lyndir.masterpassword%s%s", (const char *) &n_userNameLength, userName);
|
||||
if (!masterKeySalt) {
|
||||
fprintf (stderr, "Could not allocate master key salt: %d\n", errno);
|
||||
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
if (crypto_scrypt( (const uint8_t *)masterPassword, strlen(masterPassword), (const uint8_t *)masterKeySalt, masterKeySaltLength, MP_N, MP_r, MP_p, masterKey, MP_dkLen ) < 0) {
|
||||
fprintf (stderr, "Could not generate master key: %d\n", errno);
|
||||
fprintf(stderr, "Could not generate master key: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
memset(masterKeySalt, 0, masterKeySaltLength);
|
||||
@ -167,7 +176,7 @@ int main(int argc, char *const argv[]) {
|
||||
char *sitePasswordInfo = NULL;
|
||||
size_t sitePasswordInfoLength = asprintf(&sitePasswordInfo, "com.lyndir.masterpassword%s%s%s", (const char *) &n_siteNameLength, siteName, (const char *) &n_siteCounter);
|
||||
if (!sitePasswordInfo) {
|
||||
fprintf (stderr, "Could not allocate site seed: %d\n", errno);
|
||||
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
uint8_t sitePasswordSeed[32];
|
||||
@ -178,15 +187,16 @@ int main(int argc, char *const argv[]) {
|
||||
free(sitePasswordInfo);
|
||||
|
||||
// Determine the cipher.
|
||||
const char *cipher = CipherForType(siteType, sitePasswordSeed);
|
||||
//trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher);
|
||||
const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
|
||||
trc("type %s, cipher: %s\n", siteTypeString, cipher);
|
||||
|
||||
// Encode the password from the seed using the cipher.
|
||||
//NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher.");
|
||||
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
|
||||
for (int c = 0; c < strlen(cipher); ++c)
|
||||
//trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
|
||||
for (int c = 0; c < strlen(cipher); ++c) {
|
||||
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
|
||||
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
|
||||
}
|
||||
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
|
||||
|
||||
// Output the password.
|
||||
|
@ -6,58 +6,116 @@
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "types.h"
|
||||
|
||||
const char *CipherForType(MPElementType type, char seedByte) {
|
||||
const MPElementType TypeWithName(const char *typeName) {
|
||||
char lowerTypeName[strlen(typeName)];
|
||||
strcpy(lowerTypeName, typeName);
|
||||
for (char *tN = lowerTypeName; *tN; ++tN)
|
||||
*tN = tolower(*tN);
|
||||
|
||||
if (0 == strcmp(lowerTypeName, "x") || 0 == strcmp(lowerTypeName, "max") || 0 == strcmp(lowerTypeName, "maximum"))
|
||||
return MPElementTypeGeneratedMaximum;
|
||||
if (0 == strcmp(lowerTypeName, "l") || 0 == strcmp(lowerTypeName, "long"))
|
||||
return MPElementTypeGeneratedLong;
|
||||
if (0 == strcmp(lowerTypeName, "m") || 0 == strcmp(lowerTypeName, "med") || 0 == strcmp(lowerTypeName, "medium"))
|
||||
return MPElementTypeGeneratedMedium;
|
||||
if (0 == strcmp(lowerTypeName, "b") || 0 == strcmp(lowerTypeName, "basic"))
|
||||
return MPElementTypeGeneratedBasic;
|
||||
if (0 == strcmp(lowerTypeName, "s") || 0 == strcmp(lowerTypeName, "short"))
|
||||
return MPElementTypeGeneratedShort;
|
||||
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin"))
|
||||
return MPElementTypeGeneratedPIN;
|
||||
|
||||
fprintf(stderr, "Not a generated type name: %s", lowerTypeName);
|
||||
abort();
|
||||
}
|
||||
|
||||
const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
if (!(type & MPElementTypeClassGenerated)) {
|
||||
fprintf(stderr, "Not a generated type: %d", type);
|
||||
abort();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MPElementTypeGeneratedMaximum:
|
||||
char *ciphers = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
|
||||
case MPElementTypeGeneratedMaximum: {
|
||||
char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
|
||||
return ciphers[seedByte % 2];
|
||||
case MPElementTypeGeneratedLong:
|
||||
char *ciphers = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
|
||||
}
|
||||
case MPElementTypeGeneratedLong: {
|
||||
char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
|
||||
return ciphers[seedByte % 21];
|
||||
case MPElementTypeGeneratedMedium:
|
||||
char *ciphers = { "CvcnoCvc", "CvcCvcno" };
|
||||
}
|
||||
case MPElementTypeGeneratedMedium: {
|
||||
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
|
||||
return ciphers[seedByte % 2];
|
||||
case MPElementTypeGeneratedBasic:
|
||||
char *ciphers = { "aaanaaan", "aannaaan", "aaannaaa" };
|
||||
}
|
||||
case MPElementTypeGeneratedBasic: {
|
||||
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
|
||||
return ciphers[seedByte % 3];
|
||||
case MPElementTypeGeneratedShort:
|
||||
}
|
||||
case MPElementTypeGeneratedShort: {
|
||||
return "Cvcn";
|
||||
case MPElementTypeGeneratedPIN:
|
||||
}
|
||||
case MPElementTypeGeneratedPIN: {
|
||||
return "nnnn";
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown generated type: %d", type);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char CharacterFromClass(char characterClass, char seedByte) {
|
||||
const char CharacterFromClass(char characterClass, uint8_t seedByte) {
|
||||
const char *classCharacters;
|
||||
switch (characterClass) {
|
||||
case 'V':
|
||||
return "AEIOU"[seedByte];
|
||||
case 'C':
|
||||
return "BCDFGHJKLMNPQRSTVWXYZ"[seedByte];
|
||||
case 'v':
|
||||
return "aeiou"[seedByte];
|
||||
case 'c':
|
||||
return "bcdfghjklmnpqrstvwxyz"[seedByte];
|
||||
case 'A':
|
||||
return "AEIOUBCDFGHJKLMNPQRSTVWXYZ"[seedByte];
|
||||
case 'a':
|
||||
return "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz"[seedByte];
|
||||
case 'n':
|
||||
return "0123456789"[seedByte];
|
||||
case 'o':
|
||||
return "@&%?,=[]_:-+*$#!'^~;()/."[seedByte];
|
||||
case 'x':
|
||||
return "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()"[seedByte];
|
||||
case 'V': {
|
||||
classCharacters = "AEIOU";
|
||||
break;
|
||||
}
|
||||
case 'C': {
|
||||
classCharacters = "BCDFGHJKLMNPQRSTVWXYZ";
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
classCharacters = "aeiou";
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
classCharacters = "bcdfghjklmnpqrstvwxyz";
|
||||
break;
|
||||
}
|
||||
case 'A': {
|
||||
classCharacters = "AEIOUBCDFGHJKLMNPQRSTVWXYZ";
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
classCharacters = "0123456789";
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
classCharacters = "@&%?,=[]_:-+*$#!'^~;()/.";
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown character class: %c", characterClass);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unknown character class: %c", characterClass);
|
||||
abort();
|
||||
return classCharacters[seedByte % strlen(classCharacters)];
|
||||
}
|
||||
|
||||
|
@ -6,27 +6,27 @@
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPElementContentType) {
|
||||
typedef enum {
|
||||
MPElementContentTypePassword,
|
||||
MPElementContentTypeNote,
|
||||
MPElementContentTypePicture,
|
||||
};
|
||||
} MPElementContentType;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPElementTypeClass) {
|
||||
typedef enum {
|
||||
/** Generate the password. */
|
||||
MPElementTypeClassGenerated = 1 << 4,
|
||||
MPElementTypeClassGenerated = 1 << 4,
|
||||
/** Store the password. */
|
||||
MPElementTypeClassStored = 1 << 5,
|
||||
};
|
||||
MPElementTypeClassStored = 1 << 5,
|
||||
} MPElementTypeClass;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPElementFeature) {
|
||||
typedef enum {
|
||||
/** Export the key-protected content data. */
|
||||
MPElementFeatureExportContent = 1 << 10,
|
||||
MPElementFeatureExportContent = 1 << 10,
|
||||
/** Never export content. */
|
||||
MPElementFeatureDevicePrivate = 1 << 11,
|
||||
};
|
||||
MPElementFeatureDevicePrivate = 1 << 11,
|
||||
} MPElementFeature;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPElementType) {
|
||||
typedef enum {
|
||||
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
||||
@ -36,7 +36,14 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
|
||||
|
||||
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
||||
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
||||
};
|
||||
} MPElementType;
|
||||
|
||||
extern const char *CipherForType(MPElementType type, char seedByte);
|
||||
extern const char CharacterFromClass(char characterClass, char seedByte);
|
||||
#ifdef DEBUG
|
||||
#define trc(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
#define trc(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
const MPElementType TypeWithName(const char *typeName);
|
||||
const char *CipherForType(MPElementType type, uint8_t seedByte);
|
||||
const char CharacterFromClass(char characterClass, uint8_t seedByte);
|
||||
|
Loading…
Reference in New Issue
Block a user