Restructure, split up mpw cli from mpw core.
This commit is contained in:
parent
2dbada3c7c
commit
672b28a5b7
@ -217,7 +217,8 @@ mpw() {
|
||||
(( mpw_color )) && CFLAGS+=( -DCOLOR ) LDFLAGS+=( -l"curses" )
|
||||
|
||||
cc "${CFLAGS[@]}" -c types.c -o types.o "$@"
|
||||
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" mpw.c -o mpw "$@"
|
||||
cc "${CFLAGS[@]}" -c mpw.c -o mpw.o "$@"
|
||||
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" "mpw.o" mpw-cli.c -o mpw "$@"
|
||||
echo "done! Now run ./install or use ./mpw"
|
||||
}
|
||||
|
||||
|
207
MasterPassword/C/mpw-cli.c
Normal file
207
MasterPassword/C/mpw-cli.c
Normal file
@ -0,0 +1,207 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "mpw.h"
|
||||
|
||||
#if defined(READLINE)
|
||||
#include <readline/readline.h>
|
||||
#elif defined(EDITLINE)
|
||||
#include <histedit.h>
|
||||
#endif
|
||||
|
||||
#define MP_env_fullname "MP_FULLNAME"
|
||||
#define MP_env_sitetype "MP_SITETYPE"
|
||||
#define MP_env_sitecounter "MP_SITECOUNTER"
|
||||
|
||||
static void usage() {
|
||||
|
||||
fprintf( stderr, "Usage: mpw [-u name] [-t type] [-c counter] site\n\n" );
|
||||
fprintf( stderr, " -u name Specify the full name of the user.\n"
|
||||
" Defaults to %s in env.\n\n", MP_env_fullname );
|
||||
fprintf( stderr, " -t type Specify the password's template.\n"
|
||||
" Defaults to %s in env or 'long' for password, 'name' for login.\n"
|
||||
" x, max, maximum | 20 characters, contains symbols.\n"
|
||||
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
|
||||
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
|
||||
" b, basic | 8 characters, no symbols.\n"
|
||||
" s, short | Copy-friendly, 4 characters, no symbols.\n"
|
||||
" i, pin | 4 numbers.\n"
|
||||
" n, name | 9 letter name.\n"
|
||||
" p, phrase | 20 character sentence.\n\n", MP_env_sitetype );
|
||||
fprintf( stderr, " -c counter The value of the counter.\n"
|
||||
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter );
|
||||
fprintf( stderr, " -v variant The kind of content to generate.\n"
|
||||
" Defaults to 'password'.\n"
|
||||
" p, password | The password to log in with.\n"
|
||||
" l, login | The username to log in as.\n"
|
||||
" a, answer | The answer to a security question.\n\n" );
|
||||
fprintf( stderr, " -C context A variant-specific context.\n"
|
||||
" Defaults to empty.\n"
|
||||
" -v p, password | Doesn't currently use a context.\n"
|
||||
" -v l, login | Doesn't currently use a context.\n"
|
||||
" -v a, answer | Empty for a universal site answer or\n"
|
||||
" | the most significant word(s) of the question.\n\n" );
|
||||
fprintf( stderr, " ENVIRONMENT\n\n"
|
||||
" MP_FULLNAME | The full name of the user.\n"
|
||||
" MP_SITETYPE | The default password template.\n"
|
||||
" MP_SITECOUNTER | The default counter value.\n\n" );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
static char *homedir(const char *filename) {
|
||||
|
||||
char *homedir = NULL;
|
||||
struct passwd *passwd = getpwuid( getuid() );
|
||||
if (passwd)
|
||||
homedir = passwd->pw_dir;
|
||||
if (!homedir)
|
||||
homedir = getenv( "HOME" );
|
||||
if (!homedir)
|
||||
homedir = getcwd( NULL, 0 );
|
||||
|
||||
char *homefile = NULL;
|
||||
asprintf( &homefile, "%s/%s", homedir, filename );
|
||||
return homefile;
|
||||
}
|
||||
|
||||
static char *getlinep(const char *prompt) {
|
||||
|
||||
char *buf = NULL;
|
||||
size_t bufSize = 0;
|
||||
ssize_t lineSize;
|
||||
fprintf( stderr, "%s", prompt );
|
||||
fprintf( stderr, " " );
|
||||
if ((lineSize = getline( &buf, &bufSize, stdin )) < 0) {
|
||||
free( buf );
|
||||
return NULL;
|
||||
}
|
||||
buf[lineSize - 1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
|
||||
// Read the environment.
|
||||
char *fullName = getenv( MP_env_fullname );
|
||||
const char *masterPassword = NULL;
|
||||
const char *siteName = NULL;
|
||||
MPSiteType siteType = MPSiteTypeGeneratedLong;
|
||||
const char *siteTypeString = getenv( MP_env_sitetype );
|
||||
MPSiteVariant siteVariant = MPSiteVariantPassword;
|
||||
const char *siteVariantString = NULL;
|
||||
const char *siteContextString = NULL;
|
||||
uint32_t siteCounter = 1;
|
||||
const char *siteCounterString = getenv( MP_env_sitecounter );
|
||||
|
||||
// Read the options.
|
||||
for (int opt; (opt = getopt( argc, argv, "u:t:c:v:C:h" )) != -1;)
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
fullName = optarg;
|
||||
break;
|
||||
case 't':
|
||||
siteTypeString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
siteVariantString = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
siteContextString = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case '?':
|
||||
switch (optopt) {
|
||||
case 'u':
|
||||
fprintf( stderr, "Missing full name to option: -%c\n", optopt );
|
||||
break;
|
||||
case 't':
|
||||
fprintf( stderr, "Missing type name to option: -%c\n", optopt );
|
||||
break;
|
||||
case 'c':
|
||||
fprintf( stderr, "Missing counter value to option: -%c\n", optopt );
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "Unknown option: -%c\n", optopt );
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (optind < argc)
|
||||
siteName = argv[optind];
|
||||
|
||||
// Convert and validate input.
|
||||
if (!fullName) {
|
||||
if (!(fullName = getlinep( "Your full name:" ))) {
|
||||
fprintf( stderr, "Missing full name.\n" );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!siteName) {
|
||||
if (!(siteName = getlinep( "Site name:" ))) {
|
||||
fprintf( stderr, "Missing site name.\n" );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (siteCounterString)
|
||||
siteCounter = atoi( siteCounterString );
|
||||
if (siteCounter < 1) {
|
||||
fprintf( stderr, "Invalid site counter: %d\n", siteCounter );
|
||||
return 1;
|
||||
}
|
||||
if (siteVariantString)
|
||||
siteVariant = VariantWithName( siteVariantString );
|
||||
if (siteVariant == MPSiteVariantLogin)
|
||||
siteType = MPSiteTypeGeneratedName;
|
||||
if (siteVariant == MPSiteVariantAnswer)
|
||||
siteType = MPSiteTypeGeneratedPhrase;
|
||||
if (siteTypeString)
|
||||
siteType = TypeWithName( siteTypeString );
|
||||
|
||||
// Read the master password.
|
||||
char *mpwConfigPath = homedir( ".mpw" );
|
||||
if (!mpwConfigPath) {
|
||||
fprintf( stderr, "Couldn't resolve path for configuration file: %d\n", errno );
|
||||
return 1;
|
||||
}
|
||||
trc( "mpwConfigPath: %s\n", mpwConfigPath );
|
||||
FILE *mpwConfig = fopen( mpwConfigPath, "r" );
|
||||
free( mpwConfigPath );
|
||||
if (mpwConfig) {
|
||||
char *line = NULL;
|
||||
size_t linecap = 0;
|
||||
while (getline( &line, &linecap, mpwConfig ) > 0) {
|
||||
char *lineData = line;
|
||||
if (strcmp( strsep( &lineData, ":" ), fullName ) == 0) {
|
||||
masterPassword = strcpy( malloc( strlen( lineData ) ), strsep( &lineData, "\n" ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
free( line );
|
||||
}
|
||||
while (!masterPassword)
|
||||
masterPassword = getpass( "Your master password: " );
|
||||
|
||||
// Summarize operation.
|
||||
fprintf( stderr, "%s's password for %s:\n[ %s ]: ", fullName, siteName, Identicon( fullName, masterPassword ) );
|
||||
|
||||
// Output the password.
|
||||
uint8_t *masterKey = mpw_masterKeyForUser( fullName, masterPassword );
|
||||
char *sitePassword = mpw_passwordForSite( masterKey, siteName, siteType, siteCounter, siteVariant, siteContextString );
|
||||
fprintf( stdout, "%s\n", sitePassword );
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@ -13,300 +10,127 @@
|
||||
#include <scrypt/crypto_scrypt.h>
|
||||
#include "types.h"
|
||||
|
||||
#if defined(READLINE)
|
||||
#include <readline/readline.h>
|
||||
#elif defined(EDITLINE)
|
||||
#include <histedit.h>
|
||||
#endif
|
||||
|
||||
#define MP_N 32768
|
||||
#define MP_r 8
|
||||
#define MP_p 2
|
||||
#define MP_dkLen 64
|
||||
#define MP_hash PearlHashSHA256
|
||||
|
||||
#define MP_env_fullname "MP_FULLNAME"
|
||||
#define MP_env_sitetype "MP_SITETYPE"
|
||||
#define MP_env_sitecounter "MP_SITECOUNTER"
|
||||
void mpw_bufPush(void *buffer, size_t *bufferSize, void *pushBuffer, size_t pushSize) {
|
||||
|
||||
static void usage() {
|
||||
fprintf(stderr, "Usage: mpw [-u name] [-t type] [-c counter] site\n\n");
|
||||
fprintf(stderr, " -u name Specify the full name of the user.\n"
|
||||
" Defaults to %s in env.\n\n", MP_env_fullname);
|
||||
fprintf(stderr, " -t type Specify the password's template.\n"
|
||||
" Defaults to %s in env or 'long' for password, 'name' for login.\n"
|
||||
" x, max, maximum | 20 characters, contains symbols.\n"
|
||||
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
|
||||
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
|
||||
" b, basic | 8 characters, no symbols.\n"
|
||||
" s, short | Copy-friendly, 4 characters, no symbols.\n"
|
||||
" i, pin | 4 numbers.\n"
|
||||
" n, name | 9 letter name.\n"
|
||||
" p, phrase | 20 character sentence.\n\n", MP_env_sitetype);
|
||||
fprintf(stderr, " -c counter The value of the counter.\n"
|
||||
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter);
|
||||
fprintf(stderr, " -v variant The kind of content to generate.\n"
|
||||
" Defaults to 'password'.\n"
|
||||
" p, password | The password to log in with.\n"
|
||||
" l, login | The username to log in as.\n"
|
||||
" a, answer | The answer to a security question.\n\n");
|
||||
fprintf(stderr, " -C context A variant-specific context.\n"
|
||||
" Defaults to empty.\n"
|
||||
" -v p, password | Doesn't currently use a context.\n"
|
||||
" -v l, login | Doesn't currently use a context.\n"
|
||||
" -v a, answer | Empty for a universal site answer or\n"
|
||||
" | the most significant word(s) of the question.\n\n");
|
||||
fprintf(stderr, " ENVIRONMENT\n\n"
|
||||
" MP_FULLNAME | The full name of the user.\n"
|
||||
" MP_SITETYPE | The default password template.\n"
|
||||
" MP_SITECOUNTER | The default counter value.\n\n");
|
||||
exit(0);
|
||||
void *pushDst = buffer + *bufferSize;
|
||||
*bufferSize += pushSize;
|
||||
realloc( buffer, *bufferSize );
|
||||
memcpy( pushDst, pushBuffer, pushSize );
|
||||
}
|
||||
|
||||
static char *homedir(const char *filename) {
|
||||
char *homedir = NULL;
|
||||
struct passwd* passwd = getpwuid(getuid());
|
||||
if (passwd)
|
||||
homedir = passwd->pw_dir;
|
||||
if (!homedir)
|
||||
homedir = getenv("HOME");
|
||||
if (!homedir)
|
||||
homedir = getcwd(NULL, 0);
|
||||
|
||||
char *homefile = NULL;
|
||||
asprintf(&homefile, "%s/%s", homedir, filename);
|
||||
return homefile;
|
||||
}
|
||||
|
||||
static char *getlinep(const char *prompt) {
|
||||
char *buf = NULL;
|
||||
size_t bufSize = 0;
|
||||
ssize_t lineSize;
|
||||
fprintf(stderr, "%s", prompt);
|
||||
fprintf(stderr, " ");
|
||||
if ((lineSize = getline(&buf, &bufSize, stdin)) < 0) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf[lineSize - 1]=0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
|
||||
// Read the environment.
|
||||
char *fullName = getenv( MP_env_fullname );
|
||||
const char *masterPassword = NULL;
|
||||
const char *siteName = NULL;
|
||||
MPSiteType siteType = MPSiteTypeGeneratedLong;
|
||||
const char *siteTypeString = getenv( MP_env_sitetype );
|
||||
MPSiteVariant siteVariant = MPSiteVariantPassword;
|
||||
const char *siteVariantString = NULL;
|
||||
const char *siteContextString = NULL;
|
||||
uint32_t siteCounter = 1;
|
||||
const char *siteCounterString = getenv( MP_env_sitecounter );
|
||||
|
||||
// Read the options.
|
||||
for (int opt; (opt = getopt(argc, argv, "u:t:c:v:C:h")) != -1;)
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
fullName = optarg;
|
||||
break;
|
||||
case 't':
|
||||
siteTypeString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
siteVariantString = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
siteContextString = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case '?':
|
||||
switch (optopt) {
|
||||
case 'u':
|
||||
fprintf(stderr, "Missing full name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 't':
|
||||
fprintf(stderr, "Missing type name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 'c':
|
||||
fprintf(stderr, "Missing counter value to option: -%c\n", optopt);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option: -%c\n", optopt);
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (optind < argc)
|
||||
siteName = argv[optind];
|
||||
|
||||
// Convert and validate input.
|
||||
if (!fullName) {
|
||||
if (!(fullName = getlinep("Your full name:"))) {
|
||||
fprintf(stderr, "Missing full name.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
trc("fullName: %s\n", fullName);
|
||||
if (!siteName) {
|
||||
if (!(siteName = getlinep("Site name:"))) {
|
||||
fprintf(stderr, "Missing site name.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (siteCounterString)
|
||||
siteCounter = atoi( siteCounterString );
|
||||
if (siteCounter < 1) {
|
||||
fprintf(stderr, "Invalid site counter: %d\n", siteCounter);
|
||||
return 1;
|
||||
}
|
||||
if (siteVariantString)
|
||||
siteVariant = VariantWithName( siteVariantString );
|
||||
if (siteVariant == MPSiteVariantLogin)
|
||||
siteType = MPSiteTypeGeneratedName;
|
||||
if (siteVariant == MPSiteVariantAnswer)
|
||||
siteType = MPSiteTypeGeneratedPhrase;
|
||||
if (siteTypeString)
|
||||
siteType = TypeWithName( siteTypeString );
|
||||
|
||||
// Read the master password.
|
||||
char *mpwConfigPath = homedir(".mpw");
|
||||
if (!mpwConfigPath) {
|
||||
fprintf(stderr, "Couldn't resolve path for configuration file: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
trc("mpwConfigPath: %s\n", mpwConfigPath);
|
||||
FILE *mpwConfig = fopen(mpwConfigPath, "r");
|
||||
free(mpwConfigPath);
|
||||
if (mpwConfig) {
|
||||
char *line = NULL;
|
||||
size_t linecap = 0;
|
||||
while (getline(&line, &linecap, mpwConfig) > 0) {
|
||||
char *lineData = line;
|
||||
if (strcmp(strsep(&lineData, ":"), fullName) == 0) {
|
||||
masterPassword = strcpy(malloc(strlen(lineData)), strsep(&lineData, "\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
while (!masterPassword)
|
||||
masterPassword = getpass( "Your master password: " );
|
||||
trc("masterPassword: %s\n", masterPassword);
|
||||
|
||||
// Summarize operation.
|
||||
fprintf(stderr, "%s's password for %s:\n[ %s ]: ", fullName, siteName, Identicon( fullName, masterPassword ));
|
||||
struct timeval startTime;
|
||||
if (gettimeofday(&startTime, NULL) != 0) {
|
||||
fprintf(stderr, "Could not get time: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPassword) {
|
||||
|
||||
// Calculate the master key salt.
|
||||
const char *mpKeyScope = ScopeForVariant(MPSiteVariantPassword);
|
||||
trc("key scope: %s\n", mpKeyScope);
|
||||
const uint32_t n_fullNameLength = htonl(strlen(fullName));
|
||||
const size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_fullNameLength) + strlen(fullName);
|
||||
const char *mpKeyScope = ScopeForVariant( MPSiteVariantPassword );
|
||||
const uint32_t n_fullNameLength = htonl( strlen( fullName ) );
|
||||
const size_t masterKeySaltLength = strlen( mpKeyScope ) + sizeof( n_fullNameLength ) + strlen( fullName );
|
||||
char *masterKeySalt = (char *)malloc( masterKeySaltLength );
|
||||
if (!masterKeySalt) {
|
||||
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
if (!masterKeySalt)
|
||||
ftl( "Could not allocate master key salt: %d\n", errno );
|
||||
|
||||
char *mKS = masterKeySalt;
|
||||
memcpy(mKS, mpKeyScope, strlen(mpKeyScope)); mKS += strlen(mpKeyScope);
|
||||
memcpy(mKS, &n_fullNameLength, sizeof(n_fullNameLength)); mKS += sizeof(n_fullNameLength);
|
||||
memcpy(mKS, fullName, strlen(fullName)); mKS += strlen(fullName);
|
||||
memcpy( mKS, mpKeyScope, strlen( mpKeyScope ) );
|
||||
mKS += strlen( mpKeyScope );
|
||||
memcpy( mKS, &n_fullNameLength, sizeof( n_fullNameLength ) );
|
||||
mKS += sizeof( n_fullNameLength );
|
||||
memcpy( mKS, fullName, strlen( fullName ) );
|
||||
mKS += strlen( fullName );
|
||||
|
||||
trc( "fullName: %s\n", fullName );
|
||||
trc( "masterPassword: %s\n", masterPassword );
|
||||
trc( "key scope: %s\n", mpKeyScope );
|
||||
trc( "masterKeySalt ID: %s\n", IDForBuf( masterKeySalt, masterKeySaltLength ) );
|
||||
if (mKS - masterKeySalt != masterKeySaltLength)
|
||||
abort();
|
||||
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
|
||||
ftl( "Unexpected master key salt length." );
|
||||
|
||||
// Calculate the master key.
|
||||
uint8_t *masterKey = (uint8_t *)malloc( MP_dkLen );
|
||||
if (!masterKey) {
|
||||
fprintf(stderr, "Could not allocate master key: %d\n", errno);
|
||||
return 1;
|
||||
fprintf( stderr, "Could not allocate master key: %d\n", errno );
|
||||
abort();
|
||||
}
|
||||
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);
|
||||
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 );
|
||||
abort();
|
||||
}
|
||||
memset(masterKeySalt, 0, masterKeySaltLength);
|
||||
free(masterKeySalt);
|
||||
struct timeval endTime;
|
||||
if (gettimeofday(&endTime, NULL) != 0) {
|
||||
fprintf(stderr, "Could not get time: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
long long secs = (endTime.tv_sec - startTime.tv_sec);
|
||||
long long usecs = (endTime.tv_usec - startTime.tv_usec);
|
||||
double elapsed = secs + usecs / 1000000.0;
|
||||
trc("masterKey ID: %s (derived in %.2fs)\n", IDForBuf(masterKey, MP_dkLen), elapsed);
|
||||
memset( masterKeySalt, 0, masterKeySaltLength );
|
||||
free( masterKeySalt );
|
||||
trc( "masterKey ID: %s\n", IDForBuf( masterKey, MP_dkLen ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
char *mpw_passwordForSite(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
|
||||
const MPSiteVariant siteVariant, const char *siteContext) {
|
||||
|
||||
// Calculate the site seed.
|
||||
trc("siteName: %s\n", siteName);
|
||||
trc("siteCounter: %d\n", siteCounter);
|
||||
trc("siteVariant: %d (%s)\n", siteVariant, siteVariantString);
|
||||
trc("siteType: %d (%s)\n", siteType, siteTypeString);
|
||||
const char *siteScope = ScopeForVariant(siteVariant);
|
||||
trc("site scope: %s, context: %s\n", siteScope, siteContextString == NULL? "<empty>": siteContextString);
|
||||
const uint32_t n_siteNameLength = htonl(strlen(siteName));
|
||||
const uint32_t n_siteCounter = htonl(siteCounter);
|
||||
const uint32_t n_siteContextLength = siteContextString == NULL? 0: htonl(strlen(siteContextString));
|
||||
size_t sitePasswordInfoLength = strlen(siteScope) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
|
||||
if (siteContextString)
|
||||
sitePasswordInfoLength += sizeof(n_siteContextLength) + strlen(siteContextString);
|
||||
trc( "siteName: %s\n", siteName );
|
||||
trc( "siteCounter: %d\n", siteCounter );
|
||||
trc( "siteVariant: %d\n", siteVariant );
|
||||
trc( "siteType: %d\n", siteType );
|
||||
const char *siteScope = ScopeForVariant( siteVariant );
|
||||
trc( "site scope: %s, context: %s\n", siteScope, siteContext == NULL? "<empty>": siteContext );
|
||||
const uint32_t n_siteNameLength = htonl( strlen( siteName ) );
|
||||
const uint32_t n_siteCounter = htonl( siteCounter );
|
||||
const uint32_t n_siteContextLength = siteContext == NULL? 0: htonl( strlen( siteContext ) );
|
||||
size_t sitePasswordInfoLength = strlen( siteScope ) + sizeof( n_siteNameLength ) + strlen( siteName ) + sizeof( n_siteCounter );
|
||||
if (siteContext)
|
||||
sitePasswordInfoLength += sizeof( n_siteContextLength ) + strlen( siteContext );
|
||||
char *sitePasswordInfo = (char *)malloc( sitePasswordInfoLength );
|
||||
if (!sitePasswordInfo) {
|
||||
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
|
||||
return 1;
|
||||
fprintf( stderr, "Could not allocate site seed: %d\n", errno );
|
||||
abort();
|
||||
}
|
||||
|
||||
char *sPI = sitePasswordInfo;
|
||||
memcpy(sPI, siteScope, strlen(siteScope)); sPI += strlen(siteScope);
|
||||
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
|
||||
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
|
||||
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
|
||||
if (siteContextString) {
|
||||
memcpy(sPI, &n_siteContextLength, sizeof(n_siteContextLength)); sPI += sizeof(n_siteContextLength);
|
||||
memcpy(sPI, siteContextString, strlen(siteContextString)); sPI += strlen(siteContextString);
|
||||
memcpy( sPI, siteScope, strlen( siteScope ) );
|
||||
sPI += strlen( siteScope );
|
||||
memcpy( sPI, &n_siteNameLength, sizeof( n_siteNameLength ) );
|
||||
sPI += sizeof( n_siteNameLength );
|
||||
memcpy( sPI, siteName, strlen( siteName ) );
|
||||
sPI += strlen( siteName );
|
||||
memcpy( sPI, &n_siteCounter, sizeof( n_siteCounter ) );
|
||||
sPI += sizeof( n_siteCounter );
|
||||
if (siteContext) {
|
||||
memcpy( sPI, &n_siteContextLength, sizeof( n_siteContextLength ) );
|
||||
sPI += sizeof( n_siteContextLength );
|
||||
memcpy( sPI, siteContext, strlen( siteContext ) );
|
||||
sPI += strlen( siteContext );
|
||||
}
|
||||
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
|
||||
abort();
|
||||
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", siteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)), Hex(&n_siteContextLength, sizeof(n_siteContextLength)), siteContextString);
|
||||
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
|
||||
trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", siteScope,
|
||||
Hex( &n_siteNameLength, sizeof( n_siteNameLength ) ), siteName, Hex( &n_siteCounter, sizeof( n_siteCounter ) ),
|
||||
Hex( &n_siteContextLength, sizeof( n_siteContextLength ) ), siteContext );
|
||||
trc( "sitePasswordInfo ID: %s\n", IDForBuf( sitePasswordInfo, sitePasswordInfoLength ) );
|
||||
|
||||
uint8_t sitePasswordSeed[32];
|
||||
HMAC_SHA256_Buf(masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed);
|
||||
memset(masterKey, 0, MP_dkLen);
|
||||
memset(sitePasswordInfo, 0, sitePasswordInfoLength);
|
||||
free(masterKey);
|
||||
free(sitePasswordInfo);
|
||||
trc("sitePasswordSeed ID: %s\n", IDForBuf(sitePasswordSeed, 32));
|
||||
HMAC_SHA256_Buf( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed );
|
||||
memset( sitePasswordInfo, 0, sitePasswordInfoLength );
|
||||
free( sitePasswordInfo );
|
||||
trc( "sitePasswordSeed ID: %s\n", IDForBuf( sitePasswordSeed, 32 ) );
|
||||
|
||||
// Determine the template.
|
||||
const char *template = TemplateForType(siteType, sitePasswordSeed[0]);
|
||||
trc("type %s, template: %s\n", siteTypeString, template);
|
||||
if (strlen(template) > 32)
|
||||
const char *template = TemplateForType( siteType, sitePasswordSeed[0] );
|
||||
trc( "type %d, template: %s\n", siteType, template );
|
||||
if (strlen( template ) > 32)
|
||||
abort();
|
||||
|
||||
// Encode the password from the seed using the template.
|
||||
char *sitePassword = (char *)calloc(strlen(template) + 1, sizeof(char));
|
||||
for (int c = 0; c < strlen(template); ++c) {
|
||||
sitePassword[c] = CharacterFromClass(template[c], sitePasswordSeed[c + 1]);
|
||||
trc("class %c, index %u (0x%02X) -> character: %c\n", template[c], sitePasswordSeed[c + 1], sitePasswordSeed[c + 1], sitePassword[c]);
|
||||
char *sitePassword = (char *)calloc( strlen( template ) + 1, sizeof( char ) );
|
||||
for (int c = 0; c < strlen( template ); ++c) {
|
||||
sitePassword[c] = CharacterFromClass( template[c], sitePasswordSeed[c + 1] );
|
||||
trc( "class %c, index %u (0x%02X) -> character: %c\n", template[c], sitePasswordSeed[c + 1], sitePasswordSeed[c + 1],
|
||||
sitePassword[c] );
|
||||
}
|
||||
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
|
||||
memset( sitePasswordSeed, 0, sizeof( sitePasswordSeed ) );
|
||||
|
||||
// Output the password.
|
||||
fprintf( stdout, "%s\n", sitePassword );
|
||||
return 0;
|
||||
return sitePassword;
|
||||
}
|
||||
|
6
MasterPassword/C/mpw.h
Normal file
6
MasterPassword/C/mpw.h
Normal file
@ -0,0 +1,6 @@
|
||||
uint8_t *mpw_masterKeyForUser(
|
||||
const char *fullName, const char *masterPassword);
|
||||
|
||||
char *mpw_passwordForSite(
|
||||
const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
|
||||
const MPSiteVariant siteVariant, const char *siteContext);
|
@ -48,6 +48,7 @@ typedef enum {
|
||||
#else
|
||||
#define trc(...) do {} while (0)
|
||||
#endif
|
||||
#define ftl(...) do { fprintf( stderr, "Could not allocate master key salt: %d\n", errno ); abort(); } while (0)
|
||||
|
||||
const MPSiteVariant VariantWithName(const char *variantName);
|
||||
const char *ScopeForVariant(MPSiteVariant variant);
|
||||
|
@ -46,6 +46,7 @@
|
||||
93D39A5FF670957C0AF8298D /* MPPasswordCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39DEA995041A13DC9CAF7 /* MPPasswordCell.m */; };
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39D8A953779B35403AF6E /* PearlUICollectionView.m */; };
|
||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */; };
|
||||
93D39B35D4B8E87ADEC05246 /* mpw-cli.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D398121C8F063A3637144E /* mpw-cli.c */; };
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */; };
|
||||
93D39B76DD5AB108BA8928E8 /* UIScrollView+PearlAdjustInsets.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */; };
|
||||
93D39B842AB9A5D072810D76 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */; };
|
||||
@ -498,8 +499,10 @@
|
||||
93D3979016BF0C5B29D1340D /* distribute */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = distribute; sourceTree = "<group>"; };
|
||||
93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = "<group>"; };
|
||||
93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
|
||||
93D398121C8F063A3637144E /* mpw-cli.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli.c"; sourceTree = "<group>"; };
|
||||
93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = "<group>"; };
|
||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
|
||||
93D3990D850D76A94C6B7A4D /* mpw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mpw.h; sourceTree = "<group>"; };
|
||||
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPWebViewController.m; sourceTree = "<group>"; };
|
||||
93D399493FEDDE74DD1A0C15 /* MPRootSegue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPRootSegue.m; sourceTree = "<group>"; };
|
||||
93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCoachmarkViewController.m; sourceTree = "<group>"; };
|
||||
@ -1612,6 +1615,8 @@
|
||||
93D3979016BF0C5B29D1340D /* distribute */,
|
||||
93D39245A478883C672818F3 /* mpw.bashrc */,
|
||||
93D39B70138D0E28F7D5E86B /* mpw-bench.c */,
|
||||
93D398121C8F063A3637144E /* mpw-cli.c */,
|
||||
93D3990D850D76A94C6B7A4D /* mpw.h */,
|
||||
);
|
||||
name = C;
|
||||
path = ../../C;
|
||||
@ -3626,6 +3631,7 @@
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
||||
93D392FD5E2052F7D7DB3774 /* NSString+MPMarkDown.m in Sources */,
|
||||
93D395B715D15F2B56F2A2EE /* types.c in Sources */,
|
||||
93D39B35D4B8E87ADEC05246 /* mpw-cli.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user