2
0

WIP - Initial complete C implementation that's still buggy and generates broken passwords, yay.

This commit is contained in:
Maarten Billemont 2014-06-07 01:27:18 -04:00
parent c4dca14800
commit 2bc357cee6
4 changed files with 143 additions and 66 deletions

View File

@ -1,3 +1,5 @@
#!/usr/bin/env bash -e #!/usr/bin/env bash -e
gcc types.c -o types.o # Run with -DDEBUG to enable trace-level output.
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
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 "$@"

View File

@ -63,6 +63,7 @@ int main(int argc, char *const argv[]) {
const char *userName = getenv( MP_env_username ); const char *userName = getenv( MP_env_username );
const char *masterPassword = NULL; const char *masterPassword = NULL;
const char *siteName = NULL; const char *siteName = NULL;
MPElementType siteType = MPElementTypeGeneratedLong;
const char *siteTypeString = getenv( MP_env_sitetype ); const char *siteTypeString = getenv( MP_env_sitetype );
uint32_t siteCounter = 1; uint32_t siteCounter = 1;
const char *siteCounterString = getenv( MP_env_sitecounter ); const char *siteCounterString = getenv( MP_env_sitecounter );
@ -83,16 +84,16 @@ int main(int argc, char *const argv[]) {
case '?': case '?':
switch (optopt) { switch (optopt) {
case 'u': case 'u':
fprintf (stderr, "Missing user name to option: -%c\n", optopt); fprintf(stderr, "Missing user name to option: -%c\n", optopt);
break; break;
case 't': case 't':
fprintf (stderr, "Missing type name to option: -%c\n", optopt); fprintf(stderr, "Missing type name to option: -%c\n", optopt);
break; break;
case 'c': case 'c':
fprintf (stderr, "Missing counter value to option: -%c\n", optopt); fprintf(stderr, "Missing counter value to option: -%c\n", optopt);
break; break;
default: default:
fprintf (stderr, "Unknown option: -%c\n", optopt); fprintf(stderr, "Unknown option: -%c\n", optopt);
} }
return 1; return 1;
default: default:
@ -103,29 +104,36 @@ int main(int argc, char *const argv[]) {
// Convert and validate input. // Convert and validate input.
if (!userName) { if (!userName) {
fprintf (stderr, "Missing user name.\n"); fprintf(stderr, "Missing user name.\n");
return 1; return 1;
} }
trc("userName: %s\n", userName);
if (!siteName) { if (!siteName) {
fprintf (stderr, "Missing site name.\n"); fprintf(stderr, "Missing site name.\n");
return 1; return 1;
} }
trc("siteName: %s\n", siteName);
if (siteCounterString) if (siteCounterString)
siteCounter = atoi( siteCounterString ); siteCounter = atoi( siteCounterString );
if (siteCounter < 1) { if (siteCounter < 1) {
fprintf (stderr, "Invalid site counter: %d\n", siteCounter); fprintf(stderr, "Invalid site counter: %d\n", siteCounter);
return 1; return 1;
} }
trc("siteCounter: %d\n", siteCounter);
if (siteTypeString)
siteType = TypeWithName( siteTypeString );
trc("siteType: %d (%s)\n", siteType, siteTypeString);
// Read the master password. // Read the master password.
char *mpwConfigPath = homedir(".mpw"); char *mpwConfigPath = homedir(".mpw");
if (!mpwConfigPath) { 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; return 1;
} }
trc("mpwConfigPath: %s\n", mpwConfigPath);
FILE *mpwConfig = fopen(mpwConfigPath, "r"); FILE *mpwConfig = fopen(mpwConfigPath, "r");
if (!mpwConfig) { 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; return 1;
} }
free(mpwConfigPath); free(mpwConfigPath);
@ -138,25 +146,26 @@ int main(int argc, char *const argv[]) {
break; break;
} }
if (!masterPassword) { if (!masterPassword) {
fprintf (stderr, "Missing master password for user: %s\n", userName); fprintf(stderr, "Missing master password for user: %s\n", userName);
return 1; return 1;
} }
trc("masterPassword: %s\n", masterPassword);
// Calculate the master key. // Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen ); uint8_t *masterKey = malloc( MP_dkLen );
if (!masterKey) { if (!masterKey) {
fprintf (stderr, "Could not allocate master key: %d\n", errno); fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1; return 1;
} }
const uint32_t n_userNameLength = htonl(strlen(userName)); const uint32_t n_userNameLength = htonl(strlen(userName));
char *masterKeySalt = NULL; char *masterKeySalt = NULL;
size_t masterKeySaltLength = asprintf(&masterKeySalt, "com.lyndir.masterpassword%s%s", (const char *) &n_userNameLength, userName); size_t masterKeySaltLength = asprintf(&masterKeySalt, "com.lyndir.masterpassword%s%s", (const char *) &n_userNameLength, userName);
if (!masterKeySalt) { 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; 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) { 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; return 1;
} }
memset(masterKeySalt, 0, masterKeySaltLength); memset(masterKeySalt, 0, masterKeySaltLength);
@ -167,7 +176,7 @@ int main(int argc, char *const argv[]) {
char *sitePasswordInfo = NULL; char *sitePasswordInfo = NULL;
size_t sitePasswordInfoLength = asprintf(&sitePasswordInfo, "com.lyndir.masterpassword%s%s%s", (const char *) &n_siteNameLength, siteName, (const char *) &n_siteCounter); size_t sitePasswordInfoLength = asprintf(&sitePasswordInfo, "com.lyndir.masterpassword%s%s%s", (const char *) &n_siteNameLength, siteName, (const char *) &n_siteCounter);
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
fprintf (stderr, "Could not allocate site seed: %d\n", errno); fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1; return 1;
} }
uint8_t sitePasswordSeed[32]; uint8_t sitePasswordSeed[32];
@ -178,15 +187,16 @@ int main(int argc, char *const argv[]) {
free(sitePasswordInfo); free(sitePasswordInfo);
// Determine the cipher. // Determine the cipher.
const char *cipher = CipherForType(siteType, sitePasswordSeed); const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
//trc(@"type %@, ciphers: %@, selected: %@", [self nameOfType:type], typeCiphers, cipher); trc("type %s, cipher: %s\n", siteTypeString, cipher);
// Encode the password from the seed using the cipher. // Encode the password from the seed using the cipher.
//NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher."); //NSAssert([seed length] >= [cipher length] + 1, @"Insufficient seed bytes to encode cipher.");
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char)); char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) for (int c = 0; c < strlen(cipher); ++c) {
//trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]); sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
}
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed)); memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
// Output the password. // Output the password.

View File

@ -6,58 +6,116 @@
// Copyright (c) 2012 Lyndir. All rights reserved. // Copyright (c) 2012 Lyndir. All rights reserved.
// //
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "types.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)) { if (!(type & MPElementTypeClassGenerated)) {
fprintf(stderr, "Not a generated type: %d", type); fprintf(stderr, "Not a generated type: %d", type);
abort(); abort();
} }
switch (type) { switch (type) {
case MPElementTypeGeneratedMaximum: case MPElementTypeGeneratedMaximum: {
char *ciphers = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" }; char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
return ciphers[seedByte % 2]; 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]; return ciphers[seedByte % 21];
case MPElementTypeGeneratedMedium: }
char *ciphers = { "CvcnoCvc", "CvcCvcno" }; case MPElementTypeGeneratedMedium: {
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
return ciphers[seedByte % 2]; return ciphers[seedByte % 2];
case MPElementTypeGeneratedBasic: }
char *ciphers = { "aaanaaan", "aannaaan", "aaannaaa" }; case MPElementTypeGeneratedBasic: {
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
return ciphers[seedByte % 3]; return ciphers[seedByte % 3];
case MPElementTypeGeneratedShort: }
case MPElementTypeGeneratedShort: {
return "Cvcn"; return "Cvcn";
case MPElementTypeGeneratedPIN: }
case MPElementTypeGeneratedPIN: {
return "nnnn"; 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) { switch (characterClass) {
case 'V': case 'V': {
return "AEIOU"[seedByte]; classCharacters = "AEIOU";
case 'C': break;
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 "@&amp;%?,=[]_:-+*$#!'^~;()/."[seedByte];
case 'x':
return "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&amp;*()"[seedByte];
} }
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); fprintf(stderr, "Unknown character class: %c", characterClass);
abort(); abort();
}
}
return classCharacters[seedByte % strlen(classCharacters)];
} }

View File

@ -6,27 +6,27 @@
// Copyright (c) 2012 Lyndir. All rights reserved. // Copyright (c) 2012 Lyndir. All rights reserved.
// //
typedef NS_ENUM(NSUInteger, MPElementContentType) { typedef enum {
MPElementContentTypePassword, MPElementContentTypePassword,
MPElementContentTypeNote, MPElementContentTypeNote,
MPElementContentTypePicture, MPElementContentTypePicture,
}; } MPElementContentType;
typedef NS_ENUM(NSUInteger, MPElementTypeClass) { typedef enum {
/** Generate the password. */ /** Generate the password. */
MPElementTypeClassGenerated = 1 << 4, MPElementTypeClassGenerated = 1 << 4,
/** Store the password. */ /** Store the password. */
MPElementTypeClassStored = 1 << 5, MPElementTypeClassStored = 1 << 5,
}; } MPElementTypeClass;
typedef NS_ENUM(NSUInteger, MPElementFeature) { typedef enum {
/** Export the key-protected content data. */ /** Export the key-protected content data. */
MPElementFeatureExportContent = 1 << 10, MPElementFeatureExportContent = 1 << 10,
/** Never export content. */ /** Never export content. */
MPElementFeatureDevicePrivate = 1 << 11, MPElementFeatureDevicePrivate = 1 << 11,
}; } MPElementFeature;
typedef NS_ENUM(NSUInteger, MPElementType) { typedef enum {
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0, MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
@ -36,7 +36,14 @@ typedef NS_ENUM(NSUInteger, MPElementType) {
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent, MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate, MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
}; } MPElementType;
extern const char *CipherForType(MPElementType type, char seedByte); #ifdef DEBUG
extern const char CharacterFromClass(char characterClass, char seedByte); #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);