diff --git a/core/c/mpw-algorithm.c b/core/c/mpw-algorithm.c
index d7fd4c22..f09b1f55 100644
--- a/core/c/mpw-algorithm.c
+++ b/core/c/mpw-algorithm.c
@@ -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)
diff --git a/core/c/mpw-algorithm.h b/core/c/mpw-algorithm.h
index 9cc8da24..13d08986 100644
--- a/core/c/mpw-algorithm.h
+++ b/core/c/mpw-algorithm.h
@@ -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
diff --git a/core/c/mpw-algorithm_v0.c b/core/c/mpw-algorithm_v0.c
index 7f9a63e3..7ae392e0 100644
--- a/core/c/mpw-algorithm_v0.c
+++ b/core/c/mpw-algorithm_v0.c
@@ -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 );
diff --git a/core/c/mpw-algorithm_v1.c b/core/c/mpw-algorithm_v1.c
index bc84ed43..19fa8d88 100644
--- a/core/c/mpw-algorithm_v1.c
+++ b/core/c/mpw-algorithm_v1.c
@@ -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 );
diff --git a/core/c/mpw-algorithm_v2.c b/core/c/mpw-algorithm_v2.c
index b35a2f30..16354530 100644
--- a/core/c/mpw-algorithm_v2.c
+++ b/core/c/mpw-algorithm_v2.c
@@ -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 );
diff --git a/core/c/mpw-algorithm_v3.c b/core/c/mpw-algorithm_v3.c
index 06694f8e..96f48eba 100644
--- a/core/c/mpw-algorithm_v3.c
+++ b/core/c/mpw-algorithm_v3.c
@@ -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 );
diff --git a/core/c/mpw-marshall.c b/core/c/mpw-marshall.c
new file mode 100644
index 00000000..4d5cf629
--- /dev/null
+++ b/core/c/mpw-marshall.c
@@ -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 .
+//==============================================================================
+
+
+#include
+#include
+#include
+#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 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){};
+}
diff --git a/core/c/mpw-marshall.h b/core/c/mpw-marshall.h
new file mode 100644
index 00000000..b32fb4bc
--- /dev/null
+++ b/core/c/mpw-marshall.h
@@ -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 .
+//==============================================================================
+
+#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
diff --git a/core/c/mpw-types.c b/core/c/mpw-types.c
index 26c36d0c..4915c719 100644
--- a/core/c/mpw-types.c
+++ b/core/c/mpw-types.c
@@ -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 );
}
}
}
diff --git a/core/c/mpw-types.h b/core/c/mpw-types.h
index e3162c48..8cd04a94 100644
--- a/core/c/mpw-types.h
+++ b/core/c/mpw-types.h
@@ -20,6 +20,7 @@
#define _MPW_TYPES_H
#include
#include
+#include
#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,
diff --git a/core/c/mpw-util.c b/core/c/mpw-util.c
index 52dc059d..fd67d490 100644
--- a/core/c/mpw-util.c
+++ b/core/c/mpw-util.c
@@ -20,7 +20,7 @@
#include
#include
-#if COLOR
+#if MPW_COLOR
#include
#include
#include
@@ -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) {
- memset( (void *)buffer, 0, bufferSize );
- free( (void *)buffer );
- }
+ if (!buffer)
+ return false;
+
+ 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,
diff --git a/core/c/mpw-util.h b/core/c/mpw-util.h
index 260ed736..74b38d5f 100644
--- a/core/c/mpw-util.h
+++ b/core/c/mpw-util.h
@@ -17,7 +17,10 @@
//==============================================================================
#include
-#include
+#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) \
- fprintf( stderr, __VA_ARGS__ ); \
- exit( 2 ); \
- } while (0)
+ ({ if (mpw_verbosity >= -2) \
+ fprintf( stderr, __VA_ARGS__ ); \
+ 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
diff --git a/platform-darwin/MasterPassword-iOS.xcodeproj/project.pbxproj b/platform-darwin/MasterPassword-iOS.xcodeproj/project.pbxproj
index ed0a8821..7f8bb3ff 100644
--- a/platform-darwin/MasterPassword-iOS.xcodeproj/project.pbxproj
+++ b/platform-darwin/MasterPassword-iOS.xcodeproj/project.pbxproj
@@ -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 = ""; };
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = ""; };
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = ""; };
+ DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = ""; };
+ DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = ""; };
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 = ""; };
@@ -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 */,
diff --git a/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj b/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj
index 9217ceda..94d3a2f6 100644
--- a/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj
+++ b/platform-darwin/MasterPassword-macOS.xcodeproj/project.pbxproj
@@ -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 = ""; };
DA0933CB1747AD2D00DE1CEF /* shot-laptop-leaning-iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "shot-laptop-leaning-iphone.png"; sourceTree = ""; };
DA0933CF1747B91B00DE1CEF /* appstore.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = appstore.png; sourceTree = ""; };
- 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 = ""; };
- 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 = ""; };
- 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 = ""; };
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 = ""; };
DA09791B1E9A824700F0BFE8 /* core.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = core.h; sourceTree = ""; };
@@ -367,6 +398,13 @@
DA0CC5581EB6AE45009A8ED9 /* MasterPassword 9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 9.xcdatamodel"; sourceTree = ""; };
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 = ""; };
+ DA1C7AB91F1A8F6E009A3551 /* mpw-cli.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli.c"; sourceTree = ""; };
+ DA1C7ABA1F1A8F6E009A3551 /* mpw-tests-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-tests-util.c"; sourceTree = ""; };
+ DA1C7ABB1F1A8F6E009A3551 /* mpw-tests-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-tests-util.h"; sourceTree = ""; };
+ DA1C7ABC1F1A8F6E009A3551 /* mpw-tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-tests.c"; sourceTree = ""; };
+ 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 = ""; };
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 = ""; };
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 = ""; };
+ DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = ""; };
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = ""; };
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = ""; };
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = ""; };
@@ -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 = "";
};
+ 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 = "";
+ };
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 = "";
@@ -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 = (
diff --git a/platform-darwin/Source/MPAlgorithm.h b/platform-darwin/Source/MPAlgorithm.h
index 1b69c039..cfb1e258 100644
--- a/platform-darwin/Source/MPAlgorithm.h
+++ b/platform-darwin/Source/MPAlgorithm.h
@@ -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;
diff --git a/platform-darwin/Source/MPAlgorithmV0.m b/platform-darwin/Source/MPAlgorithmV0.m
index cd281ed5..03c23e1e 100644
--- a/platform-darwin/Source/MPAlgorithmV0.m
+++ b/platform-darwin/Source/MPAlgorithmV0.m
@@ -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)
diff --git a/platform-darwin/Source/MPAppDelegate_Key.m b/platform-darwin/Source/MPAppDelegate_Key.m
index 7183b658..78c3ce42 100644
--- a/platform-darwin/Source/MPAppDelegate_Key.m
+++ b/platform-darwin/Source/MPAppDelegate_Key.m
@@ -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]
+ }];
}
}
}
diff --git a/platform-darwin/Source/MPAppDelegate_Store.m b/platform-darwin/Source/MPAppDelegate_Store.m
index 42e3948a..58d5bd88 100644
--- a/platform-darwin/Source/MPAppDelegate_Store.m
+++ b/platform-darwin/Source/MPAppDelegate_Store.m
@@ -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 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];
- }
-
- 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];
+ for (MPSiteQuestionEntity *siteQuestion in site.questions)
+ mpw_marshal_question( &exportSite, siteQuestion.keyword.UTF8String );
}
- return export;
+ mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser );
}
@end
diff --git a/platform-darwin/Source/MPKey.h b/platform-darwin/Source/MPKey.h
index c1eeb24c..15d26617 100644
--- a/platform-darwin/Source/MPKey.h
+++ b/platform-darwin/Source/MPKey.h
@@ -18,6 +18,7 @@
#import
#import "MPAlgorithm.h"
+#import "mpw-types.h"
@protocol MPAlgorithm;
@@ -37,8 +38,7 @@ typedef NS_ENUM( NSUInteger, MPKeyOrigin ) {
keyOrigin:(MPKeyOrigin)origin;
- (NSData *)keyIDForAlgorithm:(id)algorithm;
-- (NSData *)keyDataForAlgorithm:(id)algorithm;
-- (NSData *)keyDataForAlgorithm:(id)algorithm trimmedLength:(NSUInteger)subKeyLength;
+- (MPMasterKey)keyForAlgorithm:(id)algorithm;
- (BOOL)isEqualToKey:(MPKey *)key;
diff --git a/platform-darwin/Source/MPKey.m b/platform-darwin/Source/MPKey.m
index 9d5819cc..af9b0753 100644
--- a/platform-darwin/Source/MPKey.m
+++ b/platform-darwin/Source/MPKey.m
@@ -53,30 +53,23 @@
- (NSData *)keyIDForAlgorithm:(id)algorithm {
- return [algorithm keyIDForKeyData:[self keyDataForAlgorithm:algorithm]];
+ return [algorithm keyIDForKey:[self keyForAlgorithm:algorithm]];
}
-- (NSData *)keyDataForAlgorithm:(id)algorithm {
+- (MPMasterKey)keyForAlgorithm:(id)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];
+ }
- keyData = self.keyResolver( algorithm );
- if (keyData)
- [self.keyCache setObject:keyData forKey:algorithm];
-
- return keyData;
+ return keyData.length == MPMasterKeySize? keyData.bytes: NULL;
}
}
-- (NSData *)keyDataForAlgorithm:(id)algorithm trimmedLength:(NSUInteger)subKeyLength {
-
- NSData *keyData = [self keyDataForAlgorithm:algorithm];
- return [keyData subdataWithRange:NSMakeRange( 0, MIN( subKeyLength, keyData.length ) )];
-}
-
- (BOOL)isEqualToKey:(MPKey *)key {
return [[self keyIDForAlgorithm:MPAlgorithmDefault] isEqualToData:[key keyIDForAlgorithm:MPAlgorithmDefault]];
@@ -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
diff --git a/platform-darwin/Source/iOS/Storyboard.storyboard b/platform-darwin/Source/iOS/Storyboard.storyboard
index fd94ee1e..c653d9cd 100644
--- a/platform-darwin/Source/iOS/Storyboard.storyboard
+++ b/platform-darwin/Source/iOS/Storyboard.storyboard
@@ -1,10 +1,10 @@
-
+
-
+
@@ -103,7 +103,7 @@
-
+