2
0

WIP performing marshalling of sites in C.

This commit is contained in:
Maarten Billemont 2017-07-15 21:13:49 -04:00
parent 738ad197b2
commit 560cb1a266
25 changed files with 1224 additions and 308 deletions

View File

@ -27,7 +27,7 @@
#define MP_p 2
#define MP_hash PearlHashSHA256
const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
MPMasterKey mpw_masterKeyForUser(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
if (!fullName || !masterPassword)
return NULL;
@ -47,7 +47,7 @@ const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPass
}
}
const char *mpw_passwordForSite(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const char *mpw_passwordForSite(MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion) {
if (!masterKey || !siteName)

View File

@ -19,7 +19,10 @@
// NOTE: mpw is currently NOT thread-safe.
#include "mpw-types.h"
typedef enum(unsigned int, MPAlgorithmVersion) {
#ifndef _MPW_ALGORITHM_H
#define _MPW_ALGORITHM_H
typedef enum( unsigned int, MPAlgorithmVersion ) {
/** V0 did math with chars whose signedness was platform-dependent. */
MPAlgorithmVersion0,
/** V1 miscounted the byte-length of multi-byte site names. */
@ -28,16 +31,20 @@ typedef enum(unsigned int, MPAlgorithmVersion) {
MPAlgorithmVersion2,
/** V3 is the current version. */
MPAlgorithmVersion3,
MPAlgorithmVersionCurrent = MPAlgorithmVersion3,
MPAlgorithmVersionLatest = MPAlgorithmVersion3,
};
#define MPAlgorithmVersionCurrent MPAlgorithmVersion3
/** Derive the master key for a user based on their name and master password.
* @return A new MP_dkLen-byte allocated buffer or NULL if an allocation error occurred. */
const uint8_t *mpw_masterKeyForUser(
MPMasterKey mpw_masterKeyForUser(
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
/** Encode a password for the site from the given master key and site parameters.
* @return A newly allocated string or NULL if an allocation error occurred. */
const char *mpw_passwordForSite(
const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion);
#endif // _MPW_ALGORITHM_H

View File

@ -43,7 +43,7 @@ static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedBy
return classCharacters[seedByte % strlen( classCharacters )];
}
static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *masterPassword) {
static MPMasterKey mpw_masterKeyForUser_v0(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 0 );
@ -66,18 +66,18 @@ static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
const uint8_t *masterKey = mpw_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey;
}
static const char *mpw_passwordForSite_v0(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
static const char *mpw_passwordForSite_v0(MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
@ -110,7 +110,7 @@ static const char *mpw_passwordForSite_v0(const uint8_t *masterKey, const char *
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const char *sitePasswordSeed = (const char *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
const char *sitePasswordSeed = (const char *)mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );

View File

@ -28,7 +28,7 @@
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *masterPassword) {
static MPMasterKey mpw_masterKeyForUser_v1(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 1 );
@ -51,18 +51,18 @@ static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey;
}
static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
static const char *mpw_passwordForSite_v1(MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
@ -95,7 +95,7 @@ static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );

View File

@ -28,7 +28,7 @@
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *masterPassword) {
static MPMasterKey mpw_masterKeyForUser_v2(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 2 );
@ -51,18 +51,18 @@ static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
const uint8_t *masterKey = mpw_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey;
}
static const char *mpw_passwordForSite_v2(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
static const char *mpw_passwordForSite_v2(MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
@ -95,7 +95,7 @@ static const char *mpw_passwordForSite_v2(const uint8_t *masterKey, const char *
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );

View File

@ -28,7 +28,7 @@
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *masterPassword) {
static MPMasterKey mpw_masterKeyForUser_v3(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 3 );
@ -51,18 +51,18 @@ static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
const uint8_t *masterKey = mpw_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey;
}
static const char *mpw_passwordForSite_v3(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
static const char *mpw_passwordForSite_v3(MPMasterKey masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
@ -95,7 +95,7 @@ static const char *mpw_passwordForSite_v3(const uint8_t *masterKey, const char *
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );

522
core/c/mpw-marshall.c Normal file
View File

@ -0,0 +1,522 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#include <stdio.h>
#include <time.h>
#include <json-c/json.h>
#include "mpw-marshall.h"
#include "mpw-util.h"
MPMarshalledUser mpw_marshall_user(
const char *fullName, MPMasterKey masterKey, const MPAlgorithmVersion algorithmVersion) {
return (MPMarshalledUser){
.name = fullName,
.key = masterKey,
.version = algorithmVersion,
.avatar = 0,
.defaultType = MPSiteTypeGeneratedLong,
.lastUsed = 0,
.sites_count = 0,
.sites = NULL,
};
};
MPMarshalledSite mpw_marshall_site(
MPMarshalledUser *marshalledUser,
const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion) {
marshalledUser->sites = realloc( marshalledUser->sites, marshalledUser->sites_count + 1 );
return marshalledUser->sites[marshalledUser->sites_count++] = (MPMarshalledSite){
.name = siteName,
.type = siteType,
.counter = siteCounter,
.version = algorithmVersion,
.loginName = NULL,
.loginGenerated = 0,
.url = NULL,
.uses = 0,
.lastUsed = 0,
.questions_count = 0,
.questions = NULL,
};
};
MPMarshalledQuestion mpw_marshal_question(
MPMarshalledSite *marshalledSite, const char *keyword) {
marshalledSite->questions = realloc( marshalledSite->questions, marshalledSite->questions_count + 1 );
return marshalledSite->questions[marshalledSite->questions_count++] = (MPMarshalledQuestion){
.keyword = keyword,
};
}
#define try_asprintf(...) ({ if (asprintf( __VA_ARGS__ ) < 0) return false; })
bool mpw_marshall_write_flat(
char **out, bool redacted, const MPMarshalledUser *marshalledUser) {
try_asprintf( out, "# Master Password site export\n" );
if (redacted)
try_asprintf( out, "# Export of site names and passwords in clear-text.\n" );
else
try_asprintf( out, "# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n" );
try_asprintf( out, "# \n" );
try_asprintf( out, "##\n" );
try_asprintf( out, "# Format: %d\n", 1 );
size_t dateSize = 21;
char dateString[dateSize];
time_t now = time( NULL );
if (strftime( dateString, dateSize, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", gmtime( &now ) ))
try_asprintf( out, "# Date: %s\n", dateString );
try_asprintf( out, "# User Name: %s\n", marshalledUser->name );
try_asprintf( out, "# Full Name: %s\n", marshalledUser->name );
try_asprintf( out, "# Avatar: %u\n", marshalledUser->avatar );
try_asprintf( out, "# Key ID: %s\n", mpw_id_buf( marshalledUser->key, MPMasterKeySize ) );
try_asprintf( out, "# Algorithm: %d\n", marshalledUser->version );
try_asprintf( out, "# Default Type: %d\n", marshalledUser->defaultType );
try_asprintf( out, "# Passwords: %s\n", redacted? "PROTECTED": "VISIBLE" );
try_asprintf( out, "##\n" );
try_asprintf( out, "#\n" );
try_asprintf( out, "# Last Times Password Login\t Site\tSite\n" );
try_asprintf( out, "# used used type name\t name\tpassword\n" );
// Sites.
for (int s = 0; s < marshalledUser->sites_count; ++s) {
MPMarshalledSite site = marshalledUser->sites[s];
const char *content = NULL;
if (!redacted && site.type & MPSiteTypeClassGenerated)
content = mpw_passwordForSite( marshalledUser->key, site.name, site.type, site.counter,
MPSiteVariantPassword, NULL, site.version );
// TODO: Personal Passwords
if (strftime( dateString, dateSize, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", gmtime( &site.lastUsed ) ))
try_asprintf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n",
dateString, (long)site.uses, (long)site.type, (long)site.version, (long)site.counter,
site.loginName?: "", site.name, content?: "" );
}
return true;
}
bool mpw_marshall_write_json(
char **out, bool redacted, const MPMarshalledUser *marshalledUser) {
json_object *json_out = json_object_new_object();
// Section: "export"
json_object *json_export = json_object_new_object();
json_object_object_add( json_out, "export", json_export );
json_object_object_add( json_export, "format", json_object_new_int( 1 ) );
json_object_object_add( json_export, "redacted", json_object_new_boolean( redacted ) );
size_t dateSize = 21;
char dateString[dateSize];
time_t now = time( NULL );
if (strftime( dateString, dateSize, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", gmtime( &now ) ))
json_object_object_add( json_export, "date", json_object_new_string( dateString ) );
json_object_put( json_export );
// Section: "user"
json_object *json_user = json_object_new_object();
json_object_object_add( json_out, "user", json_user );
json_object_object_add( json_user, "avatar", json_object_new_int( marshalledUser->avatar ) );
json_object_object_add( json_user, "full_name", json_object_new_string( marshalledUser->name ) );
if (strftime( dateString, dateSize, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", gmtime( &marshalledUser->lastUsed ) ))
json_object_object_add( json_user, "last_used", json_object_new_string( dateString ) );
json_object_object_add( json_user, "key_id", json_object_new_string( mpw_id_buf( marshalledUser->key, MPMasterKeySize ) ) );
json_object_object_add( json_user, "algorithm", json_object_new_int( marshalledUser->version ) );
json_object_object_add( json_user, "default_type", json_object_new_int( marshalledUser->defaultType ) );
json_object_put( json_user );
// Section "sites"
json_object *json_sites = json_object_new_object();
json_object_object_add( json_out, "sites", json_sites );
for (int s = 0; s < marshalledUser->sites_count; ++s) {
MPMarshalledSite site = marshalledUser->sites[s];
const char *content = site.content;
if (!redacted && site.type & MPSiteTypeClassGenerated)
content = mpw_passwordForSite( marshalledUser->key, site.name, site.type, site.counter,
MPSiteVariantPassword, NULL, site.version );
// TODO: Personal Passwords
//else if (redacted && content)
// content = aes128_cbc( marshalledUser->key, content );
json_object *json_site = json_object_new_object();
json_object_object_add( json_sites, site.name, json_site );
json_object_object_add( json_site, "type", json_object_new_int( site.type ) );
json_object_object_add( json_site, "counter", json_object_new_int( site.counter ) );
json_object_object_add( json_site, "algorithm", json_object_new_int( site.version ) );
if (content)
json_object_object_add( json_site, "password", json_object_new_string( content ) );
json_object_object_add( json_site, "login_name", json_object_new_string( site.loginName?: "" ) );
json_object_object_add( json_site, "login_generated", json_object_new_boolean( site.loginGenerated ) );
json_object_object_add( json_site, "uses", json_object_new_int( site.uses ) );
if (strftime( dateString, dateSize, "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", gmtime( &site.lastUsed ) ))
json_object_object_add( json_site, "last_used", json_object_new_string( dateString ) );
json_object *json_site_questions = json_object_new_object();
json_object_object_add( json_site, "questions", json_site_questions );
for (int q = 0; q < site.questions_count; ++q) {
MPMarshalledQuestion question = site.questions[q];
json_object *json_site_question = json_object_new_object();
json_object_object_add( json_site_questions, question.keyword, json_site_question );
if (!redacted)
json_object_object_add( json_site_question, "answer", json_object_new_string(
mpw_passwordForSite( marshalledUser->key, site.name, MPSiteTypeGeneratedPhrase, 1,
MPSiteVariantAnswer, question.keyword, site.version ) ) );
json_object_put( json_site_question );
}
json_object_put( json_site_questions );
json_object *json_site_mpw = json_object_new_object();
json_object_object_add( json_site, "_ext_mpw", json_site_mpw );
json_object_object_add( json_site_mpw, "url", json_object_new_string( site.url ) );
json_object_put( json_site_mpw );
json_object_put( json_site );
}
json_object_put( json_sites );
try_asprintf( out, "%s\n", json_object_to_json_string_ext( json_out, JSON_C_TO_STRING_PRETTY ) );
json_object_put( json_out );
return true;
}
bool mpw_marshall_write(
char **out, const MPMarshallFormat outFormat, bool redacted,
const MPMarshalledUser *marshalledUser) {
switch (outFormat) {
case MPMarshallFormatFlat:
return mpw_marshall_write_flat( out, redacted, marshalledUser );
case MPMarshallFormatJSON:
return mpw_marshall_write_json( out, redacted, marshalledUser );
}
return false;
}
MPMarshalledUser mpw_marshall_read_flat(
char *in) {
// // Compile patterns.
// static NSRegularExpression *headerPattern;
// static NSArray *sitePatterns;
// NSError *error = NULL;
// if (!headerPattern) {
// headerPattern = [[NSRegularExpression alloc]
// initWithPattern:"^#[[:space:]]*([^:]+): (.*)"
// options:(NSRegularExpressionOptions)0 error:&error];
// if (error) {
// MPError( error, "Error loading the header pattern." );
// return MPImportResultInternalError;
// }
// }
// if (!sitePatterns) {
// sitePatterns = @[
// [[NSRegularExpression alloc] // Format 0
// initWithPattern:"^([^ ]+) +([[:digit:]]+) +([[:digit:]]+)(:[[:digit:]]+)? +([^\t]+)\t(.*)"
// options:(NSRegularExpressionOptions)0 error:&error],
// [[NSRegularExpression alloc] // Format 1
// initWithPattern:"^([^ ]+) +([[:digit:]]+) +([[:digit:]]+)(:[[:digit:]]+)?(:[[:digit:]]+)? +([^\t]*)\t *([^\t]+)\t(.*)"
// options:(NSRegularExpressionOptions)0 error:&error]
// ];
// if (error) {
// MPError( error, "Error loading the site patterns." );
// return MPImportResultInternalError;
// }
// }
//
// Parse import data.
int importFormat = 0;
MPMarshalledUser user;
int importAvatar = -1;
int importKeyID;
char *importUserName = NULL;
MPAlgorithmVersion importAlgorithm = MPAlgorithmVersionCurrent;
MPSiteType importDefaultType = (MPSiteType)0;
bool headerStarted = false, headerEnded = false, clearText = false;
// NSMutableSet *sitesToDelete = [NSMutableSet set];
// NSMutableArray *importedSiteSites = [NSMutableArray arrayWithCapacity:[importedSiteLines count]];
// NSFetchRequest *siteFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
// for (NSString *importedSiteLine in importedSiteLines) {
// if ([importedSiteLine hasPrefix:"#"]) {
// // Comment or header
// if (!headerStarted) {
// if ([importedSiteLine isEqualToString:"##"])
// headerStarted = YES;
// continue;
// }
// if (headerEnded)
// continue;
// if ([importedSiteLine isEqualToString:"##"]) {
// headerEnded = YES;
// continue;
// }
//
// // Header
// if ([headerPattern numberOfMatchesInString:importedSiteLine options:(NSMatchingOptions)0
// range:NSMakeRange( 0, [importedSiteLine length] )] != 1) {
// err( "Invalid header format in line: %", importedSiteLine );
// return MPImportResultMalformedInput;
// }
// NSTextCheckingResult *headerSites = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0
// range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
// NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]];
// NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]];
//
// if ([headerName isEqualToString:"Format"]) {
// importFormat = (NSUInteger)[headerValue integerValue];
// if (importFormat >= [sitePatterns count]) {
// err( "Unsupported import format: %lu", (unsigned long)importFormat );
// return MPImportResultInternalError;
// }
// }
// if (([headerName isEqualToString:"User Name"] || [headerName isEqualToString:"Full Name"]) && !importUserName) {
// importUserName = headerValue;
//
// NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
// userFetchRequest.predicate = [NSPredicate predicateWithFormat:"name == %", importUserName];
// NSArray *users = [context executeFetchRequest:userFetchRequest error:&error];
// if (!users) {
// MPError( error, "While looking for user: %@.", importUserName );
// return MPImportResultInternalError;
// }
// if ([users count] > 1) {
// err( "While looking for user: %@, found more than one: %lu", importUserName, (unsigned long)[users count] );
// return MPImportResultInternalError;
// }
//
// user = [users lastObject];
// dbg( "Existing user? %", [user debugDescription] );
// }
// if ([headerName isEqualToString:"Avatar"])
// importAvatar = (NSUInteger)[headerValue integerValue];
// if ([headerName isEqualToString:"Key ID"])
// importKeyID = [headerValue decodeHex];
// if ([headerName isEqualToString:"Version"]) {
// importBundleVersion = headerValue;
// importAlgorithm = MPAlgorithmDefaultForBundleVersion( importBundleVersion );
// }
// if ([headerName isEqualToString:"Algorithm"])
// importAlgorithm = MPAlgorithmForVersion( (MPAlgorithmVersion)[headerValue integerValue] );
// if ([headerName isEqualToString:"Default Type"])
// importDefaultType = (MPSiteType)[headerValue integerValue];
// if ([headerName isEqualToString:"Passwords"]) {
// if ([headerValue isEqualToString:"VISIBLE"])
// clearText = YES;
// }
//
// continue;
// }
// if (!headerEnded)
// continue;
// if (![importUserName length])
// return MPImportResultMalformedInput;
// if (![importedSiteLine length])
// continue;
//
// // Site
// NSRegularExpression *sitePattern = sitePatterns[importFormat];
// if ([sitePattern numberOfMatchesInString:importedSiteLine options:(NSMatchingOptions)0
// range:NSMakeRange( 0, [importedSiteLine length] )] != 1) {
// err( "Invalid site format in line: %", importedSiteLine );
// return MPImportResultMalformedInput;
// }
// NSTextCheckingResult *siteElements = [[sitePattern matchesInString:importedSiteLine options:(NSMatchingOptions)0
// range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
// NSString *lastUsed, *uses, *type, *version, *counter, *siteName, *loginName, *exportContent;
// switch (importFormat) {
// case 0:
// lastUsed = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:1]];
// uses = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:2]];
// type = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:3]];
// version = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:4]];
// if ([version length])
// version = [version substringFromIndex:1]; // Strip the leading colon.
// counter = "";
// loginName = "";
// siteName = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:5]];
// exportContent = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:6]];
// break;
// case 1:
// lastUsed = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:1]];
// uses = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:2]];
// type = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:3]];
// version = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:4]];
// if ([version length])
// version = [version substringFromIndex:1]; // Strip the leading colon.
// counter = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:5]];
// if ([counter length])
// counter = [counter substringFromIndex:1]; // Strip the leading colon.
// loginName = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:6]];
// siteName = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:7]];
// exportContent = [importedSiteLine substringWithRange:[siteElements rangeAtIndex:8]];
// break;
// default:
// err( "Unexpected import format: %lu", (unsigned long)importFormat );
// return MPImportResultInternalError;
// }
//
// // Find existing site.
// if (user) {
// siteFetchRequest.predicate = [NSPredicate predicateWithFormat:"name == %@ AND user == %", siteName, user];
// NSArray *existingSites = [context executeFetchRequest:siteFetchRequest error:&error];
// if (!existingSites) {
// MPError( error, "Lookup of existing sites failed for site: %@, user: %@.", siteName, user.userID );
// return MPImportResultInternalError;
// }
// if ([existingSites count]) {
// dbg( "Existing sites: %", existingSites );
// [sitesToDelete addObjectsFromArray:existingSites];
// }
// }
// [importedSiteSites addObject:@[ lastUsed, uses, type, version, counter, loginName, siteName, exportContent ]];
// dbg( "Will import site: lastUsed=%@, uses=%@, type=%@, version=%@, counter=%@, loginName=%@, siteName=%@, exportContent=%",
// lastUsed, uses, type, version, counter, loginName, siteName, exportContent );
// }
//
// // Ask for confirmation to import these sites and the master password of the user.
// inf( "Importing %lu sites, deleting %lu sites, for user: %", (unsigned long)[importedSiteSites count],
// (unsigned long)[sitesToDelete count], [MPUserEntity idFor:importUserName] );
// NSString *userMasterPassword = askUserPassword( user? user.name: importUserName, [importedSiteSites count],
// [sitesToDelete count] );
// if (!userMasterPassword) {
// inf( "Import cancelled." );
// return MPImportResultCancelled;
// }
// MPKey *userKey = [[MPKey alloc] initForFullName:user? user.name: importUserName withMasterPassword:userMasterPassword];
// if (user && ![[userKey keyIDForAlgorithm:user.algorithm] isEqualToData:user.keyID])
// return MPImportResultInvalidPassword;
// __block MPKey *importKey = userKey;
// if (importKeyID && ![[importKey keyIDForAlgorithm:importAlgorithm] isEqualToData:importKeyID])
// importKey = [[MPKey alloc] initForFullName:importUserName withMasterPassword:askImportPassword( importUserName )];
// if (importKeyID && ![[importKey keyIDForAlgorithm:importAlgorithm] isEqualToData:importKeyID])
// return MPImportResultInvalidPassword;
//
// // Delete existing sites.
// if (sitesToDelete.count)
// [sitesToDelete enumerateObjectsUsingBlock:^(id obj, bool *stop) {
// inf( "Deleting site: %@, it will be replaced by an imported site.", [obj name] );
// [context deleteObject:obj];
// }];
//
// // Make sure there is a user.
// if (user) {
// if (importAvatar != NSNotFound)
// user.avatar = importAvatar;
// if (importDefaultType)
// user.defaultType = importDefaultType;
// dbg( "Updating User: %", [user debugDescription] );
// }
// else {
// user = [MPUserEntity insertNewObjectInContext:context];
// user.name = importUserName;
// user.algorithm = MPAlgorithmDefault;
// user.keyID = [userKey keyIDForAlgorithm:user.algorithm];
// user.defaultType = importDefaultType?: user.algorithm.defaultType;
// if (importAvatar != NSNotFound)
// user.avatar = importAvatar;
// dbg( "Created User: %", [user debugDescription] );
// }
//
// // Import new sites.
// for (NSArray *siteElements in importedSiteSites) {
// NSDate *lastUsed = [[NSDateFormatter rfc3339DateFormatter] dateFromString:siteElements[0]];
// NSUInteger uses = (unsigned)[siteElements[1] integerValue];
// MPSiteType type = (MPSiteType)[siteElements[2] integerValue];
// MPAlgorithmVersion version = (MPAlgorithmVersion)[siteElements[3] integerValue];
// NSUInteger counter = [siteElements[4] length]? (unsigned)[siteElements[4] integerValue]: NSNotFound;
// NSString *loginName = [siteElements[5] length]? siteElements[5]: NULL;
// NSString *siteName = siteElements[6];
// NSString *exportContent = siteElements[7];
//
// // Create new site.
// id<MPAlgorithm> algorithm = MPAlgorithmForVersion( version );
// Class entityType = [algorithm classOfType:type];
// if (!entityType) {
// err( "Invalid site type in import file: %@ has type %lu", siteName, (long)type );
// return MPImportResultInternalError;
// }
// MPSiteEntity *site = (MPSiteEntity *)[entityType insertNewObjectInContext:context];
// site.name = siteName;
// site.loginName = loginName;
// site.user = user;
// site.type = type;
// site.uses = uses;
// site.lastUsed = lastUsed;
// site.algorithm = algorithm;
// if ([exportContent length]) {
// if (clearText)
// [site.algorithm importClearTextPassword:exportContent intoSite:site usingKey:userKey];
// else
// [site.algorithm importProtectedPassword:exportContent protectedByKey:importKey intoSite:site usingKey:userKey];
// }
// if ([site isKindOfClass:[MPGeneratedSiteEntity class]] && counter != NSNotFound)
// ((MPGeneratedSiteEntity *)site).counter = counter;
//
// dbg( "Created Site: %", [site debugDescription] );
// }
//
// if (![context saveToStore])
// return MPImportResultInternalError;
//
// inf( "Import completed successfully." );
//
// [[NSNotificationCenter defaultCenter] postNotificationName:MPSitesImportedNotification object:NULL userInfo:@{
// MPSitesImportedNotificationUserKey: user
// }];
//
// return MPImportResultSuccess;
return (MPMarshalledUser){};
}
MPMarshalledUser mpw_marshall_read_json(
char *in) {
return (MPMarshalledUser){};
}
MPMarshalledUser mpw_marshall_read(
char *in, const MPMarshallFormat outFormat) {
switch (outFormat) {
case MPMarshallFormatFlat:
return mpw_marshall_read_flat( in );
case MPMarshallFormatJSON:
return mpw_marshall_read_json( in );
}
return (MPMarshalledUser){};
}

94
core/c/mpw-marshall.h Normal file
View File

@ -0,0 +1,94 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#ifndef _MPW_MARSHALL_H
#define _MPW_MARSHALL_H
#include "mpw-algorithm.h"
#ifdef NS_ENUM
#define enum(_type, _name) NS_ENUM(_type, _name)
#else
#define enum(_type, _name) _type _name; enum
#endif
//// Types.
typedef enum( unsigned int, MPMarshallFormat ) {
/** Generate a key for authentication. */
MPMarshallFormatFlat,
/** Generate a name for identification. */
MPMarshallFormatJSON,
};
typedef struct MPMarshalledQuestion {
const char *keyword;
} MPMarshalledQuestion;
typedef struct MPMarshalledSite {
const char *name;
const char *content;
MPSiteType type;
uint32_t counter;
MPAlgorithmVersion version;
const char *loginName;
bool loginGenerated;
const char *url;
unsigned int uses;
time_t lastUsed;
size_t questions_count;
MPMarshalledQuestion *questions;
} MPMarshalledSite;
typedef struct MPMarshalledUser {
const char *name;
MPMasterKey key;
MPAlgorithmVersion version;
unsigned int avatar;
MPSiteType defaultType;
time_t lastUsed;
size_t sites_count;
MPMarshalledSite *sites;
} MPMarshalledUser;
//// Marshalling.
bool mpw_marshall_write(
char **out, const MPMarshallFormat outFormat, bool redacted,
const MPMarshalledUser *marshalledUser);
//// Unmarshalling.
MPMarshalledUser mpw_marshall_read(
char *in, const MPMarshallFormat outFormat);
//// Utilities.
MPMarshalledUser mpw_marshall_user(
const char *fullName, MPMasterKey masterKey, const MPAlgorithmVersion algorithmVersion);
MPMarshalledSite mpw_marshall_site(
MPMarshalledUser *marshalledUser,
const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion);
MPMarshalledQuestion mpw_marshal_question(
MPMarshalledSite *marshalledSite, const char *keyword);
#endif // _MPW_MARSHALL_H

View File

@ -143,8 +143,7 @@ const MPSiteVariant mpw_variantWithName(const char *variantName) {
if (0 == strcmp( stdVariantName, "a" ) || 0 == strcmp( stdVariantName, "answer" ))
return MPSiteVariantAnswer;
fprintf( stderr, "Not a variant name: %s", stdVariantName );
abort();
ftl( "Not a variant name: %s", stdVariantName );
}
const char *mpw_scopeForVariant(MPSiteVariant variant) {
@ -160,8 +159,7 @@ const char *mpw_scopeForVariant(MPSiteVariant variant) {
return "com.lyndir.masterpassword.answer";
}
default: {
fprintf( stderr, "Unknown variant: %d", variant );
abort();
ftl( "Unknown variant: %d", variant );
}
}
}
@ -190,8 +188,7 @@ const char *mpw_charactersInClass(char characterClass) {
case ' ':
return " ";
default: {
fprintf( stderr, "Unknown character class: %c", characterClass );
abort();
ftl( "Unknown character class: %c", characterClass );
}
}
}

View File

@ -20,6 +20,7 @@
#define _MPW_TYPES_H
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef NS_ENUM
#define enum(_type, _name) NS_ENUM(_type, _name)
@ -27,10 +28,11 @@
#define enum(_type, _name) _type _name; enum
#endif
#define MP_dkLen 64
//// Types.
#define MPMasterKeySize 64
typedef const uint8_t *MPMasterKey;
typedef enum( unsigned int, MPSiteVariant ) {
/** Generate a key for authentication. */
MPSiteVariantPassword,
@ -54,7 +56,7 @@ typedef enum( unsigned int, MPSiteFeature ) {
MPSiteFeatureDevicePrivate = 1 << 11,
};
typedef enum( unsigned int, MPSiteType) {
typedef enum( unsigned int, MPSiteType ) {
MPSiteTypeGeneratedMaximum = 0x0 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedLong = 0x1 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedMedium = 0x2 | MPSiteTypeClassGenerated | 0x0,

View File

@ -20,7 +20,7 @@
#include <stdlib.h>
#include <string.h>
#if COLOR
#if MPW_COLOR
#include <unistd.h>
#include <curses.h>
#include <term.h>
@ -33,17 +33,14 @@
#include "sodium.h"
#endif
#ifndef trc
int mpw_verbosity;
#endif
#include "mpw-util.h"
int mpw_verbosity = inf_level;
void mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
if (*bufferSize == (size_t)-1)
// The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content.
return;
return false;
*bufferSize += pushSize;
uint8_t *resizedBuffer = realloc( *buffer, *bufferSize );
@ -52,35 +49,38 @@ void mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
mpw_free( *buffer, *bufferSize - pushSize );
*bufferSize = (size_t)-1;
*buffer = NULL;
return;
return false;
}
*buffer = resizedBuffer;
uint8_t *pushDst = *buffer + *bufferSize - pushSize;
memcpy( pushDst, pushBuffer, pushSize );
return true;
}
void mpw_push_string(uint8_t **buffer, size_t *const bufferSize, const char *pushString) {
bool mpw_push_string(uint8_t **buffer, size_t *const bufferSize, const char *pushString) {
mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
return mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
}
void mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
bool mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
}
void mpw_free(const void *buffer, const size_t bufferSize) {
bool mpw_free(const void *buffer, const size_t bufferSize) {
if (!buffer)
return false;
if (buffer) {
memset( (void *)buffer, 0, bufferSize );
free( (void *)buffer );
}
return true;
}
void mpw_free_string(const char *string) {
bool mpw_free_string(const char *string) {
mpw_free( string, strlen( string ) );
return mpw_free( string, strlen( string ) );
}
uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize,

View File

@ -17,7 +17,10 @@
//==============================================================================
#include <stdio.h>
#include <stdint.h>
#include "mpw-types.h"
#ifndef _MPW_UTIL_H
#define _MPW_UTIL_H
//// Logging.
@ -25,41 +28,39 @@
extern int mpw_verbosity;
#define trc_level 3
#define trc(...) \
if (mpw_verbosity >= 3) \
fprintf( stderr, __VA_ARGS__ )
({ if (mpw_verbosity >= 3) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef dbg
#define dbg_level 2
#define dbg(...) \
if (mpw_verbosity >= 2) \
fprintf( stderr, __VA_ARGS__ )
({ if (mpw_verbosity >= 2) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef inf
#define inf_level 1
#define inf(...) \
if (mpw_verbosity >= 1) \
fprintf( stderr, __VA_ARGS__ )
({ if (mpw_verbosity >= 1) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef wrn
#define wrn_level 0
#define wrn(...) \
if (mpw_verbosity >= 0) \
fprintf( stderr, __VA_ARGS__ )
({ if (mpw_verbosity >= 0) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef err
#define err_level -1
#define err(...) \
if (mpw_verbosity >= -1) \
fprintf( stderr, __VA_ARGS__ )
({ if (mpw_verbosity >= -1) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef ftl
#define ftl_level -2
#define ftl(...) \
do { \
if (mpw_verbosity >= -2) \
({ if (mpw_verbosity >= -2) \
fprintf( stderr, __VA_ARGS__ ); \
exit( 2 ); \
} while (0)
exit( 2 ); })
#endif
//// Buffers and memory.
@ -73,19 +74,19 @@ extern int mpw_verbosity;
})
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
void mpw_push_buf(
bool mpw_push_buf(
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize);
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
void mpw_push_string(
bool mpw_push_string(
uint8_t **buffer, size_t *const bufferSize, const char *pushString);
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
void mpw_push_int(
bool mpw_push_int(
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
/** Free a buffer after zero'ing its contents. */
void mpw_free(
bool mpw_free(
const void *buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents. */
void mpw_free_string(
bool mpw_free_string(
const char *string);
//// Cryptographic functions.
@ -117,3 +118,5 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword);
/** @return The amount of display characters in the given UTF-8 string. */
const size_t mpw_utf8_strlen(const char *utf8String);
#endif // _MPW_UTIL_H

View File

@ -248,6 +248,7 @@
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; };
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */; };
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; };
@ -855,6 +856,8 @@
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
DABD360F1711E29400CF925C /* ui_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ui_background.png; sourceTree = "<group>"; };
@ -1722,6 +1725,8 @@
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */,
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */,
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
93D39AFD17CBE324D745DAB0 /* mpw-types.h */,
93D396C311C3725870343EE0 /* mpw-util.c */,
@ -3862,6 +3867,7 @@
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m in Sources */,
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */,
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,

View File

@ -23,8 +23,6 @@
93D39F833DEC1C89B2F795AC /* MPSitesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A57A7823DE98A0FF83C /* MPSitesWindowController.m */; };
DA0933CC1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */; };
DA0933D01747B91B00DE1CEF /* appstore.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0933CF1747B91B00DE1CEF /* appstore.png */; };
DA09745A1E99582900F0BFE8 /* mpw-tests-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA0974561E99582200F0BFE8 /* mpw-tests-util.c */; };
DA09745B1E99582900F0BFE8 /* mpw-tests.c in Sources */ = {isa = PBXBuildFile; fileRef = DA0974571E99582200F0BFE8 /* mpw-tests.c */; };
DA09745E1E99586600F0BFE8 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA09745D1E99586600F0BFE8 /* libxml2.tbd */; };
DA0979681E9A834C00F0BFE8 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
DA0CC53E1EB57B69009A8ED9 /* Fabric.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0CC53D1EB57B69009A8ED9 /* Fabric.plist */; };
@ -34,6 +32,22 @@
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
DA1C7AAF1F1A8F24009A3551 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
DA1C7AB01F1A8F24009A3551 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA09745D1E99586600F0BFE8 /* libxml2.tbd */; };
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */ = {isa = PBXBuildFile; fileRef = DA1C7AB91F1A8F6E009A3551 /* mpw-cli.c */; };
DA1C7AC81F1A8FD8009A3551 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
DA1C7ACF1F1A8FD8009A3551 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
DA1C7AD01F1A8FD8009A3551 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA09745D1E99586600F0BFE8 /* libxml2.tbd */; };
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */ = {isa = PBXBuildFile; fileRef = DA1C7AB81F1A8F6E009A3551 /* mpw-bench.c */; };
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA1C7ABA1F1A8F6E009A3551 /* mpw-tests-util.c */; };
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */ = {isa = PBXBuildFile; fileRef = DA1C7ABC1F1A8F6E009A3551 /* mpw-tests.c */; };
DA2508F119511D3600AC23F1 /* MPPasswordWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */; };
DA250925195148E200AC23F1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DA26861D1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = DA26860A1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataClass.m */; };
@ -70,6 +84,7 @@
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
DA5180CA19FF2F9200A587E9 /* MPAlgorithmV2.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5180C719FF2F9200A587E9 /* MPAlgorithmV2.m */; };
DA5180CE19FF307E00A587E9 /* MPAppDelegate_Store.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5180CD19FF307E00A587E9 /* MPAppDelegate_Store.m */; };
DA531CC31EFF3BF4008C72CB /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C981724A667003798D8 /* MPAlgorithm.m */; };
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C9A1724A667003798D8 /* MPAlgorithmV0.m */; };
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5E5C9C1724A667003798D8 /* MPAlgorithmV1.m */; };
@ -103,6 +118,7 @@
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; };
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; };
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
@ -234,6 +250,24 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
DA1C7AB11F1A8F24009A3551 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
DA1C7AD11F1A8FD8009A3551 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
DA6774391A474A03004F356A /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@ -291,9 +325,6 @@
DA0933C91747A56A00DE1CEF /* MPInitialWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPInitialWindow.xib; sourceTree = "<group>"; };
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = "<group>"; };
DA0933CF1747B91B00DE1CEF /* appstore.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = appstore.png; sourceTree = "<group>"; };
DA0974561E99582200F0BFE8 /* mpw-tests-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mpw-tests-util.c"; path = "../../platform-independent/cli-c/cli/mpw-tests-util.c"; sourceTree = "<group>"; };
DA0974571E99582200F0BFE8 /* mpw-tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "mpw-tests.c"; path = "../../platform-independent/cli-c/cli/mpw-tests.c"; sourceTree = "<group>"; };
DA09745C1E99583B00F0BFE8 /* mpw-tests-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mpw-tests-util.h"; path = "../../platform-independent/cli-c/cli/mpw-tests-util.h"; sourceTree = "<group>"; };
DA09745D1E99586600F0BFE8 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; };
DA09745F1E995EB500F0BFE8 /* mpw_tests.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = mpw_tests.xml; path = ../../core/java/tests/src/main/resources/mpw_tests.xml; sourceTree = "<group>"; };
DA09791B1E9A824700F0BFE8 /* core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = core.h; sourceTree = "<group>"; };
@ -367,6 +398,13 @@
DA0CC5581EB6AE45009A8ED9 /* MasterPassword 9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 9.xcdatamodel"; sourceTree = "<group>"; };
DA16B340170661DB000A0EAB /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
DA16B343170661EE000A0EAB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
DA1C7AB61F1A8F24009A3551 /* mpw-cli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-cli"; sourceTree = BUILT_PRODUCTS_DIR; };
DA1C7AB81F1A8F6E009A3551 /* mpw-bench.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-bench.c"; sourceTree = "<group>"; };
DA1C7AB91F1A8F6E009A3551 /* mpw-cli.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli.c"; sourceTree = "<group>"; };
DA1C7ABA1F1A8F6E009A3551 /* mpw-tests-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-tests-util.c"; sourceTree = "<group>"; };
DA1C7ABB1F1A8F6E009A3551 /* mpw-tests-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-tests-util.h"; sourceTree = "<group>"; };
DA1C7ABC1F1A8F6E009A3551 /* mpw-tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-tests.c"; sourceTree = "<group>"; };
DA1C7AD61F1A8FD8009A3551 /* mpw-bench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-bench"; sourceTree = BUILT_PRODUCTS_DIR; };
DA2508F019511D3600AC23F1 /* MPPasswordWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MPPasswordWindowController.xib; sourceTree = "<group>"; };
DA2508F919513C1400AC23F1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
DA2508FA19513C1400AC23F1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
@ -874,6 +912,8 @@
DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; };
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
@ -999,6 +1039,24 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
DA1C7AAE1F1A8F24009A3551 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DA1C7AAF1F1A8F24009A3551 /* libsodium.a in Frameworks */,
DA1C7AB01F1A8F24009A3551 /* libxml2.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA1C7ACE1F1A8FD8009A3551 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DA1C7ACF1F1A8FD8009A3551 /* libsodium.a in Frameworks */,
DA1C7AD01F1A8FD8009A3551 /* libxml2.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA5BFA41147E415C00F98B1E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -1156,6 +1214,19 @@
path = Fabric;
sourceTree = "<group>";
};
DA1C7AB71F1A8F6E009A3551 /* cli */ = {
isa = PBXGroup;
children = (
DA1C7AB81F1A8F6E009A3551 /* mpw-bench.c */,
DA1C7AB91F1A8F6E009A3551 /* mpw-cli.c */,
DA1C7ABA1F1A8F6E009A3551 /* mpw-tests-util.c */,
DA1C7ABB1F1A8F6E009A3551 /* mpw-tests-util.h */,
DA1C7ABC1F1A8F6E009A3551 /* mpw-tests.c */,
);
name = cli;
path = "../../platform-independent/cli-c/cli";
sourceTree = "<group>";
};
DA2508F819513C1400AC23F1 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
@ -1196,6 +1267,8 @@
DAC6326C148680650075AEA5 /* libjrswizzle.a */,
DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */,
DA67743B1A474A03004F356A /* mpw-test */,
DA1C7AB61F1A8F24009A3551 /* mpw-cli */,
DA1C7AD61F1A8FD8009A3551 /* mpw-bench */,
);
name = Products;
sourceTree = "<group>";
@ -1734,15 +1807,15 @@
DA6773291A4746AF004F356A /* C */ = {
isa = PBXGroup;
children = (
DA1C7AB71F1A8F6E009A3551 /* cli */,
DA831A271A6E1146000AC234 /* mpw-algorithm_v0.c */,
DA831A281A6E1146000AC234 /* mpw-algorithm_v1.c */,
DA831A291A6E1146000AC234 /* mpw-algorithm_v2.c */,
DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */,
DA6773BB1A4746AF004F356A /* mpw-algorithm.c */,
DA6773BC1A4746AF004F356A /* mpw-algorithm.h */,
DA0974561E99582200F0BFE8 /* mpw-tests-util.c */,
DA09745C1E99583B00F0BFE8 /* mpw-tests-util.h */,
DA0974571E99582200F0BFE8 /* mpw-tests.c */,
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */,
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */,
DA6773C21A4746AF004F356A /* mpw-types.c */,
DA6773C31A4746AF004F356A /* mpw-types.h */,
DA6773C51A4746AF004F356A /* mpw-util.c */,
@ -2101,6 +2174,40 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
DA1C7AA61F1A8F24009A3551 /* mpw-cli */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA1C7AB21F1A8F24009A3551 /* Build configuration list for PBXNativeTarget "mpw-cli" */;
buildPhases = (
DA1C7AA71F1A8F24009A3551 /* Sources */,
DA1C7AAE1F1A8F24009A3551 /* Frameworks */,
DA1C7AB11F1A8F24009A3551 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "mpw-cli";
productName = "mpw-test";
productReference = DA1C7AB61F1A8F24009A3551 /* mpw-cli */;
productType = "com.apple.product-type.tool";
};
DA1C7AC61F1A8FD8009A3551 /* mpw-bench */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA1C7AD21F1A8FD8009A3551 /* Build configuration list for PBXNativeTarget "mpw-bench" */;
buildPhases = (
DA1C7AC71F1A8FD8009A3551 /* Sources */,
DA1C7ACE1F1A8FD8009A3551 /* Frameworks */,
DA1C7AD11F1A8FD8009A3551 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = "mpw-bench";
productName = "mpw-test";
productReference = DA1C7AD61F1A8FD8009A3551 /* mpw-bench */;
productType = "com.apple.product-type.tool";
};
DA5BFA43147E415C00F98B1E /* MasterPassword */ = {
isa = PBXNativeTarget;
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
@ -2205,6 +2312,12 @@
LastUpgradeCheck = 0830;
ORGANIZATIONNAME = Lyndir;
TargetAttributes = {
DA1C7AA61F1A8F24009A3551 = {
DevelopmentTeam = HL3Q45LX9N;
};
DA1C7AC61F1A8FD8009A3551 = {
DevelopmentTeam = HL3Q45LX9N;
};
DA5BFA43147E415C00F98B1E = {
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
@ -2254,6 +2367,8 @@
DAC6326B148680650075AEA5 /* jrswizzle */,
DAADCC4F19FB006500987B1D /* KCOrderedAccessorFix */,
DA67743A1A474A03004F356A /* mpw-test */,
DA1C7AC61F1A8FD8009A3551 /* mpw-bench */,
DA1C7AA61F1A8F24009A3551 /* mpw-cli */,
);
};
/* End PBXProject section */
@ -2403,6 +2518,30 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
DA1C7AA71F1A8F24009A3551 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */,
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA1C7AC71F1A8FD8009A3551 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA1C7AC81F1A8FD8009A3551 /* mpw-marshall.c in Sources */,
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */,
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */,
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */,
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DA5BFA40147E415C00F98B1E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -2411,6 +2550,7 @@
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.m in Sources */,
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */,
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */,
DA26861E1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */,
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
@ -2453,10 +2593,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DA09745B1E99582900F0BFE8 /* mpw-tests.c in Sources */,
DA09745A1E99582900F0BFE8 /* mpw-tests-util.c in Sources */,
DA531CC31EFF3BF4008C72CB /* mpw-marshall.c in Sources */,
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */,
DA6774451A474A3B004F356A /* mpw-types.c in Sources */,
DA6774461A474A3B004F356A /* mpw-util.c in Sources */,
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */,
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2724,12 +2865,8 @@
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/Pearl/Pearl-Crypto/lib",
/usr/local/Cellar/libsodium/1.0.12/lib,
/usr/local/Cellar/libscrypt/1.21/lib,
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
@ -2738,6 +2875,138 @@
};
name = Test;
};
DA1C7AB31F1A8F24009A3551 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DA1C7AB41F1A8F24009A3551 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DA1C7AB51F1A8F24009A3551 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DA1C7AD31F1A8FD8009A3551 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DA1C7AD41F1A8FD8009A3551 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DA1C7AD51F1A8FD8009A3551 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DA5BFA6B147E415C00F98B1E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -2987,12 +3256,8 @@
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/Pearl/Pearl-Crypto/lib",
/usr/local/Cellar/libsodium/1.0.12/lib,
/usr/local/Cellar/libscrypt/1.21/lib,
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
@ -3012,12 +3277,8 @@
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/Pearl/Pearl-Crypto/lib",
/usr/local/Cellar/libsodium/1.0.12/lib,
/usr/local/Cellar/libscrypt/1.21/lib,
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
@ -3097,6 +3358,26 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
DA1C7AB21F1A8F24009A3551 /* Build configuration list for PBXNativeTarget "mpw-cli" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA1C7AB31F1A8F24009A3551 /* Debug */,
DA1C7AB41F1A8F24009A3551 /* Release */,
DA1C7AB51F1A8F24009A3551 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DA1C7AD21F1A8FD8009A3551 /* Build configuration list for PBXNativeTarget "mpw-bench" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA1C7AD31F1A8FD8009A3551 /* Debug */,
DA1C7AD41F1A8FD8009A3551 /* Release */,
DA1C7AD51F1A8FD8009A3551 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-macOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@ -49,7 +49,7 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (BOOL)tryMigrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc;
- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit;
- (NSData *)keyIDForKeyData:(NSData *)keyData;
- (NSData *)keyIDForKey:(MPMasterKey)masterKey;
- (NSData *)keyDataForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword;
- (NSString *)nameOfType:(MPSiteType)type;

View File

@ -128,21 +128,21 @@ static NSOperationQueue *_mpwQueue = nil;
__block NSData *keyData;
[self mpw_perform:^{
NSDate *start = [NSDate date];
uint8_t const *masterKeyBytes = mpw_masterKeyForUser( fullName.UTF8String, masterPassword.UTF8String, [self version] );
if (masterKeyBytes) {
keyData = [NSData dataWithBytes:masterKeyBytes length:MP_dkLen];
MPMasterKey masterKey = mpw_masterKeyForUser( fullName.UTF8String, masterPassword.UTF8String, [self version] );
if (masterKey) {
keyData = [NSData dataWithBytes:masterKey length:MPMasterKeySize];
trc( @"User: %@, password: %@ derives to key ID: %@ (took %0.2fs)", //
fullName, masterPassword, [self keyIDForKeyData:keyData], -[start timeIntervalSinceNow] );
mpw_free( masterKeyBytes, MP_dkLen );
fullName, masterPassword, [self keyIDForKey:masterKey], -[start timeIntervalSinceNow] );
mpw_free( masterKey, MPMasterKeySize );
}
}];
return keyData;
}
- (NSData *)keyIDForKeyData:(NSData *)keyData {
- (NSData *)keyIDForKey:(MPMasterKey)masterKey {
return [keyData hashWith:PearlHashSHA256];
return [[NSData dataWithBytesNoCopy:(void *)masterKey length:MPMasterKeySize] hashWith:PearlHashSHA256];
}
- (NSString *)nameOfType:(MPSiteType)type {
@ -350,9 +350,9 @@ static NSOperationQueue *_mpwQueue = nil;
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant context:(NSString *)context usingKey:(MPKey *)key {
__block NSString *content;
__block NSString *content = nil;
[self mpw_perform:^{
char const *contentBytes = mpw_passwordForSite( [key keyDataForAlgorithm:self].bytes,
char const *contentBytes = mpw_passwordForSite( [key keyForAlgorithm:self],
name.UTF8String, type, (uint32_t)counter, variant, context.UTF8String, [self version] );
if (contentBytes) {
content = [NSString stringWithCString:contentBytes encoding:NSUTF8StringEncoding];
@ -396,7 +396,7 @@ static NSOperationQueue *_mpwQueue = nil;
return NO;
}
NSData *encryptionKey = [siteKey keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptionKey = [siteKey keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:encryptionKey padding:YES];
if ([((MPStoredSiteEntity *)site).contentObject isEqualToData:encryptedContent])
@ -412,7 +412,7 @@ static NSOperationQueue *_mpwQueue = nil;
return NO;
}
NSData *encryptionKey = [siteKey keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptionKey = [siteKey keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:encryptionKey padding:YES];
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
@ -713,7 +713,7 @@ static NSOperationQueue *_mpwQueue = nil;
return nil;
NSData *decryptedContent = nil;
if ([encryptedContent length]) {
NSData *encryptionKey = [key keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptionKey = [key keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
decryptedContent = [encryptedContent decryptWithSymmetricKey:encryptionKey padding:YES];
}
if (!decryptedContent)

View File

@ -95,13 +95,14 @@
- (void)storeSavedKeyFor:(MPUserEntity *)user {
if (user.saveKey) {
NSData *keyData = [self.key keyDataForAlgorithm:user.algorithm];
if (keyData) {
MPMasterKey masterKey = [self.key keyForAlgorithm:user.algorithm];
if (masterKey) {
[self forgetSavedKeyFor:user];
inf( @"Saving key in keychain for user: %@", user.userID );
[PearlKeyChain addOrUpdateItemForQuery:[self createKeyQueryforUser:user origin:nil]
withAttributes:@{ (__bridge id)kSecValueData: keyData }];
[PearlKeyChain addOrUpdateItemForQuery:[self createKeyQueryforUser:user origin:nil] withAttributes:@{
(__bridge id)kSecValueData: [NSData dataWithBytesNoCopy:(void *)masterKey length:MPMasterKeySize]
}];
}
}
}

View File

@ -17,6 +17,7 @@
//==============================================================================
#import "MPAppDelegate_Store.h"
#import "mpw-marshall.h"
#if TARGET_OS_IPHONE
#define STORE_OPTIONS NSPersistentStoreFileProtectionKey : NSFileProtectionComplete,
@ -840,68 +841,26 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
MPUserEntity *activeUser = [self activeUserForMainThread];
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", activeUser.userID );
// Header.
NSMutableString *export = [NSMutableString new];
[export appendFormat:@"# Master Password site export\n"];
if (revealPasswords)
[export appendFormat:@"# Export of site names and passwords in clear-text.\n"];
else
[export appendFormat:@"# Export of site names and stored passwords (unless device-private) encrypted with the master key.\n"];
[export appendFormat:@"# \n"];
[export appendFormat:@"##\n"];
[export appendFormat:@"# Format: 1\n"];
[export appendFormat:@"# Date: %@\n", [[NSDateFormatter rfc3339DateFormatter] stringFromDate:[NSDate date]]];
[export appendFormat:@"# User Name: %@\n", activeUser.name];
[export appendFormat:@"# Full Name: %@\n", activeUser.name];
[export appendFormat:@"# Avatar: %lu\n", (unsigned long)activeUser.avatar];
[export appendFormat:@"# Key ID: %@\n", [activeUser.keyID encodeHex]];
[export appendFormat:@"# Version: %@\n", [PearlInfoPlist get].CFBundleVersion];
[export appendFormat:@"# Algorithm: %d\n", activeUser.algorithm.version];
[export appendFormat:@"# Default Type: %d\n", activeUser.defaultType];
[export appendFormat:@"# Passwords: %@\n", revealPasswords? @"VISIBLE": @"PROTECTED"];
[export appendFormat:@"##\n"];
[export appendFormat:@"#\n"];
[export appendFormat:@"# Last Times Password Login\t Site\tSite\n"];
[export appendFormat:@"# used used type name\t name\tpassword\n"];
MPMarshalledUser exportUser = mpw_marshall_user( activeUser.name.UTF8String,
[self.key keyForAlgorithm:activeUser.algorithm], activeUser.algorithm.version );
exportUser.avatar = activeUser.avatar;
exportUser.defaultType = activeUser.defaultType;
exportUser.lastUsed = (time_t)activeUser.lastUsed.timeIntervalSince1970;
// Sites.
for (MPSiteEntity *site in activeUser.sites) {
NSDate *lastUsed = site.lastUsed;
NSUInteger uses = site.uses;
MPSiteType type = site.type;
id<MPAlgorithm> algorithm = site.algorithm;
NSUInteger counter = 0;
NSString *loginName = site.loginName;
NSString *siteName = site.name;
NSString *content = nil;
MPMarshalledSite exportSite = mpw_marshall_site( &exportUser,
site.name.UTF8String, site.type, site.counter, site.algorithm.version );
exportSite.loginName = site.loginName.UTF8String;
exportSite.url = site.url.UTF8String;
exportSite.uses = site.uses;
exportSite.lastUsed = (time_t)site.lastUsed.timeIntervalSince1970;
// Generated-specific
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
counter = ((MPGeneratedSiteEntity *)site).counter;
// Determine the content to export.
if (!(type & MPSiteFeatureDevicePrivate)) {
if (revealPasswords)
content = [site.algorithm resolvePasswordForSite:site usingKey:self.key];
else if (type & MPSiteFeatureExportContent)
content = [site.algorithm exportPasswordForSite:site usingKey:self.key];
for (MPSiteQuestionEntity *siteQuestion in site.questions)
mpw_marshal_question( &exportSite, siteQuestion.keyword.UTF8String );
}
NSString *lastUsedExport = [[NSDateFormatter rfc3339DateFormatter] stringFromDate:lastUsed];
long usesExport = (long)uses;
NSString *typeExport = strf( @"%lu:%lu:%lu", (long)type, (long)[algorithm version], (long)counter );
NSString *loginNameExport = loginName?: @"";
NSString *contentExport = content?: @"";
[export appendFormat:@"%@ %8ld %8S %25S\t%25S\t%@\n",
lastUsedExport, usesExport,
(const unsigned short *)[typeExport cStringUsingEncoding:NSUTF16StringEncoding],
(const unsigned short *)[loginNameExport cStringUsingEncoding:NSUTF16StringEncoding],
(const unsigned short *)[siteName cStringUsingEncoding:NSUTF16StringEncoding],
contentExport];
}
return export;
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser );
}
@end

View File

@ -18,6 +18,7 @@
#import <Foundation/Foundation.h>
#import "MPAlgorithm.h"
#import "mpw-types.h"
@protocol MPAlgorithm;
@ -37,8 +38,7 @@ typedef NS_ENUM( NSUInteger, MPKeyOrigin ) {
keyOrigin:(MPKeyOrigin)origin;
- (NSData *)keyIDForAlgorithm:(id<MPAlgorithm>)algorithm;
- (NSData *)keyDataForAlgorithm:(id<MPAlgorithm>)algorithm;
- (NSData *)keyDataForAlgorithm:(id<MPAlgorithm>)algorithm trimmedLength:(NSUInteger)subKeyLength;
- (MPMasterKey)keyForAlgorithm:(id<MPAlgorithm>)algorithm;
- (BOOL)isEqualToKey:(MPKey *)key;

View File

@ -53,28 +53,21 @@
- (NSData *)keyIDForAlgorithm:(id<MPAlgorithm>)algorithm {
return [algorithm keyIDForKeyData:[self keyDataForAlgorithm:algorithm]];
return [algorithm keyIDForKey:[self keyForAlgorithm:algorithm]];
}
- (NSData *)keyDataForAlgorithm:(id<MPAlgorithm>)algorithm {
- (MPMasterKey)keyForAlgorithm:(id<MPAlgorithm>)algorithm {
@synchronized (self) {
NSData *keyData = [self.keyCache objectForKey:algorithm];
if (keyData)
return keyData;
if (!keyData) {
keyData = self.keyResolver( algorithm );
if (keyData)
[self.keyCache setObject:keyData forKey:algorithm];
return keyData;
}
}
- (NSData *)keyDataForAlgorithm:(id<MPAlgorithm>)algorithm trimmedLength:(NSUInteger)subKeyLength {
NSData *keyData = [self keyDataForAlgorithm:algorithm];
return [keyData subdataWithRange:NSMakeRange( 0, MIN( subKeyLength, keyData.length ) )];
return keyData.length == MPMasterKeySize? keyData.bytes: NULL;
}
}
- (BOOL)isEqualToKey:(MPKey *)key {
@ -84,10 +77,7 @@
- (BOOL)isEqual:(id)object {
if (![object isKindOfClass:[MPKey class]])
return NO;
return [self isEqualToKey:object];
return [object isKindOfClass:[MPKey class]] && [self isEqualToKey:object];
}
@end

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="Q1S-vU-GGO">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<capability name="Alignment constraints with different attributes" minToolsVersion="5.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
@ -103,7 +103,7 @@
</constraints>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Sa-Vg-EEI" userLabel="Name Backdrop">
<rect key="frame" x="44" y="263" width="128.5" height="16"/>
<rect key="frame" x="43.5" y="263" width="128.5" height="16"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="1000" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cLT-s0-4SQ" userLabel="Name Field">
<rect key="frame" x="5" y="0.0" width="118.5" height="16"/>
@ -1629,7 +1629,7 @@
</connections>
</searchBar>
<view hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LEX-BK-PdS" userLabel="Bad Name Tip">
<rect key="frame" x="38" y="86" width="300.5" height="75.5"/>
<rect key="frame" x="37.5" y="86" width="300.5" height="75.5"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black_top.png" translatesAutoresizingMaskIntoConstraints="NO" id="Rt5-v4-I0R">
<rect key="frame" x="0.0" y="0.0" width="300.5" height="75.5"/>
@ -1771,7 +1771,7 @@ eg. apple.com, rmitchell@twitter.com</string>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1lc-e7-Qme" userLabel="Emergency Generator">
<rect key="frame" x="20" y="135" width="335" height="397.5"/>
<rect key="frame" x="20" y="135.5" width="335" height="397.5"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Emergency Generator" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="4Lh-s0-Dbt">
<rect key="frame" x="20" y="20" width="295" height="21"/>

View File

@ -40,6 +40,7 @@ fi
# Optional features.
mpw_color=${mpw_color:-1} # Colorized Identicon, requires libncurses-dev.
mpw_json=${mpw_json:-1} # Support for JSON-based user configuration format.
mpw_sodium=${mpw_sodium:-1} # Use libsodium if available instead of cperciva's libscrypt.
# Default build flags.
@ -255,12 +256,14 @@ mpw() {
-l"crypto"
)
# optional features
(( mpw_color )) && CFLAGS+=( -DCOLOR ) LDFLAGS+=( -l"curses" )
(( mpw_color )) && CFLAGS+=( -DMPW_COLOR ) LDFLAGS+=( -l"curses" )
(( mpw_json )) && CFLAGS+=( -DMPW_JSON ) LDFLAGS+=( -l"json-c" )
cc "${CFLAGS[@]}" "$@" -c core/mpw-algorithm.c -o core/mpw-algorithm.o
cc "${CFLAGS[@]}" "$@" -c core/mpw-types.c -o core/mpw-types.o
cc "${CFLAGS[@]}" "$@" -c core/mpw-util.c -o core/mpw-util.o
cc "${CFLAGS[@]}" "$@" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \
cc "${CFLAGS[@]}" "$@" -c core/mpw-marshall.c -o core/mpw-marshall.o
cc "${CFLAGS[@]}" "$@" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" "core/mpw-marshall.o" \
"${LDFLAGS[@]}" "cli/mpw-cli.c" -o "mpw"
echo "done! Now run ./install or use ./mpw"
}

View File

@ -65,13 +65,11 @@ int main(int argc, char *const argv[]) {
uint8_t *sitePasswordInfo = malloc( 128 );
iterations = 3000000;
masterKey = mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent );
if (!masterKey) {
if (!masterKey)
ftl( "Could not allocate master key: %d\n", errno );
abort();
}
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
free( (void *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, 128 ) );
free( (void *)mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, 128 ) );
if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rhmac-sha-256: iteration %d / %d (%.0f%%)..", i, iterations, percent );
@ -110,10 +108,8 @@ int main(int argc, char *const argv[]) {
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
masterKey = mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent );
if (!masterKey) {
if (!masterKey)
ftl( "Could not allocate master key: %d\n", errno );
abort();
}
free( (void *)mpw_passwordForSite(
masterKey, siteName, siteType, siteCounter, siteVariant, siteContext, MPAlgorithmVersionCurrent ) );

View File

@ -1,5 +1,3 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>
@ -15,18 +13,22 @@
#include "mpw-algorithm.h"
#include "mpw-util.h"
#include "mpw-marshall.h"
#define MP_env_fullname "MP_FULLNAME"
#define MP_env_sitetype "MP_SITETYPE"
#define MP_env_sitecounter "MP_SITECOUNTER"
#define MP_env_fullName "MP_FULLNAME"
#define MP_env_siteType "MP_SITETYPE"
#define MP_env_siteCounter "MP_SITECOUNTER"
#define MP_env_algorithm "MP_ALGORITHM"
static void usage() {
fprintf( stderr, "Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-V variant] [-C context] [-v|-q] [-h] site\n\n" );
fprintf( stderr, " -u name Specify the full name of the user.\n"
" Defaults to %s in env or prompts.\n\n", MP_env_fullname );
fprintf( stderr, " -t type Specify the password's template.\n"
inf( ""
"Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-V variant] [-C context] [-v|-q] [-h] site\n\n" );
inf( ""
" -u name Specify the full name of the user.\n"
" Defaults to %s in env or prompts.\n\n", MP_env_fullName );
inf( ""
" -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"
@ -35,34 +37,41 @@ static void usage() {
" 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, " -a version The algorithm version to use.\n"
" p, phrase | 20 character sentence.\n\n", MP_env_siteType );
inf( ""
" -c counter The value of the counter.\n"
" Defaults to %s in env or 1.\n\n", MP_env_siteCounter );
inf( ""
" -a version The algorithm version to use.\n"
" Defaults to %s in env or %d.\n\n", MP_env_algorithm, MPAlgorithmVersionCurrent );
fprintf( stderr, " -V variant The kind of content to generate.\n"
inf( ""
" -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"
inf( ""
" -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, " -v Increase output verbosity (can be repeated).\n\n" );
fprintf( stderr, " -q Decrease output verbosity (can be repeated).\n\n" );
fprintf( stderr, " ENVIRONMENT\n\n"
inf( ""
" -v Increase output verbosity (can be repeated).\n\n" );
inf( ""
" -q Decrease output verbosity (can be repeated).\n\n" );
inf( ""
" ENVIRONMENT\n\n"
" %-14s | The full name of the user (see -u).\n"
" %-14s | The default password template (see -t).\n"
" %-14s | The default counter value (see -c).\n"
" %-14s | The default algorithm version (see -a).\n\n",
MP_env_fullname, MP_env_sitetype, MP_env_sitecounter, MP_env_algorithm );
MP_env_fullName, MP_env_siteType, MP_env_siteCounter, MP_env_algorithm );
exit( 0 );
}
static char *homedir(const char *filename) {
static char *mpwPath(const char *prefix, const char *extension) {
char *homedir = NULL;
struct passwd *passwd = getpwuid( getuid() );
@ -73,9 +82,15 @@ static char *homedir(const char *filename) {
if (!homedir)
homedir = getcwd( NULL, 0 );
char *homefile = NULL;
asprintf( &homefile, "%s/%s", homedir, filename );
return homefile;
char *mpwPath = NULL;
asprintf( &mpwPath, "%s.%s", prefix, extension );
char *slash = strstr( mpwPath, "/" );
if (slash)
*slash = '\0';
asprintf( &mpwPath, "%s/.mpw.d/%s", homedir, mpwPath );
return mpwPath;
}
static char *getline_prompt(const char *prompt) {
@ -95,49 +110,43 @@ static char *getline_prompt(const char *prompt) {
int main(int argc, char *const argv[]) {
// Read the environment.
const char *fullName = NULL;
const char *masterPassword = NULL;
const char *siteName = NULL;
// Master Password defaults.
const char *fullName = NULL, *masterPassword = NULL, *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 );
MPAlgorithmVersion algorithmVersion = MPAlgorithmVersionCurrent;
const char *algorithmVersionString = getenv( MP_env_algorithm );
if (algorithmVersionString && strlen( algorithmVersionString ))
if (sscanf( algorithmVersionString, "%u", &algorithmVersion ) != 1)
ftl( "Invalid %s: %s\n", MP_env_algorithm, algorithmVersionString );
uint32_t siteCounter = 1;
// Read the options.
// Read the environment.
const char *fullNameArg = getenv( MP_env_fullName ), *masterPasswordArg = NULL, *siteNameArg = NULL;
const char *siteTypeArg = getenv( MP_env_siteType ), *siteVariantArg = NULL, *siteContextArg = NULL;
const char *siteCounterArg = getenv( MP_env_siteCounter );
const char *algorithmVersionArg = getenv( MP_env_algorithm );
// Read the command-line options.
for (int opt; (opt = getopt( argc, argv, "u:P:t:c:V:a:C:vqh" )) != -1;)
switch (opt) {
case 'u':
fullName = strdup( optarg );
fullNameArg = optarg;
break;
case 'P':
// Do not use this. Passing your master password via the command-line
// is insecure. This is here for non-interactive testing purposes only.
masterPassword = strcpy( malloc( strlen( optarg ) + 1 ), optarg );
// Passing your master password via the command-line is insecure. Testing purposes only.
masterPasswordArg = optarg;
break;
case 't':
siteTypeString = optarg;
siteTypeArg = optarg;
break;
case 'c':
siteCounterString = optarg;
siteCounterArg = optarg;
break;
case 'V':
siteVariantString = optarg;
siteVariantArg = optarg;
break;
case 'a':
if (sscanf( optarg, "%u", &algorithmVersion ) != 1)
ftl( "Not a version: %s\n", optarg );
algorithmVersionArg = optarg;
break;
case 'C':
siteContextString = optarg;
siteContextArg = optarg;
break;
case 'v':
++mpw_verbosity;
@ -161,64 +170,112 @@ int main(int argc, char *const argv[]) {
break;
default:
ftl( "Unknown option: -%c\n", optopt );
break;
}
default:
ftl("Unexpected option: %c", opt);
ftl( "Unexpected option: %c", opt );
break;
}
if (optind < argc)
siteName = strdup( argv[optind] );
siteNameArg = argv[optind];
// Convert and validate input.
if (!fullName && (fullName = getenv( MP_env_fullname )))
fullName = strdup( fullName );
if (!fullName && !(fullName = getline_prompt( "Your full name:" )))
// Empty strings unset the argument.
fullNameArg = fullNameArg && strlen( fullNameArg )? fullNameArg: NULL;
masterPasswordArg = masterPasswordArg && strlen( masterPasswordArg )? masterPasswordArg: NULL;
siteNameArg = siteNameArg && strlen( siteNameArg )? siteNameArg: NULL;
siteTypeArg = siteTypeArg && strlen( siteTypeArg )? siteTypeArg: NULL;
siteVariantArg = siteVariantArg && strlen( siteVariantArg )? siteVariantArg: NULL;
siteContextArg = siteContextArg && strlen( siteContextArg )? siteContextArg: NULL;
siteCounterArg = siteCounterArg && strlen( siteCounterArg )? siteCounterArg: NULL;
algorithmVersionArg = algorithmVersionArg && strlen( algorithmVersionArg )? algorithmVersionArg: NULL;
// Determine fullName and siteName.
if (!(fullNameArg && (fullName = strdup( fullNameArg ))) &&
!(fullName = getline_prompt( "Your full name:" )))
ftl( "Missing full name.\n" );
if (!siteName && !(siteName = getline_prompt( "Site name:" )))
if (!(siteNameArg && (siteName = strdup( siteNameArg ))) &&
!(siteName = getline_prompt( "Site name:" )))
ftl( "Missing site name.\n" );
if (siteCounterString)
siteCounter = (uint32_t)atol( siteCounterString );
if (siteCounter < 1)
ftl( "Invalid site counter: %d\n", siteCounter );
if (siteVariantString)
siteVariant = mpw_variantWithName( siteVariantString );
// Read defaults for fullName user from config.
char *mpwSitesPath = mpwPath( fullName, "mpsites" );
if (!mpwSitesPath)
wrn( "Couldn't resolve path for configuration file: %d\n", errno );
else {
FILE *mpwSites = fopen( mpwSitesPath, "r" );
free( mpwSitesPath );
if (!mpwSites)
dbg( "Couldn't open configuration file: %s: %d\n", mpwSitesPath, errno );
else {
size_t readAmount = 4096, bufSize = 0, bufPointer = 0, readSize = 0;
void *buf = NULL;
while ((buf = realloc( buf, bufSize += readAmount )) &&
(bufPointer += (readSize = fread( buf + bufPointer, 1, readAmount, mpwSites ))) &&
(readSize == readAmount));
// Load personal defaults from user config.
MPMarshalledUser user = mpw_marshall_read( buf, MPMarshallFormatFlat );
if (!user.name)
wrn( "Couldn't parse configuration file: %s\n", mpwSitesPath );
else {
fullName = user.name;
algorithmVersion = user.version;
siteType = user.defaultType;
for (int s = 0; s < user.sites_count; ++s) {
MPMarshalledSite site = user.sites[s];
if (strcmp( siteName, site.name ) == 0) {
siteType = site.type;
siteCounter = site.counter;
algorithmVersion = site.version;
break;
}
}
}
}
}
// Parse default-overriding command-line parameters.
if ((algorithmVersionArg && sscanf( algorithmVersionArg, "%u", &algorithmVersion ) != 1) ||
algorithmVersion > MPAlgorithmVersionLatest)
ftl( "Invalid algorithm: %s\n", algorithmVersionArg );
if (siteCounterArg) {
long long int siteCounterInt = atoll( siteCounterArg );
if (siteCounterInt < 0 || siteCounterInt > UINT32_MAX)
ftl( "Invalid site counter: %s\n", siteCounterArg );
siteCounter = (uint32_t)siteCounterInt;
}
if (siteVariantArg)
siteVariant = mpw_variantWithName( siteVariantArg );
if (siteVariant == MPSiteVariantLogin)
siteType = MPSiteTypeGeneratedName;
if (siteVariant == MPSiteVariantAnswer)
siteType = MPSiteTypeGeneratedPhrase;
if (siteTypeString)
siteType = mpw_typeWithName( siteTypeString );
trc( "algorithmVersion: %u\n", algorithmVersion );
// Read the master password.
char *mpwConfigPath = homedir( ".mpw" );
if (!mpwConfigPath)
ftl( "Couldn't resolve path for configuration file: %d\n", errno );
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;
}
}
mpw_free( line, linecap );
}
while (!masterPassword || !strlen(masterPassword))
if (siteTypeArg)
siteType = mpw_typeWithName( siteTypeArg );
if (!(masterPasswordArg && (masterPassword = strdup( masterPasswordArg ))))
while (!masterPassword || !strlen( masterPassword ))
masterPassword = getpass( "Your master password: " );
// Summarize operation.
const char *identicon = mpw_identicon( fullName, masterPassword );
if (!identicon) {
err( "Couldn't determine identicon.\n" );
} else {
fprintf( stderr, "%s's password for %s:\n[ %s ]: ", fullName, siteName, identicon );
if (!identicon)
wrn( "Couldn't determine identicon.\n" );
dbg( "-----------------\n" );
dbg( "fullName : %s\n", fullName );
trc( "masterPassword : %s\n", masterPassword );
dbg( "identicon : %s\n", identicon );
dbg( "siteName : %s\n", siteName );
dbg( "siteType : %u\n", siteType );
dbg( "algorithmVersion : %u\n", algorithmVersion );
dbg( "siteCounter : %u\n", siteCounter );
dbg( "-----------------\n\n" );
inf( "%s's password for %s:\n[ %s ]: ", fullName, siteName, identicon );
mpw_free_string( identicon );
}
// Output the password.
const uint8_t *masterKey = mpw_masterKeyForUser(
@ -229,8 +286,8 @@ int main(int argc, char *const argv[]) {
ftl( "Couldn't derive master key." );
const char *sitePassword = mpw_passwordForSite(
masterKey, siteName, siteType, siteCounter, siteVariant, siteContextString, algorithmVersion );
mpw_free( masterKey, MP_dkLen );
masterKey, siteName, siteType, siteCounter, siteVariant, siteContextArg, algorithmVersion );
mpw_free( masterKey, MPMasterKeySize );
mpw_free_string( siteName );
if (!sitePassword)
ftl( "Couldn't derive site password." );

View File

@ -15,10 +15,8 @@ int main(int argc, char *const argv[]) {
int failedTests = 0;
xmlNodePtr tests = xmlDocGetRootElement( xmlParseFile( "mpw_tests.xml" ) );
if (!tests) {
if (!tests)
ftl( "Couldn't find test case: mpw_tests.xml\n" );
abort();
}
for (xmlNodePtr testCase = tests->children; testCase; testCase = testCase->next) {
if (testCase->type != XML_ELEMENT_NODE || xmlStrcmp( testCase->name, BAD_CAST "case" ) != 0)
@ -48,7 +46,7 @@ int main(int argc, char *const argv[]) {
}
// 1. calculate the master key.
const uint8_t *masterKey = mpw_masterKeyForUser(
MPMasterKey masterKey = mpw_masterKeyForUser(
(char *)fullName, (char *)masterPassword, algorithm );
if (!masterKey)
ftl( "Couldn't derive master key." );
@ -56,7 +54,7 @@ int main(int argc, char *const argv[]) {
// 2. calculate the site password.
const char *sitePassword = mpw_passwordForSite(
masterKey, (char *)siteName, siteType, siteCounter, siteVariant, (char *)siteContext, algorithm );
mpw_free( masterKey, MP_dkLen );
mpw_free( masterKey, MPMasterKeySize );
if (!sitePassword)
ftl( "Couldn't derive site password." );