2
0

Compare commits

...

64 Commits

Author SHA1 Message Date
Maarten Billemont
895df6377d Only distribute release tags, include TAG and VERSION. 2017-09-04 14:48:40 -04:00
Maarten Billemont
3d46f60ff4 Add VERSION to distribution archive. 2017-09-04 14:38:08 -04:00
Maarten Billemont
44d8ab6e53 Remove some pointless local's. 2017-09-04 14:29:25 -04:00
Maarten Billemont
cd70009c2c Move instructions into cli-c for distribution. 2017-09-04 14:17:20 -04:00
Maarten Billemont
4261160902 Some more refactoring. 2017-09-03 17:00:35 -04:00
Maarten Billemont
ced7aef5d7 Fix target assignment of mpw-cli-util.c 2017-09-03 16:53:14 -04:00
Maarten Billemont
63100913c5 libjson-c's upstream still has build issues, switch back to our fork. 2017-09-03 15:48:43 -04:00
Maarten Billemont
6904d4c427 purposeResult is not an owned reference. 2017-09-03 15:46:38 -04:00
Maarten Billemont
4271d77225 Remove debugging code. 2017-09-03 15:43:22 -04:00
Maarten Billemont
6811773e54 Refactor CLI code to make the flow more clear and the free'ing more reliable. 2017-09-03 15:41:12 -04:00
Maarten Billemont
060ce61030 Fix ./build's targets interpretation & other improvements. 2017-09-01 11:16:09 -04:00
Maarten Billemont
9a5e9ced31 More consistent spacing in usage output. 2017-08-31 15:32:58 -04:00
Maarten Billemont
568401a612 Extract cli utilities into mpw-cli-util to keep things cleaner. 2017-08-31 15:30:42 -04:00
Maarten Billemont
92a3a0ccbd Switch libjson-c back to upstream and fix some build issues with it. 2017-08-31 15:14:08 -04:00
Maarten Billemont
ba24c2be34 Rename env vars to make it clear they are for the mpw binary, add PATH support for askpass. 2017-08-31 13:42:03 -04:00
Maarten Billemont
019cefd3fb Add support for askpass program for reading answers from the user. 2017-08-31 13:37:28 -04:00
Maarten Billemont
eef82f7ed4 Don't infinite loop when prompting if no terminal is available. 2017-08-31 11:49:36 -04:00
Maarten Billemont
2dfe0f78b0 Build & link all sources at once to allow link-time optimization. 2017-08-31 11:48:34 -04:00
Maarten Billemont
627144b583 Make MPW_JSON optional as documented. 2017-08-31 11:48:10 -04:00
Maarten Billemont
fad0f5e5dd Add PearlCryptUtils back since PearlKeyChain uses it. 2017-08-30 19:05:42 -04:00
Maarten Billemont
8562338b62 Support for reading master password from an FD. 2017-08-30 19:05:21 -04:00
Maarten Billemont
17de69834e Declare __unused if not declared by compiler. 2017-08-30 13:27:59 -04:00
Maarten Billemont
aeeab7dbf6 Improve build script documentation and targets variable. 2017-08-30 10:18:23 -04:00
Maarten Billemont
ce60ba6c9f External libs configuration no longer used. 2017-08-30 09:58:01 -04:00
Maarten Billemont
d22f93e564 Format code. 2017-08-30 09:57:15 -04:00
Maarten Billemont
6f4f6b8d1e Copy TOTP counter support to v2 override. 2017-08-30 09:54:16 -04:00
Maarten Billemont
6fa8ee53cd Currently unused implementation of HOTP. 2017-08-30 09:40:51 -04:00
Maarten Billemont
23af56c150 Slight clean-up of types, includes and warnings. 2017-08-30 09:39:35 -04:00
Maarten Billemont
91828cbad7 Test script for CLI. 2017-08-30 09:38:23 -04:00
Maarten Billemont
40d2788ae0 Implement OTP counter feature for counter values of 0. 2017-08-30 09:35:55 -04:00
Maarten Billemont
21a3a28980 Copy args so we can re-use it. 2017-08-29 12:06:40 -04:00
Maarten Billemont
f5c7bee58f Remove unused Pearl-Crypto. 2017-08-29 01:01:38 -04:00
Maarten Billemont
e364f5159b Fix build warnings. 2017-08-28 23:48:24 -04:00
Maarten Billemont
74f9f1ca00 Fix up objc code to match new C API. 2017-08-28 19:37:51 -04:00
Maarten Billemont
328d38ac19 Remove PearlLayout. 2017-08-28 19:34:22 -04:00
Maarten Billemont
7735d82c7b Silence unused variable warnings for compiler check variables. 2017-08-28 19:25:51 -04:00
Maarten Billemont
1e7c200865 Remove non-standard asprintf from mpw-cli. 2017-08-28 18:25:58 -04:00
Maarten Billemont
724b357dd8 Create path for mpw.d sites files if it doesn't exist yet. 2017-08-28 17:58:57 -04:00
Maarten Billemont
a85efc5736 Remove all build-time external dependency fetching/building logic. 2017-08-27 11:17:45 -04:00
Maarten Billemont
9eb58119ea Remove dependency on external bcrypt. 2017-08-27 10:47:39 -04:00
Maarten Billemont
77b4ed2cfd Remove dependency on asprintf. 2017-08-27 09:25:53 -04:00
Maarten Billemont
011416690a Some warning cleanup. 2017-08-27 09:04:18 -04:00
Maarten Billemont
53eb5c8a73 Refactoring and fix up mpw_color. 2017-08-27 08:53:58 -04:00
Maarten Billemont
2f99855cd4 Remove non-standard host-endian functions. 2017-08-27 07:46:34 -04:00
Maarten Billemont
18eaeec1de Fix some rewrite bugs. 2017-08-23 00:53:14 -04:00
Maarten Billemont
5ee700c9b9 Small fix. 2017-08-23 00:05:50 -04:00
Maarten Billemont
a8949ca07e NULL out free'ed references. 2017-08-23 00:01:23 -04:00
Maarten Billemont
0a42579d9e Improved free'ing on error conditions. 2017-08-22 18:38:36 -04:00
Maarten Billemont
f2f8747126 Support for persisting login/question type & stateful types, null checking, cleanup and rewrite of CLI state. 2017-08-22 18:18:24 -04:00
Maarten Billemont
f83cdacab8 Document -M, -P, allow saving login name. 2017-08-22 11:38:04 -04:00
Maarten Billemont
98aeb02d32 Forgot to merge in i386 2017-08-13 19:06:06 -04:00
Maarten Billemont
2bbaeccd05 Forgot to merge in i386 2017-08-13 18:32:03 -04:00
Maarten Billemont
91e0a04e66 Add support for i386 in libjson-c and libsodium builds. 2017-08-13 16:53:18 -04:00
Maarten Billemont
661fc523ad Don't pass nil error to crashlytics. 2017-08-13 16:49:56 -04:00
Maarten Billemont
b9cbaf7343 Cross-compile fixes for iOS. 2017-08-13 15:52:08 -04:00
Maarten Billemont
e451308fdc Refactoring regression, use right algorithm version for siteKey. 2017-08-13 11:35:15 -04:00
Maarten Billemont
1b51c5efa4 Build script update. 2017-08-13 11:02:05 -04:00
Maarten Billemont
a8776eec58 Fix C cli API. 2017-08-13 08:50:16 -04:00
Maarten Billemont
d9cdb7ef83 Fix error name collision. 2017-08-13 01:00:03 -04:00
Maarten Billemont
28c7a64bd2 Fork json-c temporarily to fix some code issues. 2017-08-13 00:30:25 -04:00
Maarten Billemont
d7193f7753 Adapt macOS for new APIs. 2017-08-12 22:26:48 -04:00
Maarten Billemont
f5c7d11f0e Add marshalling metadata lookup & adapt iOS for new APIs. 2017-08-12 21:57:47 -04:00
Maarten Billemont
c0ba96daa2 Update Darwin platform project with solid support for linking libsodium & libjson-c 2017-08-11 01:42:03 -04:00
Maarten Billemont
b374d9e04a Some type fixes. 2017-08-10 21:29:59 -04:00
71 changed files with 5008 additions and 2341 deletions

16
.gitignore vendored
View File

@@ -13,8 +13,6 @@ xcuserdata/
DerivedData/
# Generated
/platform-independent/cli-c/VERSION
/platform-independent/cli-c/mpw-*.tar.gz
/platform-darwin/Resources/Media/Images.xcassets/
# Media
@@ -31,17 +29,3 @@ local.properties
# Maven
target
dependency-reduced-pom.xml
# C
core/c/*.o
core/c/lib/*/.unpacked
core/c/lib/*/.patched
core/c/lib/*/src
core/c/lib/include
platform-independent/cli-c/cli/*.o
platform-independent/cli-c/mpw-*.tar.gz
platform-independent/cli-c/mpw-*.tar.gz.sig
platform-independent/cli-c/mpw
platform-independent/cli-c/mpw-bench
platform-independent/cli-c/mpw-tests
platform-independent/cli-c/VERSION

2
.gitmodules vendored
View File

@@ -24,4 +24,4 @@
url = https://github.com/jedisct1/libsodium.git
[submodule "platform-darwin/External/libjson-c"]
path = platform-darwin/External/libjson-c
url = https://github.com/json-c/json-c.git
url = https://github.com/lhunath/json-c.git

View File

@@ -4,7 +4,7 @@ env: TERM=dumb SHLVL=0
git:
submodules: true
script:
- "( brew install libsodium )"
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests )"
- "( brew install libsodium json-c )"
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )"

View File

@@ -194,49 +194,7 @@ Note that in order to build the Android application, you will need to have the A
Go into the `platform-independent/cli-c` directory and run `./build`. The native command-line client will then be built.
When the build completes, you will have an `mpw` binary you can use. You can copy it into your `PATH` or use the `./install` script to help you do so.
For example:
./build && sudo ./install
mpw -h
Normally, this is all you need to do, however note that there are a few dependencies that need to be met, depending on which targets you are building (by default, only the `mpw` target is built):
- `mpw`
The C implementation depends either on `libsodium` or Tarsnap's `scrypt` and `openssl-dev`.
We recommend you install `libsodium`. If `libsodium` is not installed when `./build` is executed, the script will try to download and statically link Tarsnap's `scrypt` instead. Tarsnap's `scrypt` depends on you having `openssl-dev` installed.
If you have `mpw_color` enabled (it is enabled by default), the build also depends on `ncurses-dev` to communicate with the terminal.
- `mpw-bench`
This tool compares the performance of a few cryptographic algorithms, including bcrypt. The `./build` script will try to automatically download and statically link `bcrypt`.
- `mpw-tests`
This tool runs a suite of tests to ensure the correct passwords are being generated by the algorithm under various circumstances. The test suite is declared in `mpw-tests.xml` which needs to exist in the current working directory when running the tool. In addition, `libxml2` is used to parse the file, so this target depends on you having it installed when running `./build`.
Finally, there are a few different ways you can modify the build process.
To build additional targets, set the `targets` environment variable:
targets='mpw mpw-tests' ./build
To pass additional compiler arguments, eg. add a library search path, pass them as arguments to the script:
./build -L/usr/local/lib
There are a few toggleable features, to change them, pass them as environment variables:
mpw_color=0 ./build
Currently, there is only one toggleable feature:
- `mpw_color`: [default: 1] Colorized Identicon, depends on `ncurses-dev`.
For detailed instructions, see [the native CLI instructions](platform-independent/cli-c/README.md).
## Support

View File

@@ -57,7 +57,7 @@
#include "base64.h"
/* aaaack but it's fast and const should make it shared text page. */
static const unsigned char b64ToBits[256] =
static const uint8_t b64ToBits[256] =
{
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
@@ -97,20 +97,20 @@ int mpw_base64_decode(uint8_t *plainBuf, const char *b64Text) {
b64Cursor = (uint8_t *)b64Text;
register uint8_t *plainCursor = plainBuf;
while (b64Remaining > 4) {
*(plainCursor++) = (b64ToBits[b64Cursor[0]] << 2 | b64ToBits[b64Cursor[1]] >> 4);
*(plainCursor++) = (b64ToBits[b64Cursor[1]] << 4 | b64ToBits[b64Cursor[2]] >> 2);
*(plainCursor++) = (b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[0]] << 2 | b64ToBits[b64Cursor[1]] >> 4);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[1]] << 4 | b64ToBits[b64Cursor[2]] >> 2);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
b64Cursor += 4;
b64Remaining -= 4;
}
/* Note: (b64Size == 1) would be an error, so just ingore that case */
if (b64Remaining > 1)
*(plainCursor++) = (b64ToBits[b64Cursor[0]] << 2 | b64ToBits[b64Cursor[1]] >> 4);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[0]] << 2 | b64ToBits[b64Cursor[1]] >> 4);
if (b64Remaining > 2)
*(plainCursor++) = (b64ToBits[b64Cursor[1]] << 4 | b64ToBits[b64Cursor[2]] >> 2);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[1]] << 4 | b64ToBits[b64Cursor[2]] >> 2);
if (b64Remaining > 3)
*(plainCursor++) = (b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
*(plainCursor++) = (uint8_t)(b64ToBits[b64Cursor[2]] << 6 | b64ToBits[b64Cursor[3]]);
return (int)(plainCursor - plainBuf);
}
@@ -126,7 +126,7 @@ size_t mpw_base64_encode_max(size_t plainSize) {
int mpw_base64_encode(char *b64Text, const uint8_t *plainBuf, size_t plainSize) {
int plainCursor = 0;
size_t plainCursor = 0;
char *b64Cursor = b64Text;
for (; plainCursor < plainSize - 2; plainCursor += 3) {
*b64Cursor++ = basis_64[((plainBuf[plainCursor] >> 2)) & 0x3F];

View File

@@ -1,4 +0,0 @@
home=http://www.openwall.com/crypt/
pkg=http://www.openwall.com/crypt/crypt_blowfish-1.3.tar.gz
pkg_sha256=83fa01fca6996fe8d882b7f8e9ba0305a5664936100b01481ea3c6a8ce8d72fd
patches=(arm)

View File

@@ -1,12 +0,0 @@
--- x86.S 2014-11-21 09:09:58.000000000 -0500
+++ x86.S 2014-11-21 09:11:01.000000000 -0500
@@ -199,5 +199,9 @@
#endif
#if defined(__ELF__) && defined(__linux__)
+#if defined(__arm__)
+.section .note.GNU-stack,"",%progbits
+#else
.section .note.GNU-stack,"",@progbits
#endif
+#endif

View File

@@ -1,4 +0,0 @@
home=http://www.tarsnap.com/scrypt.html
git=https://github.com/Tarsnap/scrypt.git
pkg=https://www.tarsnap.com/scrypt/scrypt-1.2.1.tgz
pkg_sha256=4621f5e7da2f802e20850436219370092e9fcda93bd598f6d4236cce33f4c577

View File

@@ -1,38 +0,0 @@
diff -ruN /Users/lhunath/.src/scrypt/Makefile ./Makefile
--- /Users/lhunath/.src/scrypt/Makefile 2014-05-02 11:28:58.000000000 -0400
+++ ./Makefile 2014-05-02 12:07:27.000000000 -0400
@@ -2,11 +2,11 @@
VER?= nosse
SRCS= main.c
LDADD+= -lcrypto
-WARNS?= 6
+WARNS?= 0
# We have a config file for FreeBSD
CFLAGS += -I .
-CFLAGS += -DCONFIG_H_FILE=\"config_freebsd.h\"
+CFLAGS += -DCONFIG_H_FILE=\"config_osx.h\"
# Include all possible object files containing built scrypt code.
CLEANFILES += crypto_scrypt-ref.o
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
--- /Users/lhunath/.src/scrypt/lib/util/memlimit.c 2014-05-02 11:28:58.000000000 -0400
+++ ./lib/util/memlimit.c 2014-05-02 11:52:42.000000000 -0400
@@ -75,7 +75,7 @@
* have returned to us.
*/
if (usermemlen == sizeof(uint64_t))
- usermem = *(uint64_t *)usermembuf;
+ usermem = *(uint64_t *)(void *)usermembuf;
else if (usermemlen == sizeof(uint32_t))
usermem = SIZE_MAX;
else
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
--- /Users/lhunath/.src/scrypt/config_osx.h 1969-12-31 19:00:00.000000000 -0500
+++ config_osx.h 2014-05-02 12:06:55.000000000 -0400
@@ -0,0 +1,5 @@
+/* A default configuration for FreeBSD, used if there is no config.h. */
+
+#define HAVE_POSIX_MEMALIGN 1
+#define HAVE_SYSCTL_HW_USERMEM 1
+#define HAVE_SYS_PARAM_H 1

View File

@@ -24,9 +24,14 @@
MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
if (fullName && !strlen( fullName ))
fullName = NULL;
if (masterPassword && !strlen( masterPassword ))
masterPassword = NULL;
trc( "-- mpw_masterKey (algorithm: %u)\n", algorithmVersion );
trc( "fullName: %s\n", fullName );
trc( "masterPassword.id: %s\n", mpw_id_buf( masterPassword, strlen( masterPassword ) ) );
trc( "masterPassword.id: %s\n", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
if (!fullName || !masterPassword)
return NULL;
@@ -49,6 +54,11 @@ MPSiteKey mpw_siteKey(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext ))
keyContext = NULL;
trc( "-- mpw_siteKey (algorithm: %u)\n", algorithmVersion );
trc( "siteName: %s\n", siteName );
trc( "siteCounter: %d\n", siteCounter );
@@ -78,7 +88,14 @@ const char *mpw_siteResult(
const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion) {
MPSiteKey siteKey = mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext ))
keyContext = NULL;
if (resultParam && !strlen( resultParam ))
resultParam = NULL;
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
if (!siteKey)
return NULL;
@@ -102,7 +119,7 @@ const char *mpw_siteResult(
return NULL;
}
}
else if (resultType & MPResultTypeClassState) {
else if (resultType & MPResultTypeClassStateful) {
switch (algorithmVersion) {
case MPAlgorithmVersion0:
return mpw_sitePasswordFromCrypt_v0( masterKey, siteKey, resultType, resultParam );
@@ -142,28 +159,35 @@ const char *mpw_siteResult(
const char *mpw_siteState(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext,
const MPResultType resultType, const char *state,
const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion) {
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext ))
keyContext = NULL;
if (resultParam && !strlen( resultParam ))
resultParam = NULL;
MPSiteKey siteKey = mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
if (!siteKey)
return NULL;
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
trc( "state: %s\n", state );
if (!masterKey || !state)
trc( "resultParam: %s\n", resultParam );
if (!masterKey || !resultParam)
return NULL;
switch (algorithmVersion) {
case MPAlgorithmVersion0:
return mpw_siteState_v0( masterKey, siteKey, resultType, state );
return mpw_siteState_v0( masterKey, siteKey, resultType, resultParam );
case MPAlgorithmVersion1:
return mpw_siteState_v1( masterKey, siteKey, resultType, state );
return mpw_siteState_v1( masterKey, siteKey, resultType, resultParam );
case MPAlgorithmVersion2:
return mpw_siteState_v2( masterKey, siteKey, resultType, state );
return mpw_siteState_v2( masterKey, siteKey, resultType, resultParam );
case MPAlgorithmVersion3:
return mpw_siteState_v3( masterKey, siteKey, resultType, state );
return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam );
default:
err( "Unsupported version: %d\n", algorithmVersion );
return NULL;

View File

@@ -22,7 +22,7 @@
#ifndef _MPW_ALGORITHM_H
#define _MPW_ALGORITHM_H
typedef enum( unsigned int, MPAlgorithmVersion ) {
typedef mpw_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. */
@@ -48,7 +48,8 @@ MPSiteKey mpw_siteKey(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion);
/** Encode a password for the site from the given site key.
/** Generate a site result token from the given parameters.
* @param resultParam A parameter for the resultType. For stateful result types, the output of mpw_siteState.
* @return A newly allocated string or NULL if an error occurred. */
const char *mpw_siteResult(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
@@ -56,12 +57,13 @@ const char *mpw_siteResult(
const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion);
/** Perform symmetric encryption on a secret token's plainText.
* @return The newly allocated cipherText of the secret token encrypted by the masterKey. */
/** Encrypt a stateful site token for persistence.
* @param resultParam A parameter for the resultType. For stateful result types, the desired mpw_siteResult.
* @return A newly allocated string or NULL if an error occurred. */
const char *mpw_siteState(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext,
const MPResultType resultType, const char *state,
const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion);
#endif // _MPW_ALGORITHM_H

View File

@@ -18,33 +18,33 @@
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include "mpw-types.h"
#include "mpw-util.h"
#include "base64.h"
#define MP_N 32768LU
#define MP_r 8U
#define MP_p 2U
#define MP_otp_window 5 * 60 /* s */
// Algorithm version helpers.
static const char *mpw_templateForType_v0(MPResultType type, uint16_t seedByte) {
static const char *mpw_templateForType_v0(MPResultType type, uint16_t templateIndex) {
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );
char const *template = templates && count? templates[seedByte % count]: NULL;
char const *template = templates && count? templates[templateIndex % count]: NULL;
free( templates );
return template;
}
static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedByte) {
static const char mpw_characterFromClass_v0(char characterClass, uint16_t classIndex) {
const char *classCharacters = mpw_charactersInClass( characterClass );
if (!classCharacters)
return '\0';
return classCharacters[seedByte % strlen( classCharacters )];
return classCharacters[classIndex % strlen( classCharacters )];
}
// Algorithm version overrides.
@@ -56,11 +56,11 @@ static MPMasterKey mpw_masterKey_v0(
// Calculate the master key salt.
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n",
keyScope, mpw_hex_l( htonl( mpw_utf8_strlen( fullName ) ) ), fullName );
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( fullName ) ), fullName );
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, keyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)mpw_utf8_strlen( fullName ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
err( "Could not allocate master key salt: %s\n", strerror( errno ) );
@@ -71,9 +71,9 @@ static MPMasterKey mpw_masterKey_v0(
// Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
mpw_free( &masterKeySalt, masterKeySaltSize );
if (!masterKey) {
err( "Could not allocate master key: %s\n", strerror( errno ) );
err( "Could not derive master key: %s\n", strerror( errno ) );
return NULL;
}
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
@@ -82,31 +82,32 @@ static MPMasterKey mpw_masterKey_v0(
}
static MPSiteKey mpw_siteKey_v0(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext) {
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext) {
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
trc( "keyScope: %s\n", keyScope );
// TODO: Implement MPCounterValueTOTP
// OTP counter value.
if (siteCounter == MPCounterValueTOTP)
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
// Calculate the site seed.
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
keyScope, mpw_hex_l( htonl( mpw_utf8_strlen( siteName ) ) ), siteName, mpw_hex_l( htonl( siteCounter ) ),
keyContext? mpw_hex_l( htonl( mpw_utf8_strlen( keyContext ) ) ): NULL, keyContext );
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
keyContext? mpw_hex_l( (uint32_t)mpw_utf8_strlen( keyContext ) ): NULL, keyContext );
size_t siteSaltSize = 0;
uint8_t *siteSalt = NULL;
mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( siteName ) ) );
mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)mpw_utf8_strlen( siteName ) );
mpw_push_string( &siteSalt, &siteSaltSize, siteName );
mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
mpw_push_int( &siteSalt, &siteSaltSize, siteCounter );
if (keyContext) {
mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)mpw_utf8_strlen( keyContext ) );
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
}
if (!siteSalt || !siteSaltSize) {
if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) );
mpw_free( siteSalt, siteSaltSize );
return NULL;
}
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
@@ -114,7 +115,7 @@ static MPSiteKey mpw_siteKey_v0(
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) {
err( "Could not derive site key: %s\n", strerror( errno ) );
return NULL;
@@ -125,12 +126,15 @@ static MPSiteKey mpw_siteKey_v0(
}
static const char *mpw_sitePasswordFromTemplate_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey __unused masterKey, MPSiteKey siteKey, MPResultType resultType, const char __unused *resultParam) {
const char *_siteKey = (const char *)siteKey;
// Determine the template.
const char *_siteKey = (const char *)siteKey;
const char *template = mpw_templateForType_v0( resultType, htons( _siteKey[0] ) );
trc( "template: %u => %s\n", htons( _siteKey[0] ), template );
uint16_t seedByte;
mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte );
const char *template = mpw_templateForType_v0( resultType, seedByte );
trc( "template: %u => %s\n", seedByte, template );
if (!template)
return NULL;
if (strlen( template ) > MPSiteKeySize) {
@@ -139,11 +143,12 @@ static const char *mpw_sitePasswordFromTemplate_v0(
}
// Encode the password from the seed using the template.
char *sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass_v0( template[c], htons( _siteKey[c + 1] ) );
mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte );
sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte );
trc( " - class: %c, index: %5u (0x%02hX) => character: %c\n",
template[c], htons( _siteKey[c + 1] ), htons( _siteKey[c + 1] ), sitePassword[c] );
template[c], seedByte, seedByte, sitePassword[c] );
}
trc( " => password: %s\n", sitePassword );
@@ -151,7 +156,7 @@ static const char *mpw_sitePasswordFromTemplate_v0(
}
static const char *mpw_sitePasswordFromCrypt_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText) {
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) {
if (!cipherText) {
err( "Missing encrypted state.\n" );
@@ -163,25 +168,25 @@ static const char *mpw_sitePasswordFromCrypt_v0(
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText );
if ((int)bufSize < 0) {
err( "Base64 decoding error." );
mpw_free( cipherBuf, mpw_base64_decode_max( cipherText ) );
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
return NULL;
}
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) );
// Decrypt
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
mpw_free( &cipherBuf, bufSize );
const char *plainText = strndup( (char *)plainBytes, bufSize );
mpw_free( plainBytes, bufSize );
mpw_free( &plainBytes, bufSize );
if (!plainText)
err( "AES decryption error: %s\n", strerror( errno ) );
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
mpw_free( cipherBuf, bufSize );
return plainText;
}
static const char *mpw_sitePasswordFromDerive_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey __unused masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
switch (resultType) {
case MPResultTypeDeriveKey: {
@@ -206,15 +211,16 @@ static const char *mpw_sitePasswordFromDerive_v0(
// Base64-encode
size_t b64Max = mpw_base64_encode_max( keySize );
char *sitePassword = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( sitePassword, resultKey, keySize ) < 0) {
char *b64Key = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( b64Key, resultKey, keySize ) < 0) {
err( "Base64 encoding error." );
mpw_free_string( sitePassword );
sitePassword = NULL;
mpw_free_string( &b64Key );
}
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( sitePassword, strlen( sitePassword ) ) );
else
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) );
mpw_free( &resultKey, keySize );
return sitePassword;
return b64Key;
}
default:
err( "Unsupported derived password type: %d\n", resultType );
@@ -223,7 +229,7 @@ static const char *mpw_sitePasswordFromDerive_v0(
}
static const char *mpw_siteState_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *plainText) {
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *plainText) {
// Encrypt
size_t bufSize = strlen( plainText );
@@ -239,11 +245,11 @@ static const char *mpw_siteState_v0(
char *cipherText = calloc( 1, b64Max + 1 );
if (mpw_base64_encode( cipherText, cipherBuf, bufSize ) < 0) {
err( "Base64 encoding error." );
mpw_free_string( cipherText );
cipherText = NULL;
mpw_free_string( &cipherText );
}
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
mpw_free( cipherBuf, bufSize );
else
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
mpw_free( &cipherBuf, bufSize );
return cipherText;
}

View File

@@ -17,28 +17,26 @@
//==============================================================================
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768LU
#define MP_r 8U
#define MP_p 2U
#define MP_otp_window 5 * 60 /* s */
// Inherited functions.
MPMasterKey mpw_masterKey_v0(
const char *fullName, const char *masterPassword);
MPSiteKey mpw_siteKey_v0(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext);
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext);
const char *mpw_sitePasswordFromCrypt_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText);
const char *mpw_sitePasswordFromDerive_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam);
const char *mpw_siteState_v0(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state);
// Algorithm version overrides.
static MPMasterKey mpw_masterKey_v1(
@@ -48,18 +46,19 @@ static MPMasterKey mpw_masterKey_v1(
}
static MPSiteKey mpw_siteKey_v1(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext) {
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext) {
return mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
}
static const char *mpw_sitePasswordFromTemplate_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey __unused masterKey, MPSiteKey siteKey, MPResultType resultType, const char __unused *resultParam) {
// Determine the template.
const char *template = mpw_templateForType( resultType, siteKey[0] );
trc( "template: %u => %s\n", siteKey[0], template );
uint8_t seedByte = siteKey[0];
const char *template = mpw_templateForType( resultType, seedByte );
trc( "template: %u => %s\n", seedByte, template );
if (!template)
return NULL;
if (strlen( template ) > MPSiteKeySize) {
@@ -70,9 +69,10 @@ static const char *mpw_sitePasswordFromTemplate_v1(
// Encode the password from the seed using the template.
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass( template[c], siteKey[c + 1] );
seedByte = siteKey[c + 1];
sitePassword[c] = mpw_characterFromClass( template[c], seedByte );
trc( " - class: %c, index: %3u (0x%02hhX) => character: %c\n",
template[c], siteKey[c + 1], siteKey[c + 1], sitePassword[c] );
template[c], seedByte, seedByte, sitePassword[c] );
}
trc( " => password: %s\n", sitePassword );
@@ -80,19 +80,19 @@ static const char *mpw_sitePasswordFromTemplate_v1(
}
static const char *mpw_sitePasswordFromCrypt_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText) {
return mpw_sitePasswordFromCrypt_v0( masterKey, siteKey, resultType, cipherText );
}
static const char *mpw_sitePasswordFromDerive_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
return mpw_sitePasswordFromDerive_v0( masterKey, siteKey, resultType, resultParam );
}
static const char *mpw_siteState_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state) {
return mpw_siteState_v0( masterKey, siteKey, resultType, state );
}

View File

@@ -18,26 +18,26 @@
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <time.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768LU
#define MP_r 8U
#define MP_p 2U
#define MP_otp_window 5 * 60 /* s */
// Inherited functions.
MPMasterKey mpw_masterKey_v1(
const char *fullName, const char *masterPassword);
const char *mpw_sitePasswordFromTemplate_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam);
const char *mpw_sitePasswordFromCrypt_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText);
const char *mpw_sitePasswordFromDerive_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam);
const char *mpw_siteState_v1(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state);
// Algorithm version overrides.
static MPMasterKey mpw_masterKey_v2(
@@ -47,31 +47,32 @@ static MPMasterKey mpw_masterKey_v2(
}
static MPSiteKey mpw_siteKey_v2(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext) {
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext) {
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
trc( "keyScope: %s\n", keyScope );
// TODO: Implement MPCounterValueTOTP
// OTP counter value.
if (siteCounter == MPCounterValueTOTP)
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
// Calculate the site seed.
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
keyScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName, mpw_hex_l( htonl( siteCounter ) ),
keyContext? mpw_hex_l( htonl( strlen( keyContext ) ) ): NULL, keyContext );
keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext );
size_t siteSaltSize = 0;
uint8_t *siteSalt = NULL;
mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( siteName ) ) );
mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)strlen( siteName ) );
mpw_push_string( &siteSalt, &siteSaltSize, siteName );
mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
mpw_push_int( &siteSalt, &siteSaltSize, siteCounter );
if (keyContext) {
mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)strlen( keyContext ) );
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
}
if (!siteSalt || !siteSaltSize) {
if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) );
mpw_free( siteSalt, siteSaltSize );
return NULL;
}
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
@@ -79,9 +80,9 @@ static MPSiteKey mpw_siteKey_v2(
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n",
mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) {
err( "Could not allocate site key: %s\n", strerror( errno ) );
err( "Could not derive site key: %s\n", strerror( errno ) );
return NULL;
}
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
@@ -90,25 +91,25 @@ static MPSiteKey mpw_siteKey_v2(
}
static const char *mpw_sitePasswordFromTemplate_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
return mpw_sitePasswordFromTemplate_v1( masterKey, siteKey, resultType, resultParam );
}
static const char *mpw_sitePasswordFromCrypt_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText) {
return mpw_sitePasswordFromCrypt_v1( masterKey, siteKey, resultType, cipherText );
}
static const char *mpw_sitePasswordFromDerive_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
return mpw_sitePasswordFromDerive_v1( masterKey, siteKey, resultType, resultParam );
}
static const char *mpw_siteState_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state) {
return mpw_siteState_v1( masterKey, siteKey, resultType, state );
}

View File

@@ -18,27 +18,26 @@
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768LU
#define MP_r 8U
#define MP_p 2U
#define MP_otp_window 5 * 60 /* s */
// Inherited functions.
MPSiteKey mpw_siteKey_v2(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext);
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext);
const char *mpw_sitePasswordFromTemplate_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam);
const char *mpw_sitePasswordFromCrypt_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText);
const char *mpw_sitePasswordFromDerive_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam);
const char *mpw_siteState_v2(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state);
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state);
// Algorithm version overrides.
static MPMasterKey mpw_masterKey_v3(
@@ -49,11 +48,11 @@ static MPMasterKey mpw_masterKey_v3(
// Calculate the master key salt.
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n",
keyScope, mpw_hex_l( htonl( strlen( fullName ) ) ), fullName );
keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName );
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, keyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( strlen( fullName ) ) );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
err( "Could not allocate master key salt: %s\n", strerror( errno ) );
@@ -64,9 +63,9 @@ static MPMasterKey mpw_masterKey_v3(
// Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
mpw_free( &masterKeySalt, masterKeySaltSize );
if (!masterKey) {
err( "Could not allocate master key: %s\n", strerror( errno ) );
err( "Could not derive master key: %s\n", strerror( errno ) );
return NULL;
}
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
@@ -75,32 +74,32 @@ static MPMasterKey mpw_masterKey_v3(
}
static MPSiteKey mpw_siteKey_v3(
const MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext) {
MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter,
MPKeyPurpose keyPurpose, const char *keyContext) {
return mpw_siteKey_v2( masterKey, siteName, siteCounter, keyPurpose, keyContext );
}
static const char *mpw_sitePasswordFromTemplate_v3(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
return mpw_sitePasswordFromTemplate_v2( masterKey, siteKey, resultType, resultParam );
}
static const char *mpw_sitePasswordFromCrypt_v3(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *cipherText) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *cipherText) {
return mpw_sitePasswordFromCrypt_v2( masterKey, siteKey, resultType, cipherText );
}
static const char *mpw_sitePasswordFromDerive_v3(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *resultParam) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *resultParam) {
return mpw_sitePasswordFromDerive_v2( masterKey, siteKey, resultType, resultParam );
}
static const char *mpw_siteState_v3(
MPMasterKey masterKey, MPSiteKey siteKey, const MPResultType resultType, const char *state) {
MPMasterKey masterKey, MPSiteKey siteKey, MPResultType resultType, const char *state) {
return mpw_siteState_v2( masterKey, siteKey, resultType, state );
}

View File

@@ -21,7 +21,7 @@
#include "mpw-marshall-util.h"
#include "mpw-util.h"
char *mpw_get_token(char **in, char *eol, char *delim) {
char *mpw_get_token(const char **in, const char *eol, char *delim) {
// Skip leading spaces.
for (; **in == ' '; ++*in);
@@ -50,6 +50,7 @@ time_t mpw_mktime(
return false;
}
#if MPW_JSON
json_object *mpw_get_json_section(
json_object *obj, const char *section) {
@@ -76,14 +77,14 @@ const char *mpw_get_json_string(
return json_object_get_string( json_value );
}
int32_t mpw_get_json_int(
json_object *obj, const char *section, int32_t defaultValue) {
int64_t mpw_get_json_int(
json_object *obj, const char *section, int64_t defaultValue) {
json_object *json_value = mpw_get_json_section( obj, section );
if (!json_value)
return defaultValue;
return json_object_get_int( json_value );
return json_object_get_int64( json_value );
}
bool mpw_get_json_boolean(
@@ -95,15 +96,15 @@ bool mpw_get_json_boolean(
return json_object_get_boolean( json_value ) == TRUE;
}
#endif
bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword) {
if (*masterKeyAlgorithm != targetKeyAlgorithm) {
mpw_free( *masterKey, MPMasterKeySize );
mpw_free( masterKey, MPMasterKeySize );
*masterKeyAlgorithm = targetKeyAlgorithm;
*masterKey = mpw_masterKey(
fullName, masterPassword, *masterKeyAlgorithm );
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
if (!*masterKey) {
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm );
return false;

View File

@@ -20,7 +20,7 @@
#define _MPW_MARSHALL_UTIL_H
#include <time.h>
#include <json-c/json.h>
#include "json-c/json.h"
#include "mpw-algorithm.h"
@@ -30,7 +30,7 @@
* The input string reference is advanced beyond the token delimitor if one is found.
* @return A new string containing the token or NULL if the delim wasn't found before eol. */
char *mpw_get_token(
char **in, char *eol, char *delim);
const char **in, const char *eol, char *delim);
/** Convert an RFC 3339 time string into epoch time. */
time_t mpw_mktime(
const char *time);
@@ -50,8 +50,8 @@ const char *mpw_get_json_string(
/** Search for an integer in a JSON object tree.
* @param section A dot-delimited list of JSON object keys to walk toward the child object.
* @return The integer value or defaultValue if one of the section's object keys was not found in the source object's tree. */
int32_t mpw_get_json_int(
json_object *obj, const char *section, int32_t defaultValue);
int64_t mpw_get_json_int(
json_object *obj, const char *section, int64_t defaultValue);
/** Search for a boolean in a JSON object tree.
* @param section A dot-delimited list of JSON object keys to walk toward the child object.
* @return The boolean value or defaultValue if one of the section's object keys was not found in the source object's tree. */

View File

@@ -63,8 +63,8 @@ MPMarshalledSite *mpw_marshall_site(
.counter = siteCounter,
.algorithm = algorithmVersion,
.loginName = NULL,
.loginGenerated = false,
.loginContent = NULL,
.loginType = MPResultTypeTemplateName,
.url = NULL,
.uses = 0,
@@ -79,35 +79,54 @@ MPMarshalledSite *mpw_marshall_site(
MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledSite *site, const char *keyword) {
if (!keyword || !mpw_realloc( &site->questions, NULL, sizeof( MPMarshalledQuestion ) * ++site->questions_count ))
if (!mpw_realloc( &site->questions, NULL, sizeof( MPMarshalledQuestion ) * ++site->questions_count ))
return NULL;
if (!keyword)
keyword = "";
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
*question = (MPMarshalledQuestion){
.keyword = strdup( keyword ),
.content = NULL,
.type = MPResultTypeTemplatePhrase,
};
return question;
}
bool mpw_marshal_free(
MPMarshalledUser *user) {
bool mpw_marshal_info_free(
MPMarshallInfo **info) {
if (!user)
if (!info || !*info)
return true;
bool success = true;
for (size_t s = 0; s < user->sites_count; ++s) {
MPMarshalledSite *site = &user->sites[s];
success &= mpw_free_string( site->name );
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
return success;
}
bool mpw_marshal_free(
MPMarshalledUser **user) {
if (!user || !*user)
return true;
bool success = true;
success &= mpw_free_strings( &(*user)->fullName, &(*user)->masterPassword, NULL );
for (size_t s = 0; s < (*user)->sites_count; ++s) {
MPMarshalledSite *site = &(*user)->sites[s];
success &= mpw_free_strings( &site->name, &site->content, &site->loginContent, &site->url, NULL );
for (size_t q = 0; q < site->questions_count; ++q) {
MPMarshalledQuestion *question = &site->questions[q];
success &= mpw_free_string( question->keyword );
success &= mpw_free_strings( &question->keyword, &question->content, NULL );
}
success &= mpw_free( site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
success &= mpw_free( &site->questions, sizeof( MPMarshalledQuestion ) * site->questions_count );
}
success &= mpw_free( user->sites, sizeof( MPMarshalledSite ) * user->sites_count );
success &= mpw_free_string( user->fullName );
success &= mpw_free_string( user->masterPassword );
success &= mpw_free( &(*user)->sites, sizeof( MPMarshalledSite ) * (*user)->sites_count );
success &= mpw_free( user, sizeof( MPMarshalledUser ) );
return success;
@@ -163,7 +182,7 @@ static bool mpw_marshall_write_flat(
if (!site->name || !strlen( site->name ))
continue;
const char *content = NULL;
const char *content = NULL, *loginContent = NULL;
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
@@ -171,26 +190,32 @@ static bool mpw_marshall_write_flat(
return false;
}
if (site->type & MPResultTypeClassTemplate)
content = mpw_siteResult( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, site->content, site->algorithm );
content = mpw_siteResult( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, site->content, site->algorithm );
loginContent = mpw_siteResult( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, site->loginContent, site->algorithm );
}
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
else {
// Redacted
content = strdup( site->content );
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
content = strdup( site->content );
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
loginContent = strdup( site->loginContent );
}
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
mpw_string_pushf( out, "%s %8ld %lu:%lu:%lu %25s\t%25s\t%s\n",
dateString, (long)site->uses, (long)site->type, (long)site->algorithm, (long)site->counter,
site->loginName?: "", site->name, content?: "" );
mpw_free_string( content );
loginContent?: "", site->name, content?: "" );
mpw_free_strings( &content, &loginContent, NULL );
}
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ MPMarshallSuccess };
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return true;
}
#if MPW_JSON
static bool mpw_marshall_write_json(
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
@@ -225,15 +250,15 @@ static bool mpw_marshall_write_json(
// Section: "user"
json_object *json_user = json_object_new_object();
json_object_object_add( json_file, "user", json_user );
json_object_object_add( json_user, "avatar", json_object_new_int( (int)user->avatar ) );
json_object_object_add( json_user, "avatar", json_object_new_int( (int32_t)user->avatar ) );
json_object_object_add( json_user, "full_name", json_object_new_string( user->fullName ) );
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &user->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( masterKey, MPMasterKeySize ) ) );
json_object_object_add( json_user, "algorithm", json_object_new_int( (int)user->algorithm ) );
json_object_object_add( json_user, "default_type", json_object_new_int( (int)user->defaultType ) );
json_object_object_add( json_user, "algorithm", json_object_new_int( (int32_t)user->algorithm ) );
json_object_object_add( json_user, "default_type", json_object_new_int( (int32_t)user->defaultType ) );
// Section "sites"
json_object *json_sites = json_object_new_object();
@@ -243,7 +268,7 @@ static bool mpw_marshall_write_json(
if (!site->name || !strlen( site->name ))
continue;
const char *content = NULL;
const char *content = NULL, *loginContent = NULL;
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
@@ -251,26 +276,31 @@ static bool mpw_marshall_write_json(
return false;
}
if (site->type & MPResultTypeClassTemplate)
content = mpw_siteResult( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, site->content, site->algorithm );
content = mpw_siteResult( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, site->content, site->algorithm );
loginContent = mpw_siteResult( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, site->loginContent, site->algorithm );
}
else if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
else {
// Redacted
content = strdup( site->content );
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
content = strdup( site->content );
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
loginContent = strdup( site->loginContent );
}
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( (int)site->type ) );
json_object_object_add( json_site, "counter", json_object_new_int( (int)site->counter ) );
json_object_object_add( json_site, "algorithm", json_object_new_int( (int)site->algorithm ) );
json_object_object_add( json_site, "type", json_object_new_int( (int32_t)site->type ) );
json_object_object_add( json_site, "counter", json_object_new_int( (int32_t)site->counter ) );
json_object_object_add( json_site, "algorithm", json_object_new_int( (int32_t)site->algorithm ) );
if (content)
json_object_object_add( json_site, "password", json_object_new_string( content ) );
if (site->loginName)
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 ) );
if (loginContent)
json_object_object_add( json_site, "login_name", json_object_new_string( loginContent ) );
json_object_object_add( json_site, "login_type", json_object_new_int( (int32_t)site->loginType ) );
json_object_object_add( json_site, "uses", json_object_new_int( (int)site->uses ) );
json_object_object_add( json_site, "uses", json_object_new_int( (int32_t)site->uses ) );
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
json_object_object_add( json_site, "last_used", json_object_new_string( dateString ) );
@@ -283,13 +313,18 @@ static bool mpw_marshall_write_json(
json_object *json_site_question = json_object_new_object();
json_object_object_add( json_site_questions, question->keyword, json_site_question );
json_object_object_add( json_site_question, "type", json_object_new_int( (int32_t)question->type ) );
if (!user->redacted) {
// Clear Text
const char *answer = mpw_siteResult( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeRecovery, question->keyword, MPResultTypeTemplatePhrase, NULL, site->algorithm );
if (answer)
json_object_object_add( json_site_question, "answer", json_object_new_string( answer ) );
const char *answerContent = mpw_siteResult( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeRecovery, question->keyword, question->type, question->content, site->algorithm );
json_object_object_add( json_site_question, "answer", json_object_new_string( answerContent ) );
}
else {
// Redacted
if (site->type & MPSiteFeatureExportContent && question->content && strlen( question->content ))
json_object_object_add( json_site_question, "answer", json_object_new_string( question->content ) );
}
}
@@ -298,35 +333,93 @@ static bool mpw_marshall_write_json(
if (site->url)
json_object_object_add( json_site_mpw, "url", json_object_new_string( site->url ) );
mpw_free_string( content );
mpw_free_strings( &content, &loginContent, NULL );
}
mpw_string_pushf( out, "%s\n", json_object_to_json_string_ext( json_file, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED ) );
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
json_object_put( json_file );
*error = (MPMarshallError){ MPMarshallSuccess };
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return true;
}
#endif
bool mpw_marshall_write(
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error) {
switch (outFormat) {
case MPMarshallFormatNone:
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return false;
case MPMarshallFormatFlat:
return mpw_marshall_write_flat( out, user, error );
#if MPW_JSON
case MPMarshallFormatJSON:
return mpw_marshall_write_json( out, user, error );
#endif
default:
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
return false;
}
}
static void mpw_marshall_read_flat_info(
const char *in, MPMarshallInfo *info) {
info->algorithm = MPAlgorithmVersionCurrent;
// Parse import data.
bool headerStarted = false;
for (const char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) {
// Comment or header
if (*positionInLine == '#') {
++positionInLine;
if (!headerStarted) {
if (*positionInLine == '#')
// ## starts header
headerStarted = true;
// Comment before header
continue;
}
if (*positionInLine == '#')
// ## ends header
break;
// Header
char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
if (!headerName || !headerValue)
continue;
if (strcmp( headerName, "Algorithm" ) == 0)
info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
info->fullName = strdup( headerValue );
if (strcmp( headerName, "Key ID" ) == 0)
info->keyID = strdup( headerValue );
if (strcmp( headerName, "Passwords" ) == 0)
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
if (strcmp( headerName, "Date" ) == 0)
info->date = mpw_mktime( headerValue );
mpw_free_strings( &headerName, &headerValue, NULL );
continue;
}
}
}
static MPMarshalledUser *mpw_marshall_read_flat(
char *in, const char *masterPassword, MPMarshallError *error) {
const char *in, const char *masterPassword, MPMarshallError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
if (!in || !strlen( in )) {
error->type = MPMarshallErrorStructure;
error->description = mpw_str( "No input data." );
return NULL;
}
// Parse import data.
MPMasterKey masterKey = NULL;
@@ -336,7 +429,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
MPAlgorithmVersion algorithm = MPAlgorithmVersionCurrent, masterKeyAlgorithm = (MPAlgorithmVersion)-1;
MPResultType defaultType = MPResultTypeDefault;
bool headerStarted = false, headerEnded = false, importRedacted = false;
for (char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) {
for (const char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) {
// Comment or header
if (*positionInLine == '#') {
@@ -394,8 +487,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (strcmp( headerName, "Passwords" ) == 0)
importRedacted = strcmp( headerValue, "VISIBLE" ) != 0;
mpw_free_string( headerName );
mpw_free_string( headerValue );
mpw_free_strings( &headerName, &headerValue, NULL );
continue;
}
if (!headerEnded)
@@ -437,7 +529,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (typeAndVersion) {
str_type = strdup( strtok( typeAndVersion, ":" ) );
str_algorithm = strdup( strtok( NULL, "" ) );
mpw_free_string( typeAndVersion );
mpw_free_string( &typeAndVersion );
}
str_counter = strdup( "1" );
siteLoginName = NULL;
@@ -453,7 +545,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
str_algorithm = strdup( strtok( NULL, ":" ) );
str_counter = strdup( strtok( NULL, "" ) );
mpw_free_string( typeAndVersionAndCounter );
mpw_free_string( &typeAndVersionAndCounter );
}
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
@@ -497,23 +589,28 @@ static MPMarshalledUser *mpw_marshall_read_flat(
return NULL;
}
site->loginName = siteLoginName? strdup( siteLoginName ): NULL;
site->uses = (unsigned int)atoi( str_uses );
site->lastUsed = siteLastUsed;
if (siteContent && strlen( siteContent )) {
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
return NULL;
}
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
return NULL;
}
if (siteContent && strlen( siteContent ))
site->content = mpw_siteState( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, siteContent, site->algorithm );
}
else
// Redacted
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
}
else {
// Redacted
if (siteContent && strlen( siteContent ))
site->content = strdup( siteContent );
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName );
}
}
else {
@@ -524,27 +621,50 @@ static MPMarshalledUser *mpw_marshall_read_flat(
return NULL;
}
mpw_free_string( str_lastUsed );
mpw_free_string( str_uses );
mpw_free_string( str_type );
mpw_free_string( str_algorithm );
mpw_free_string( str_counter );
mpw_free_string( siteLoginName );
mpw_free_string( siteName );
mpw_free_string( siteContent );
mpw_free_strings( &str_lastUsed, &str_uses, &str_type, &str_algorithm, &str_counter, NULL );
mpw_free_strings( &siteLoginName, &siteName, &siteContent, NULL );
}
mpw_free_string( fullName );
mpw_free_string( keyID );
mpw_free( masterKey, MPMasterKeySize );
mpw_free_strings( &fullName, &keyID, NULL );
mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ MPMarshallSuccess };
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return user;
}
static MPMarshalledUser *mpw_marshall_read_json(
char *in, const char *masterPassword, MPMarshallError *error) {
#if MPW_JSON
static void mpw_marshall_read_json_info(
const char *in, MPMarshallInfo *info) {
*error = (MPMarshallError){ MPMarshallErrorInternal };
// Parse JSON.
enum json_tokener_error json_error = json_tokener_success;
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
if (!json_file || json_error != json_tokener_success)
return;
// Section: "export"
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
if (fileFormat < 1)
return;
info->redacted = mpw_get_json_boolean( json_file, "export.redacted", true );
info->date = mpw_mktime( mpw_get_json_string( json_file, "export.date", NULL ) );
// Section: "user"
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
info->fullName = strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
info->keyID = strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
json_object_put( json_file );
}
static MPMarshalledUser *mpw_marshall_read_json(
const char *in, const char *masterPassword, MPMarshallError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
if (!in || !strlen( in )) {
error->type = MPMarshallErrorStructure;
error->description = mpw_str( "No input data." );
return NULL;
}
// Parse JSON.
enum json_tokener_error json_error = json_tokener_success;
@@ -560,7 +680,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
MPMarshalledUser *user = NULL;
// Section: "export"
unsigned int fileFormat = (unsigned int)mpw_get_json_int( json_file, "export.format", 0 );
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
if (fileFormat < 1) {
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
return NULL;
@@ -572,7 +692,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
const char *fullName = mpw_get_json_string( json_file, "user.full_name", NULL );
const char *str_lastUsed = mpw_get_json_string( json_file, "user.last_used", NULL );
const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL );
int32_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
int64_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
return NULL;
@@ -614,13 +734,13 @@ static MPMarshalledUser *mpw_marshall_read_json(
json_object *json_sites = mpw_get_json_section( json_file, "sites" );
json_object_object_foreachC( json_sites, json_site ) {
const char *siteName = json_site.key;
value = mpw_get_json_int( json_site.val, "algorithm", user->algorithm );
value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm );
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
return NULL;
}
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", user->defaultType );
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
if (!mpw_nameForType( siteType )) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
return NULL;
@@ -633,7 +753,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
MPCounterValue siteCounter = (MPCounterValue)value;
const char *siteContent = mpw_get_json_string( json_site.val, "password", NULL );
const char *siteLoginName = mpw_get_json_string( json_site.val, "login_name", NULL );
bool siteLoginGenerated = mpw_get_json_boolean( json_site.val, "login_generated", false );
MPResultType siteLoginType = (MPResultType)mpw_get_json_int( json_site.val, "login_type", MPResultTypeTemplateName );
unsigned int siteUses = (unsigned int)mpw_get_json_int( json_site.val, "uses", 0 );
str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL );
time_t siteLastUsed = mpw_mktime( str_lastUsed );
@@ -651,46 +771,94 @@ static MPMarshalledUser *mpw_marshall_read_json(
return NULL;
}
site->loginName = siteLoginName? strdup( siteLoginName ): NULL;
site->loginGenerated = siteLoginGenerated;
site->loginType = siteLoginType;
site->url = siteURL? strdup( siteURL ): NULL;
site->uses = siteUses;
site->lastUsed = siteLastUsed;
if (siteContent && strlen( siteContent )) {
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
return NULL;
}
if (!user->redacted) {
// Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." };
return NULL;
}
if (siteContent && strlen( siteContent ))
site->content = mpw_siteState( masterKey, site->name, site->counter,
MPKeyPurposeAuthentication, NULL, site->type, siteContent, site->algorithm );
}
else
// Redacted
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeIdentification, NULL, site->loginType, siteLoginName, site->algorithm );
}
else {
// Redacted
if (siteContent && strlen( siteContent ))
site->content = strdup( siteContent );
if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName );
}
json_object_iter json_site_question;
json_object *json_site_questions = mpw_get_json_section( json_site.val, "questions" );
json_object_object_foreachC( json_site_questions, json_site_question )
mpw_marshal_question( site, json_site_question.key );
json_object_object_foreachC( json_site_questions, json_site_question ) {
MPMarshalledQuestion *question = mpw_marshal_question( site, json_site_question.key );
const char *answerContent = mpw_get_json_string( json_site_question.val, "answer", NULL );
question->type = (MPResultType)mpw_get_json_int( json_site_question.val, "type", MPResultTypeTemplatePhrase );
if (!user->redacted) {
// Clear Text
if (answerContent && strlen( answerContent ))
question->content = mpw_siteState( masterKey, site->name, MPCounterValueInitial,
MPKeyPurposeRecovery, question->keyword, question->type, answerContent, site->algorithm );
}
else {
// Redacted
if (answerContent && strlen( answerContent ))
question->content = strdup( answerContent );
}
}
}
json_object_put( json_file );
*error = (MPMarshallError){ MPMarshallSuccess };
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return user;
}
#endif
MPMarshallInfo *mpw_marshall_read_info(
const char *in) {
MPMarshallInfo *info = malloc( sizeof( MPMarshallInfo ) );
*info = (MPMarshallInfo){ .format = MPMarshallFormatNone };
if (in && strlen( in )) {
if (in[0] == '#') {
*info = (MPMarshallInfo){ .format = MPMarshallFormatFlat };
mpw_marshall_read_flat_info( in, info );
}
else if (in[0] == '{') {
*info = (MPMarshallInfo){ .format = MPMarshallFormatJSON };
#if MPW_JSON
mpw_marshall_read_json_info( in, info );
#endif
}
}
return info;
}
MPMarshalledUser *mpw_marshall_read(
char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error) {
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error) {
switch (inFormat) {
case MPMarshallFormatNone:
*error = (MPMarshallError){ .type = MPMarshallSuccess };
return false;
case MPMarshallFormatFlat:
return mpw_marshall_read_flat( in, masterPassword, error );
#if MPW_JSON
case MPMarshallFormatJSON:
return mpw_marshall_read_json( in, masterPassword, error );
#endif
default:
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
return NULL;
@@ -700,6 +868,9 @@ MPMarshalledUser *mpw_marshall_read(
const MPMarshallFormat mpw_formatWithName(
const char *formatName) {
if (!formatName || !strlen( formatName ))
return MPMarshallFormatNone;
// Lower-case to standardize it.
size_t stdFormatNameSize = strlen( formatName );
char stdFormatName[stdFormatNameSize + 1];
@@ -707,6 +878,8 @@ const MPMarshallFormat mpw_formatWithName(
stdFormatName[c] = (char)tolower( formatName[c] );
stdFormatName[stdFormatNameSize] = '\0';
if (strncmp( mpw_nameForFormat( MPMarshallFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
return MPMarshallFormatNone;
if (strncmp( mpw_nameForFormat( MPMarshallFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
return MPMarshallFormatFlat;
if (strncmp( mpw_nameForFormat( MPMarshallFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
@@ -720,6 +893,8 @@ const char *mpw_nameForFormat(
const MPMarshallFormat format) {
switch (format) {
case MPMarshallFormatNone:
return "none";
case MPMarshallFormatFlat:
return "flat";
case MPMarshallFormatJSON:
@@ -735,6 +910,8 @@ const char *mpw_marshall_format_extension(
const MPMarshallFormat format) {
switch (format) {
case MPMarshallFormatNone:
return NULL;
case MPMarshallFormatFlat:
return "mpsites";
case MPMarshallFormatJSON:

View File

@@ -25,7 +25,9 @@
//// Types.
typedef enum( unsigned int, MPMarshallFormat ) {
typedef mpw_enum( unsigned int, MPMarshallFormat ) {
/** Generate a key for authentication. */
MPMarshallFormatNone,
/** Generate a key for authentication. */
MPMarshallFormatFlat,
/** Generate a name for identification. */
@@ -34,7 +36,7 @@ typedef enum( unsigned int, MPMarshallFormat ) {
MPMarshallFormatDefault = MPMarshallFormatJSON,
};
typedef enum( unsigned int, MPMarshallErrorType ) {
typedef mpw_enum( unsigned int, MPMarshallErrorType ) {
/** The marshalling operation completed successfully. */
MPMarshallSuccess,
/** An error in the structure of the marshall file interrupted marshalling. */
@@ -57,6 +59,8 @@ typedef struct MPMarshallError {
typedef struct MPMarshalledQuestion {
const char *keyword;
const char *content;
MPResultType type;
} MPMarshalledQuestion;
typedef struct MPMarshalledSite {
@@ -66,8 +70,8 @@ typedef struct MPMarshalledSite {
MPCounterValue counter;
MPAlgorithmVersion algorithm;
const char *loginName;
bool loginGenerated;
const char *loginContent;
MPResultType loginType;
const char *url;
unsigned int uses;
@@ -91,24 +95,44 @@ typedef struct MPMarshalledUser {
MPMarshalledSite *sites;
} MPMarshalledUser;
typedef struct MPMarshallInfo {
MPMarshallFormat format;
MPAlgorithmVersion algorithm;
const char *fullName;
const char *keyID;
bool redacted;
time_t date;
} MPMarshallInfo;
//// Marshalling.
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */
bool mpw_marshall_write(
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error);
/** Try to read metadata on the sites in the input buffer. */
MPMarshallInfo *mpw_marshall_read_info(
const char *in);
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */
MPMarshalledUser *mpw_marshall_read(
char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
//// Utilities.
/** Create a new user object ready for marshalling. */
MPMarshalledUser *mpw_marshall_user(
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
/** Create a new site attached to the given user object, ready for marshalling. */
MPMarshalledSite *mpw_marshall_site(
MPMarshalledUser *user,
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion);
/** Create a new question attached to the given site object, ready for marshalling. */
MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledSite *site, const char *keyword);
/** Free the given user object and all associated data. */
bool mpw_marshal_info_free(
MPMarshallInfo **info);
bool mpw_marshal_free(
MPMarshalledUser *user);
MPMarshalledUser **user);
//// Format.
@@ -122,6 +146,9 @@ const MPMarshallFormat mpw_formatWithName(
*/
const char *mpw_nameForFormat(
const MPMarshallFormat format);
/**
* @return The file extension that's recommended for files that use the given marshalling format.
*/
const char *mpw_marshall_format_extension(
const MPMarshallFormat format);

View File

@@ -16,16 +16,9 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef COLOR
#include <curses.h>
#include <term.h>
#endif
#include "mpw-types.h"
#include "mpw-util.h"
@@ -48,9 +41,9 @@ const MPResultType mpw_typeWithName(const char *typeName) {
if ('n' == typeName[0])
return MPResultTypeTemplateName;
if ('P' == typeName[0])
return MPResultTypeStatePersonal;
return MPResultTypeStatefulPersonal;
if ('D' == typeName[0])
return MPResultTypeStateDevice;
return MPResultTypeStatefulDevice;
if ('k' == typeName[0])
return MPResultTypeDeriveKey;
}
@@ -82,10 +75,10 @@ const MPResultType mpw_typeWithName(const char *typeName) {
return MPResultTypeTemplateName;
if (strncmp( mpw_nameForType( MPResultTypeTemplatePhrase ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeTemplatePhrase;
if (strncmp( mpw_nameForType( MPResultTypeStatePersonal ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeStatePersonal;
if (strncmp( mpw_nameForType( MPResultTypeStateDevice ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeStateDevice;
if (strncmp( mpw_nameForType( MPResultTypeStatefulPersonal ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeStatefulPersonal;
if (strncmp( mpw_nameForType( MPResultTypeStatefulDevice ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeStatefulDevice;
if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeDeriveKey;
@@ -112,9 +105,9 @@ const char *mpw_nameForType(MPResultType resultType) {
return "name";
case MPResultTypeTemplatePhrase:
return "phrase";
case MPResultTypeStatePersonal:
case MPResultTypeStatefulPersonal:
return "personal";
case MPResultTypeStateDevice:
case MPResultTypeStatefulDevice:
return "device";
case MPResultTypeDeriveKey:
return "key";
@@ -170,11 +163,11 @@ const char **mpw_templatesForType(MPResultType type, size_t *count) {
}
}
const char *mpw_templateForType(MPResultType type, uint8_t seedByte) {
const char *mpw_templateForType(MPResultType type, uint8_t templateIndex) {
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );
char const *template = templates && count? templates[seedByte % count]: NULL;
char const *template = templates && count? templates[templateIndex % count]: NULL;
free( templates );
return template;

View File

@@ -23,11 +23,15 @@
#include <stdint.h>
#include <stdbool.h>
//#ifdef NS_ENUM
//#define enum(_type, _name) NS_ENUM(_type, _name)
//#else
#define enum(_type, _name) _type _name; enum
//#endif
#ifdef NS_ENUM
#define mpw_enum(_type, _name) NS_ENUM(_type, _name)
#else
#define mpw_enum(_type, _name) _type _name; enum
#endif
#ifndef __unused
#define __unused __attribute__((unused))
#endif
//// Types.
@@ -37,7 +41,7 @@ typedef const uint8_t *MPMasterKey;
typedef const uint8_t *MPSiteKey;
typedef const char *MPKeyID;
typedef enum( uint8_t, MPKeyPurpose ) {
typedef mpw_enum( uint8_t, MPKeyPurpose ) {
/** Generate a key for authentication. */
MPKeyPurposeAuthentication,
/** Generate a name for identification. */
@@ -47,17 +51,17 @@ typedef enum( uint8_t, MPKeyPurpose ) {
};
// bit 4 - 9
typedef enum( uint16_t, MPResultTypeClass ) {
typedef mpw_enum( uint16_t, MPResultTypeClass ) {
/** Use the site key to generate a password from a template. */
MPResultTypeClassTemplate = 1 << 4,
/** Use the site key to encrypt and decrypt a stateful entity. */
MPResultTypeClassState = 1 << 5,
MPResultTypeClassStateful = 1 << 5,
/** Use the site key to derive a site-specific object. */
MPResultTypeClassDerive = 1 << 6,
};
// bit 10 - 15
typedef enum( uint16_t, MPSiteFeature ) {
typedef mpw_enum( uint16_t, MPSiteFeature ) {
/** Export the key-protected content data. */
MPSiteFeatureExportContent = 1 << 10,
/** Never export content. */
@@ -67,7 +71,7 @@ typedef enum( uint16_t, MPSiteFeature ) {
};
// bit 0-3 | MPResultTypeClass | MPSiteFeature
typedef enum( uint32_t, MPResultType ) {
typedef mpw_enum( uint32_t, MPResultType ) {
/** pg^VMAUBk5x3p%HP%i4= */
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
/** BiroYena8:Kixa */
@@ -86,9 +90,9 @@ typedef enum( uint32_t, MPResultType ) {
MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0,
/** Custom saved password. */
MPResultTypeStatePersonal = 0x0 | MPResultTypeClassState | MPSiteFeatureExportContent,
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
/** Custom saved password that should not be exported from the device. */
MPResultTypeStateDevice = 0x1 | MPResultTypeClassState | MPSiteFeatureDevicePrivate,
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
/** Derive a unique binary key. */
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
@@ -96,7 +100,7 @@ typedef enum( uint32_t, MPResultType ) {
MPResultTypeDefault = MPResultTypeTemplateLong,
};
typedef enum ( uint32_t, MPCounterValue ) {
typedef mpw_enum ( uint32_t, MPCounterValue ) {
/** Use a time-based counter value, resulting in a TOTP generator. */
MPCounterValueTOTP = 0,
/** The initial value for a site's counter. */
@@ -142,7 +146,7 @@ const char **mpw_templatesForType(MPResultType type, size_t *count);
* @return An internal string that contains the password encoding template of the given type
* for a seed that starts with the given byte.
*/
const char *mpw_templateForType(MPResultType type, uint8_t seedByte);
const char *mpw_templateForType(MPResultType type, uint8_t templateIndex);
/**
* @return An internal string that contains all the characters that occur in the given character class.

View File

@@ -26,34 +26,57 @@
#include <term.h>
#endif
#if HAS_CPERCIVA
#if MPW_CPERCIVA
#include <scrypt/crypto_scrypt.h>
#include <scrypt/sha256.h>
#elif HAS_SODIUM
#elif MPW_SODIUM
#include "sodium.h"
#ifdef SODIUM_LIBRARY_MINIMAL
#include "crypto_stream_aes128ctr.h"
#include "crypto_kdf_blake2b.h"
#endif
#endif
#include "mpw-util.h"
#ifdef inf_level
int mpw_verbosity = inf_level;
#endif
bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
void mpw_uint16(const uint16_t number, uint8_t buf[2]) {
buf[0] = (uint8_t)((number >> 8L) & UINT8_MAX);
buf[1] = (uint8_t)((number >> 0L) & UINT8_MAX);
}
void mpw_uint32(const uint32_t number, uint8_t buf[4]) {
buf[0] = (uint8_t)((number >> 24) & UINT8_MAX);
buf[1] = (uint8_t)((number >> 16) & UINT8_MAX);
buf[2] = (uint8_t)((number >> 8L) & UINT8_MAX);
buf[3] = (uint8_t)((number >> 0L) & UINT8_MAX);
}
void mpw_uint64(const uint64_t number, uint8_t buf[8]) {
buf[0] = (uint8_t)((number >> 56) & UINT8_MAX);
buf[1] = (uint8_t)((number >> 48) & UINT8_MAX);
buf[2] = (uint8_t)((number >> 40) & UINT8_MAX);
buf[3] = (uint8_t)((number >> 32) & UINT8_MAX);
buf[4] = (uint8_t)((number >> 24) & UINT8_MAX);
buf[5] = (uint8_t)((number >> 16) & UINT8_MAX);
buf[6] = (uint8_t)((number >> 8L) & UINT8_MAX);
buf[7] = (uint8_t)((number >> 0L) & UINT8_MAX);
}
bool mpw_push_buf(uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize) {
if (!buffer || !bufferSize || !pushBuffer || !pushSize)
return false;
if (*bufferSize == ERR)
if (*bufferSize == (size_t)ERR)
// The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content.
return false;
if (!mpw_realloc( buffer, bufferSize, pushSize )) {
// realloc failed, we can't push. Mark the buffer as broken.
mpw_free( *buffer, *bufferSize );
mpw_free( buffer, *bufferSize );
*bufferSize = (size_t)ERR;
*buffer = NULL;
return false;
}
@@ -62,13 +85,15 @@ bool mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *
return true;
}
bool mpw_push_string(uint8_t **const buffer, size_t *const bufferSize, const char *pushString) {
bool mpw_push_string(uint8_t **buffer, size_t *bufferSize, const char *pushString) {
return pushString && mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
}
bool mpw_string_push(char **const string, const char *pushString) {
bool mpw_string_push(char **string, const char *pushString) {
if (!string || !pushString)
return false;
if (!*string)
*string = calloc( 1, sizeof( char ) );
@@ -76,29 +101,29 @@ bool mpw_string_push(char **const string, const char *pushString) {
return pushString && mpw_push_buf( (uint8_t **const)string, &stringLength, pushString, strlen( pushString ) + 1 );
}
bool mpw_string_pushf(char **const string, const char *pushFormat, ...) {
bool mpw_string_pushf(char **string, const char *pushFormat, ...) {
va_list args;
va_start( args, pushFormat );
char *pushString = NULL;
bool success = vasprintf( &pushString, pushFormat, args ) >= 0 && mpw_string_push( string, pushString );
bool success = mpw_string_push( string, mpw_vstr( pushFormat, args ) );
va_end( args );
mpw_free_string( pushString );
return success;
}
bool mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
bool mpw_push_int(uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt) {
return mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
uint8_t pushBuf[4 /* 32 / 8 */];
mpw_uint32( pushInt, pushBuf );
return mpw_push_buf( buffer, bufferSize, &pushBuf, sizeof( pushBuf ) );
}
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize) {
if (!buffer)
return false;
void *newBuffer = realloc( *buffer, (bufferSize? *bufferSize: 0) + deltaSize );
void *newBuffer = realloc( (void *)*buffer, (bufferSize? *bufferSize: 0) + deltaSize );
if (!newBuffer)
return false;
@@ -109,19 +134,35 @@ bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize) {
return true;
}
bool mpw_free(const void *buffer, const size_t bufferSize) {
bool __mpw_free(const void **buffer, const size_t bufferSize) {
if (!buffer)
if (!buffer || !*buffer)
return false;
memset( (void *)buffer, 0, bufferSize );
free( (void *)buffer );
memset( (void *)*buffer, 0, bufferSize );
free( (void *)*buffer );
*buffer = NULL;
return true;
}
bool mpw_free_string(const char *string) {
bool __mpw_free_string(const char **string) {
return string && mpw_free( string, strlen( string ) );
return *string && __mpw_free( (const void **)string, strlen( *string ) );
}
bool __mpw_free_strings(const char **strings, ...) {
bool success = true;
va_list args;
va_start( args, strings );
success &= mpw_free_string( strings );
for (const char **string; (string = va_arg( args, const char ** ));)
success &= mpw_free_string( string );
va_end( args );
return success;
}
uint8_t const *mpw_kdf_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize,
@@ -134,14 +175,14 @@ uint8_t const *mpw_kdf_scrypt(const size_t keySize, const char *secret, const ui
if (!key)
return NULL;
#if HAS_CPERCIVA
#if MPW_CPERCIVA
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
mpw_free( key, keySize );
mpw_free( &key, keySize );
return NULL;
}
#elif HAS_SODIUM
#elif MPW_SODIUM
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) != 0) {
mpw_free( key, keySize );
mpw_free( &key, keySize );
return NULL;
}
#else
@@ -163,7 +204,7 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
if (!subkey)
return NULL;
#if HAS_SODIUM
#if MPW_SODIUM
if (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
contextSize < crypto_generichash_blake2b_BYTES_MIN || contextSize > crypto_generichash_blake2b_BYTES_MAX ||
@@ -175,10 +216,8 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES];
bzero( saltBuf, sizeof saltBuf );
if (id) {
uint64_t id_n = htonll( id );
memcpy( saltBuf, &id_n, sizeof id_n );
}
if (id)
mpw_uint64( id, saltBuf );
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
bzero( personalBuf, sizeof saltBuf );
@@ -186,7 +225,7 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
memcpy( personalBuf, personal, strlen( personal ) );
if (crypto_generichash_blake2b_salt_personal( subkey, subkeySize, context, contextSize, key, keySize, saltBuf, personalBuf ) != 0) {
mpw_free( subkey, subkeySize );
mpw_free( &subkey, subkeySize );
return NULL;
}
#else
@@ -201,13 +240,13 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
if (!key || !keySize || !message || !messageSize)
return NULL;
#if HAS_CPERCIVA
#if MPW_CPERCIVA
uint8_t *const mac = malloc( 32 );
if (!mac)
return NULL;
HMAC_SHA256_Buf( key, keySize, message, messageSize, mac );
#elif HAS_SODIUM
#elif MPW_SODIUM
uint8_t *const mac = malloc( crypto_auth_hmacsha256_BYTES );
if (!mac)
return NULL;
@@ -216,7 +255,7 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
crypto_auth_hmacsha256_update( &state, message, messageSize ) != 0 ||
crypto_auth_hmacsha256_final( &state, mac ) != 0) {
mpw_free( mac, crypto_auth_hmacsha256_BYTES );
mpw_free( &mac, crypto_auth_hmacsha256_BYTES );
return NULL;
}
#else
@@ -228,7 +267,7 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, const size_t bufSize) {
#if HAS_SODIUM
#if MPW_SODIUM
if (!key || keySize < crypto_stream_KEYBYTES)
return NULL;
@@ -242,7 +281,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
if (encrypt) {
uint8_t *const cipherBuf = malloc( bufSize );
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
mpw_free( cipherBuf, bufSize );
mpw_free( &cipherBuf, bufSize );
return NULL;
}
return cipherBuf;
@@ -250,7 +289,7 @@ static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t key
else {
uint8_t *const plainBuf = malloc( bufSize );
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
mpw_free( plainBuf, bufSize );
mpw_free( &plainBuf, bufSize );
return NULL;
}
for (size_t c = 0; c < bufSize; ++c)
@@ -274,15 +313,44 @@ uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const u
return mpw_aes( false, key, keySize, cipherBuf, bufSize );
}
#if UNUSED
const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor, uint8_t digits, uint8_t truncationOffset) {
// Hash the moving factor with the key.
uint8_t counter[8];
mpw_uint64( movingFactor, counter );
uint8_t hash[20];
hmac_sha1( key, keySize, counter, sizeof( counter ), hash );
// Determine the offset to select OTP bytes from.
int offset;
if ((truncationOffset >= 0) && (truncationOffset < (sizeof( hash ) - 4)))
offset = truncationOffset;
else
offset = hash[sizeof( hash ) - 1] & 0xf;
// Select four bytes from the truncation offset.
uint32_t otp = 0U
| ((hash[offset + 0] & 0x7f) << 24)
| ((hash[offset + 1] & 0xff) << 16)
| ((hash[offset + 2] & 0xff) << 8)
| ((hash[offset + 3] & 0xff) << 0);
// Render the OTP as `digits` decimal digits.
otp %= (int)pow(10, digits);
return strdup( mpw_str( "%0*d", digits, otp ) );
}
#endif
MPKeyID mpw_id_buf(const void *buf, size_t length) {
if (!buf)
return "<unset>";
#if HAS_CPERCIVA
#if MPW_CPERCIVA
uint8_t hash[32];
SHA256_Buf( buf, length, hash );
#elif HAS_SODIUM
#elif MPW_SODIUM
uint8_t hash[crypto_hash_sha256_BYTES];
crypto_hash_sha256( hash, buf, length );
#else
@@ -305,24 +373,50 @@ bool mpw_id_buf_equals(const char *id1, const char *id2) {
return true;
}
static char *str_str;
const char *mpw_str(const char *format, ...) {
va_list args;
va_start( args, format );
vasprintf( &str_str, format, args );
const char *str_str = mpw_vstr( format, args );
va_end( args );
return str_str;
}
static char **mpw_hex_buf;
static unsigned int mpw_hex_buf_i;
const char *mpw_vstr(const char *format, va_list args) {
// TODO: We should find a way to get rid of this shared storage medium.
// TODO: Not thread-safe
static char *str_str;
static size_t str_str_max;
if (!str_str && !(str_str = calloc( str_str_max = 1, sizeof( char ) )))
return NULL;
do {
va_list args_attempt;
va_copy( args_attempt, args );
size_t len = (size_t)vsnprintf( str_str, str_str_max, format, args_attempt );
va_end( args_attempt );
if ((int)len < 0)
return NULL;
if (len < str_str_max)
break;
if (!mpw_realloc( &str_str, &str_str_max, len - str_str_max + 1 ))
return NULL;
} while (true);
return str_str;
}
const char *mpw_hex(const void *buf, size_t length) {
// FIXME: Not thread-safe
// TODO: We should find a way to get rid of this shared storage medium.
// TODO: Not thread-safe
static char **mpw_hex_buf;
static unsigned int mpw_hex_buf_i;
if (!mpw_hex_buf)
mpw_hex_buf = calloc( 10, sizeof( char * ) );
mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10;
@@ -336,34 +430,60 @@ const char *mpw_hex(const void *buf, size_t length) {
const char *mpw_hex_l(uint32_t number) {
return mpw_hex( &number, sizeof( number ) );
uint8_t buf[4 /* 32 / 8 */];
buf[0] = (uint8_t)((number >> 24) & UINT8_MAX);
buf[1] = (uint8_t)((number >> 16) & UINT8_MAX);
buf[2] = (uint8_t)((number >> 8L) & UINT8_MAX);
buf[3] = (uint8_t)((number >> 0L) & UINT8_MAX);
return mpw_hex( &buf, sizeof( buf ) );
}
#ifdef COLOR
static int putvari;
static char *putvarc = NULL;
static int termsetup;
static int initputvar() {
if (!isatty(STDERR_FILENO))
return 0;
if (putvarc)
free( putvarc );
#if MPW_COLOR
static char *str_tputs;
static int str_tputs_cursor;
static const int str_tputs_max = 256;
static bool mpw_setupterm() {
if (!isatty( STDERR_FILENO ))
return false;
static bool termsetup;
if (!termsetup) {
int status;
if (! (termsetup = (setupterm( NULL, STDERR_FILENO, &status ) == 0 && status == 1))) {
wrn( "Terminal doesn't support color (setupterm errno %d).\n", status );
return 0;
int errret;
if (!(termsetup = (setupterm( NULL, STDERR_FILENO, &errret ) == OK))) {
wrn( "Terminal doesn't support color (setupterm errret %d).\n", errret );
return false;
}
}
putvarc=(char *)calloc(256, sizeof(char));
putvari=0;
return 1;
return true;
}
static int putvar(int c) {
putvarc[putvari++]=c;
return 0;
static int mpw_tputc(int c) {
if (++str_tputs_cursor < str_tputs_max) {
str_tputs[str_tputs_cursor] = (char)c;
return OK;
}
return ERR;
}
static char *mpw_tputs(const char *str, int affcnt) {
if (str_tputs)
mpw_free( &str_tputs, str_tputs_max );
str_tputs = calloc( str_tputs_max, sizeof( char ) );
str_tputs_cursor = -1;
char *result = tputs( str, affcnt, mpw_tputc ) == ERR? NULL: strndup( str_tputs, str_tputs_max );
if (str_tputs)
mpw_free( &str_tputs, str_tputs_max );
return result;
}
#endif
const char *mpw_identicon(const char *fullName, const char *masterPassword) {
@@ -377,23 +497,20 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};
const uint8_t *identiconSeed = mpw_hash_hmac_sha256( (const uint8_t *)masterPassword, strlen( masterPassword ),
(const uint8_t *)fullName,
strlen( fullName ) );
const uint8_t *identiconSeed = mpw_hash_hmac_sha256(
(const uint8_t *)masterPassword, strlen( masterPassword ),
(const uint8_t *)fullName, strlen( fullName ) );
if (!identiconSeed)
return NULL;
char *colorString, *resetString;
#ifdef COLOR
if (initputvar()) {
#ifdef MPW_COLOR
if (mpw_setupterm()) {
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
tputs(tparm(tgetstr("AF", NULL), colorIdentifier), 1, putvar);
colorString = calloc(strlen(putvarc) + 1, sizeof(char));
strcpy(colorString, putvarc);
tputs(tgetstr("me", NULL), 1, putvar);
resetString = calloc(strlen(putvarc) + 1, sizeof(char));
strcpy(resetString, putvarc);
} else
colorString = mpw_tputs( tparm( tgetstr( "AF", NULL ), colorIdentifier ), 1 );
resetString = mpw_tputs( tgetstr( "me", NULL ), 1 );
}
else
#endif
{
colorString = calloc( 1, sizeof( char ) );
@@ -409,9 +526,8 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
resetString );
mpw_free( identiconSeed, 32 );
free( colorString );
free( resetString );
mpw_free( &identiconSeed, 32 );
mpw_free_strings( &colorString, &resetString, NULL );
return identicon;
}

View File

@@ -31,42 +31,42 @@ extern int mpw_verbosity;
#define trc_level 3
/** Logging internal state. */
#define trc(...) ({ \
if (mpw_verbosity >= 3) \
if (mpw_verbosity >= trc_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef dbg
#define dbg_level 2
/** Logging state and events interesting when investigating issues. */
#define dbg(...) ({ \
if (mpw_verbosity >= 2) \
if (mpw_verbosity >= dbg_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef inf
#define inf_level 1
/** User messages. */
#define inf(...) ({ \
if (mpw_verbosity >= 1) \
if (mpw_verbosity >= inf_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef wrn
#define wrn_level 0
/** Recoverable issues and user suggestions. */
#define wrn(...) ({ \
if (mpw_verbosity >= 0) \
if (mpw_verbosity >= wrn_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef err
#define err_level -1
/** Unrecoverable issues. */
#define err(...) ({ \
if (mpw_verbosity >= -1) \
if (mpw_verbosity >= err_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef ftl
#define ftl_level -2
/** Issues that lead to abortion. */
#define ftl(...) ({ \
if (mpw_verbosity >= -2) \
if (mpw_verbosity >= ftl_level) \
fprintf( stderr, __VA_ARGS__ ); })
#endif
@@ -85,6 +85,9 @@ extern int mpw_verbosity;
#ifndef ERR
#define ERR -1
#endif
#ifndef OK
#define OK 0
#endif
#ifndef stringify
#define stringify(s) #s
#endif
@@ -94,6 +97,11 @@ extern int mpw_verbosity;
//// Buffers and memory.
/** Write a number to a byte buffer using mpw's endianness (big/network endian). */
void mpw_uint16(const uint16_t number, uint8_t buf[2]);
void mpw_uint32(const uint32_t number, uint8_t buf[4]);
void mpw_uint64(const uint64_t number, uint8_t buf[8]);
/** Allocate a new array of _type, assign its element count to _count if not NULL and populate it with the varargs. */
#define mpw_alloc_array(_count, _type, ...) ({ \
_type stackElements[] = { __VA_ARGS__ }; \
@@ -106,18 +114,18 @@ extern int mpw_verbosity;
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
bool mpw_push_buf(
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize);
uint8_t **buffer, size_t *bufferSize, const void *pushBuffer, const size_t pushSize);
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
bool mpw_push_string(
uint8_t **buffer, size_t *const bufferSize, const char *pushString);
uint8_t **buffer, size_t *bufferSize, const char *pushString);
/** Push a string onto another string. reallocs the target string and appends the source string. */
bool mpw_string_push(
char **const string, const char *pushString);
char **string, const char *pushString);
bool mpw_string_pushf(
char **const string, const char *pushFormat, ...);
char **string, const char *pushFormat, ...);
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
bool mpw_push_int(
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
uint8_t **buffer, size_t *bufferSize, const uint32_t pushInt);
/** Reallocate the given buffer from the given size by adding the delta size.
* On success, the buffer size pointer will be updated to the buffer's new size
* and the buffer pointer may be updated to a new memory address.
@@ -128,14 +136,23 @@ bool mpw_push_int(
* @return true if successful, false if reallocation failed.
*/
#define mpw_realloc(buffer, bufferSize, deltaSize) \
__mpw_realloc( (void **)buffer, bufferSize, deltaSize )
bool __mpw_realloc(void **buffer, size_t *bufferSize, const size_t deltaSize);
/** Free a buffer after zero'ing its contents. */
bool mpw_free(
const void *buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents. */
bool mpw_free_string(
const char *string);
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); })
bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
#define mpw_free(buffer, bufferSize) \
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (const void **)_b, bufferSize ); })
bool __mpw_free(
const void **buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents, then set the reference to NULL. */
#define mpw_free_string(string) \
({ typeof(string) _s = string; const char *__s = *_s; (void)__s; __mpw_free_string( (const char **)_s ); })
bool __mpw_free_string(
const char **string);
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
#define mpw_free_strings(strings, ...) \
({ typeof(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (const char **)_s, __VA_ARGS__ ); })
bool __mpw_free_strings(
const char **strings, ...);
//// Cryptographic functions.
@@ -161,12 +178,19 @@ uint8_t const *mpw_aes_encrypt(
* @return A new bufSize allocated buffer containing the plainBuf. */
uint8_t const *mpw_aes_decrypt(
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize);
/** Calculate an OTP using RFC-4226.
* @return A newly allocated string containing exactly `digits` decimal OTP digits. */
#if UNUSED
const char *mpw_hotp(
const uint8_t *key, size_t keySize, uint64_t movingFactor, uint8_t digits, uint8_t truncationOffset);
#endif
//// Visualizers.
/** Compose a formatted string.
* @return A C-string in a reused buffer, do not free or store it. */
const char *mpw_str(const char *format, ...);
const char *mpw_vstr(const char *format, va_list args);
/** Encode a buffer as a string of hexadecimal characters.
* @return A C-string in a reused buffer, do not free or store it. */
const char *mpw_hex(const void *buf, size_t length);

View File

@@ -125,7 +125,6 @@
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD384B1711E29700CF925C /* icon_thumbs-up@2x.png */; };
DA25C600197DBF260046CDCF /* icon_trash.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38501711E29700CF925C /* icon_trash.png */; };
DA25C601197DBF260046CDCF /* icon_trash@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD38511711E29700CF925C /* icon_trash@2x.png */; };
DA25C6B41980D3C50046CDCF /* openssl in Headers */ = {isa = PBXBuildFile; fileRef = DA25C6B31980D3C10046CDCF /* openssl */; settings = {ATTRIBUTES = (Public, ); }; };
DA29992F19C86F5700AF7DF1 /* thumb_generated_login@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA29992D19C86F5700AF7DF1 /* thumb_generated_login@2x.png */; };
DA29993019C86F5700AF7DF1 /* thumb_generated_login.png in Resources */ = {isa = PBXBuildFile; fileRef = DA29992E19C86F5700AF7DF1 /* thumb_generated_login.png */; };
DA29993219C9132F00AF7DF1 /* thumb_generated_login@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA29993119C9132F00AF7DF1 /* thumb_generated_login@3x.png */; };
@@ -176,6 +175,7 @@
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */; };
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
@@ -251,6 +251,9 @@
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 */; };
DAB7AE5D1F3D752900C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE5C1F3D752900C856B1 /* libjson-c.a */; };
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE761F3D755B00C856B1 /* libjson-c.a */; };
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.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 */; };
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
@@ -403,12 +406,8 @@
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45F415039823003ABA7C /* PearlStringUtils.h */; };
DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45F515039823003ABA7C /* PearlStringUtils.m */; };
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */; };
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */; };
DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */; };
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460015039823003ABA7C /* PearlKeyChain.h */; };
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460115039823003ABA7C /* PearlKeyChain.m */; };
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460215039823003ABA7C /* PearlRSAKey.h */; };
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460315039823003ABA7C /* PearlRSAKey.m */; };
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */; };
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460915039823003ABA7C /* Pearl-UIKit.h */; };
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460A15039823003ABA7C /* PearlAlert.h */; };
@@ -419,10 +418,6 @@
DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460F15039823003ABA7C /* PearlBoxView.m */; };
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461015039823003ABA7C /* PearlGradientView.h */; };
DAFE4A4515039824003ABA7C /* PearlGradientView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461115039823003ABA7C /* PearlGradientView.m */; };
DAFE4A4615039824003ABA7C /* PearlLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461215039823003ABA7C /* PearlLayout.h */; };
DAFE4A4715039824003ABA7C /* PearlLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461315039823003ABA7C /* PearlLayout.m */; };
DAFE4A4815039824003ABA7C /* PearlLayoutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461415039823003ABA7C /* PearlLayoutView.h */; };
DAFE4A4915039824003ABA7C /* PearlLayoutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461515039823003ABA7C /* PearlLayoutView.m */; };
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461615039823003ABA7C /* PearlMessageView.h */; };
DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461715039823003ABA7C /* PearlMessageView.m */; };
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461815039823003ABA7C /* PearlRootViewController.h */; };
@@ -452,6 +447,23 @@
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE4A63150399FF003ABA93 /* NSDateFormatter+RFC3339.h */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
DAB7AE4D1F3D618700C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DAB7AE471F3D468300C856B1;
remoteInfo = "libsodium-ios";
};
DAB7AE4F1F3D618700C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DAB7AE3D1F3D464A00C856B1;
remoteInfo = "libjson-c";
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
DA32D01E19D111C6004F3F0E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -742,7 +754,6 @@
DA250A14195665A100AC23F1 /* UITableView+PearlReloadItems.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+PearlReloadItems.h"; sourceTree = "<group>"; };
DA250A15195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionReusableView+PearlDequeue.m"; sourceTree = "<group>"; };
DA250A16195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionReusableView+PearlDequeue.h"; sourceTree = "<group>"; };
DA25C6B31980D3C10046CDCF /* openssl */ = {isa = PBXFileReference; lastKnownFileType = folder; path = openssl; sourceTree = "<group>"; };
DA29992D19C86F5700AF7DF1 /* thumb_generated_login@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_login@2x.png"; sourceTree = "<group>"; };
DA29992E19C86F5700AF7DF1 /* thumb_generated_login.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = thumb_generated_login.png; sourceTree = "<group>"; };
DA29993119C9132F00AF7DF1 /* thumb_generated_login@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "thumb_generated_login@3x.png"; sourceTree = "<group>"; };
@@ -782,6 +793,8 @@
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
DA3B844D190FC5DF00246EEA /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = ../../../External/iOS/Crashlytics.framework; sourceTree = "<group>"; };
DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Regular.otf"; sourceTree = "<group>"; };
DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
DA45711C1F572F1E00D54152 /* PearlCryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlCryptUtils.h; sourceTree = "<group>"; };
DA5A09DD171A70E4005284AB /* play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = play.png; sourceTree = "<group>"; };
DA5A09DE171A70E4005284AB /* play@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "play@2x.png"; sourceTree = "<group>"; };
DA5A09E8171BB0F7005284AB /* unlocked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unlocked.png; sourceTree = "<group>"; };
@@ -803,7 +816,6 @@
DA67460C18DE7F0C00DFE240 /* Exo2.0-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Bold.otf"; sourceTree = "<group>"; };
DA70EC7F1811B13C00F65DB2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
DA771FE41E6E1595004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
DA7F2C5E1C48B70D00404A26 /* libopensslcrypto-ios-sim.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios-sim.a"; sourceTree = "<group>"; };
DA854C8118D4CFBF00106317 /* avatar-add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add@2x.png"; sourceTree = "<group>"; };
DA854C8218D4CFBF00106317 /* avatar-add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-add.png"; sourceTree = "<group>"; };
DA92614C1BE1A57500369DE5 /* MPAppDelegate_InApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAppDelegate_InApp.h; sourceTree = "<group>"; };
@@ -818,16 +830,16 @@
DAA1411D1922FF020032B392 /* PearlTween.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlTween.h; sourceTree = "<group>"; };
DAA1411F1922FF020032B392 /* map-macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "map-macro.h"; sourceTree = "<group>"; };
DAA1757D19D86BE70044227B /* libAttributedMarkdown.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAttributedMarkdown.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAA175B119D86C620044227B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
DAA175B119D86C620044227B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
DAA175B619D86C620044227B /* markdown_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markdown_lib.h; sourceTree = "<group>"; };
DAA175B719D86C620044227B /* markdown_lib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_lib.m; sourceTree = "<group>"; };
DAA175B819D86C620044227B /* markdown_output.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_output.m; sourceTree = "<group>"; };
DAA175B919D86C620044227B /* markdown_parser.leg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = markdown_parser.leg; sourceTree = "<group>"; };
DAA175B919D86C620044227B /* markdown_parser.leg */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = markdown_parser.leg; sourceTree = "<group>"; };
DAA175BA19D86C620044227B /* markdown_parser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = markdown_parser.m; sourceTree = "<group>"; };
DAA175BB19D86C620044227B /* markdown_peg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = markdown_peg.h; sourceTree = "<group>"; };
DAA175EB19D86C620044227B /* parsing_functions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = parsing_functions.m; sourceTree = "<group>"; };
DAA175EC19D86C620044227B /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = "<group>"; };
DAA175ED19D86C620044227B /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = "<group>"; };
DAA175ED19D86C620044227B /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = "<group>"; };
DAA175EE19D86C620044227B /* README_PEG-MARKDWON.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "README_PEG-MARKDWON.markdown"; sourceTree = "<group>"; };
DAA175EF19D86C620044227B /* utility_functions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utility_functions.m; sourceTree = "<group>"; };
DAA1761C19D86E800044227B /* attributed-markdown.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "attributed-markdown.pch"; sourceTree = "<group>"; };
@@ -862,6 +874,30 @@
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; };
DAB7AE5C1F3D752900C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-ios/lib/libjson-c.a"; sourceTree = "<group>"; };
DAB7AE611F3D755B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
DAB7AE621F3D755B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
DAB7AE631F3D755B00C856B1 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
DAB7AE641F3D755B00C856B1 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; };
DAB7AE651F3D755B00C856B1 /* json_c_version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_c_version.h; sourceTree = "<group>"; };
DAB7AE661F3D755B00C856B1 /* json_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_config.h; sourceTree = "<group>"; };
DAB7AE671F3D755B00C856B1 /* json_inttypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_inttypes.h; sourceTree = "<group>"; };
DAB7AE681F3D755B00C856B1 /* json_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object.h; sourceTree = "<group>"; };
DAB7AE691F3D755B00C856B1 /* json_object_iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object_iterator.h; sourceTree = "<group>"; };
DAB7AE6A1F3D755B00C856B1 /* json_object_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object_private.h; sourceTree = "<group>"; };
DAB7AE6B1F3D755B00C856B1 /* json_pointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_pointer.h; sourceTree = "<group>"; };
DAB7AE6C1F3D755B00C856B1 /* json_tokener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_tokener.h; sourceTree = "<group>"; };
DAB7AE6D1F3D755B00C856B1 /* json_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_util.h; sourceTree = "<group>"; };
DAB7AE6E1F3D755B00C856B1 /* json_visit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_visit.h; sourceTree = "<group>"; };
DAB7AE6F1F3D755B00C856B1 /* linkhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linkhash.h; sourceTree = "<group>"; };
DAB7AE701F3D755B00C856B1 /* math_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = math_compat.h; sourceTree = "<group>"; };
DAB7AE711F3D755B00C856B1 /* printbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = printbuf.h; sourceTree = "<group>"; };
DAB7AE721F3D755B00C856B1 /* random_seed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = random_seed.h; sourceTree = "<group>"; };
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.h; sourceTree = "<group>"; };
DAB7AE741F3D755B00C856B1 /* vasprintf_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vasprintf_compat.h; sourceTree = "<group>"; };
DAB7AE761F3D755B00C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libjson-c.a"; sourceTree = "<group>"; };
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; };
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; };
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>"; };
DABD36101711E29400CF925C /* ui_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ui_background@2x.png"; sourceTree = "<group>"; };
@@ -1475,7 +1511,7 @@
DABD38C11711E29700CF925C /* tip_location_teal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_teal@2x.png"; sourceTree = "<group>"; };
DABD38C21711E29700CF925C /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = "<group>"; };
DABD38C31711E29700CF925C /* tip_location_wood@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_wood@2x.png"; sourceTree = "<group>"; };
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jquery-1.6.1.min.js"; sourceTree = "<group>"; };
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = sourcecode.javascript; path = "jquery-1.6.1.min.js"; sourceTree = "<group>"; };
DABD38C91711E29700CF925C /* keypad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = keypad.png; sourceTree = "<group>"; };
DABD38CA1711E29700CF925C /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
DABD38CB1711E29700CF925C /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
@@ -1514,7 +1550,7 @@
DABD3BF01711E2DC00CF925C /* MPiOSConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPiOSConfig.h; sourceTree = "<group>"; };
DABD3BF11711E2DC00CF925C /* MPiOSConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPiOSConfig.m; sourceTree = "<group>"; };
DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MasterPassword-Info.plist"; sourceTree = "<group>"; };
DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
DABD3BF81711E2DC00CF925C /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
DABD3BF91711E2DC00CF925C /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
DABD3BFB1711E2DC00CF925C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DABD3BFC1711E2DC00CF925C /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -1528,7 +1564,7 @@
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Pearl-Prefix.pch"; path = "../../Source/Pearl/Pearl-Prefix.pch"; sourceTree = "<group>"; };
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
DACA29B51705E2DE002C6C22 /* UIColor+Expanded.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+Expanded.h"; sourceTree = "<group>"; };
@@ -1545,7 +1581,6 @@
DAE1EF2317E942DE00BC0086 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
DAE2726119CE9CB3007C5262 /* UITableViewCell+PearlDeque.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewCell+PearlDeque.m"; sourceTree = "<group>"; };
DAE2726219CE9CB3007C5262 /* UITableViewCell+PearlDeque.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewCell+PearlDeque.h"; sourceTree = "<group>"; };
DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-ios.a"; sourceTree = "<group>"; };
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Touches.m"; sourceTree = "<group>"; };
DAEC85B218E3DD9A007FC0DF /* PearlUINavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUINavigationBar.m; sourceTree = "<group>"; };
@@ -1584,16 +1619,12 @@
DAFE45F315039823003ABA7C /* PearlStrings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStrings.m; sourceTree = "<group>"; };
DAFE45F415039823003ABA7C /* PearlStringUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlStringUtils.h; sourceTree = "<group>"; };
DAFE45F515039823003ABA7C /* PearlStringUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStringUtils.m; sourceTree = "<group>"; };
DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = "<group>"; };
DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; fileEncoding = 2483028224; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = "<group>"; };
DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-Crypto.h"; sourceTree = "<group>"; };
DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlCryptUtils.h; sourceTree = "<group>"; };
DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
DAFE460015039823003ABA7C /* PearlKeyChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlKeyChain.h; sourceTree = "<group>"; };
DAFE460115039823003ABA7C /* PearlKeyChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlKeyChain.m; sourceTree = "<group>"; };
DAFE460215039823003ABA7C /* PearlRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRSAKey.h; sourceTree = "<group>"; };
DAFE460315039823003ABA7C /* PearlRSAKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRSAKey.m; sourceTree = "<group>"; };
DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit-Dependencies.h"; sourceTree = "<group>"; };
DAFE460915039823003ABA7C /* Pearl-UIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit.h"; sourceTree = "<group>"; };
DAFE460A15039823003ABA7C /* PearlAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlAlert.h; sourceTree = "<group>"; };
@@ -1604,10 +1635,6 @@
DAFE460F15039823003ABA7C /* PearlBoxView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlBoxView.m; sourceTree = "<group>"; };
DAFE461015039823003ABA7C /* PearlGradientView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlGradientView.h; sourceTree = "<group>"; };
DAFE461115039823003ABA7C /* PearlGradientView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlGradientView.m; sourceTree = "<group>"; };
DAFE461215039823003ABA7C /* PearlLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLayout.h; sourceTree = "<group>"; };
DAFE461315039823003ABA7C /* PearlLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLayout.m; sourceTree = "<group>"; };
DAFE461415039823003ABA7C /* PearlLayoutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLayoutView.h; sourceTree = "<group>"; };
DAFE461515039823003ABA7C /* PearlLayoutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLayoutView.m; sourceTree = "<group>"; };
DAFE461615039823003ABA7C /* PearlMessageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlMessageView.h; sourceTree = "<group>"; };
DAFE461715039823003ABA7C /* PearlMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlMessageView.m; sourceTree = "<group>"; };
DAFE461815039823003ABA7C /* PearlRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRootViewController.h; sourceTree = "<group>"; };
@@ -1620,7 +1647,7 @@
DAFE461F15039823003ABA7C /* PearlUIUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIUtils.m; sourceTree = "<group>"; };
DAFE462015039823003ABA7C /* PearlValidatingTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlValidatingTextField.h; sourceTree = "<group>"; };
DAFE462115039823003ABA7C /* PearlValidatingTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlValidatingTextField.m; sourceTree = "<group>"; };
DAFE462415039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE462415039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE4A1115039824003ABA7C /* UIImage+PearlScaling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+PearlScaling.h"; sourceTree = "<group>"; };
DAFE4A1215039824003ABA7C /* UIImage+PearlScaling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+PearlScaling.m"; sourceTree = "<group>"; };
DAFE4A60150399FF003ABA7C /* PearlAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlAppDelegate.m; sourceTree = "<group>"; };
@@ -1649,9 +1676,11 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DAB7AE5D1F3D752900C856B1 /* libjson-c.a in Frameworks */,
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */,
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */,
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
@@ -1730,6 +1759,8 @@
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */,
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */,
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */,
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */,
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
@@ -2018,6 +2049,7 @@
DA5BFA47147E415C00F98B1E /* Frameworks */ = {
isa = PBXGroup;
children = (
DAB7AE5C1F3D752900C856B1 /* libjson-c.a */,
DA6701B716406A4100B61001 /* Accounts.framework */,
DA6701DF16406BB400B61001 /* AdSupport.framework */,
DA5BFA4E147E415C00F98B1E /* CoreData.framework */,
@@ -2042,24 +2074,6 @@
name = Frameworks;
sourceTree = "<group>";
};
DA5E5C6317248959003798D8 /* lib */ = {
isa = PBXGroup;
children = (
DA5E5C6417248959003798D8 /* include */,
DA7F2C5E1C48B70D00404A26 /* libopensslcrypto-ios-sim.a */,
DAE8E65119867AB500416A0F /* libopensslcrypto-ios.a */,
);
path = lib;
sourceTree = "<group>";
};
DA5E5C6417248959003798D8 /* include */ = {
isa = PBXGroup;
children = (
DA25C6B31980D3C10046CDCF /* openssl */,
);
path = include;
sourceTree = "<group>";
};
DAA141181922FED80032B392 /* iOS */ = {
isa = PBXGroup;
children = (
@@ -2097,6 +2111,59 @@
path = AttributedMarkdown;
sourceTree = "<group>";
};
DAB7AE5E1F3D755B00C856B1 /* libjson-c-ios */ = {
isa = PBXGroup;
children = (
DAB7AE5F1F3D755B00C856B1 /* include */,
DAB7AE751F3D755B00C856B1 /* lib */,
);
name = "libjson-c-ios";
path = "libjson-c/libjson-c-ios";
sourceTree = "<group>";
};
DAB7AE5F1F3D755B00C856B1 /* include */ = {
isa = PBXGroup;
children = (
DAB7AE601F3D755B00C856B1 /* json-c */,
);
path = include;
sourceTree = "<group>";
};
DAB7AE601F3D755B00C856B1 /* json-c */ = {
isa = PBXGroup;
children = (
DAB7AE611F3D755B00C856B1 /* arraylist.h */,
DAB7AE621F3D755B00C856B1 /* bits.h */,
DAB7AE631F3D755B00C856B1 /* debug.h */,
DAB7AE641F3D755B00C856B1 /* json.h */,
DAB7AE651F3D755B00C856B1 /* json_c_version.h */,
DAB7AE661F3D755B00C856B1 /* json_config.h */,
DAB7AE671F3D755B00C856B1 /* json_inttypes.h */,
DAB7AE681F3D755B00C856B1 /* json_object.h */,
DAB7AE691F3D755B00C856B1 /* json_object_iterator.h */,
DAB7AE6A1F3D755B00C856B1 /* json_object_private.h */,
DAB7AE6B1F3D755B00C856B1 /* json_pointer.h */,
DAB7AE6C1F3D755B00C856B1 /* json_tokener.h */,
DAB7AE6D1F3D755B00C856B1 /* json_util.h */,
DAB7AE6E1F3D755B00C856B1 /* json_visit.h */,
DAB7AE6F1F3D755B00C856B1 /* linkhash.h */,
DAB7AE701F3D755B00C856B1 /* math_compat.h */,
DAB7AE711F3D755B00C856B1 /* printbuf.h */,
DAB7AE721F3D755B00C856B1 /* random_seed.h */,
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */,
DAB7AE741F3D755B00C856B1 /* vasprintf_compat.h */,
);
path = "json-c";
sourceTree = "<group>";
};
DAB7AE751F3D755B00C856B1 /* lib */ = {
isa = PBXGroup;
children = (
DAB7AE761F3D755B00C856B1 /* libjson-c.a */,
);
path = lib;
sourceTree = "<group>";
};
DABD360D1711E29400CF925C /* Media */ = {
isa = PBXGroup;
children = (
@@ -2945,6 +3012,7 @@
DACA22121705DDC5002C6C22 /* External */ = {
isa = PBXGroup;
children = (
DAB7AE5E1F3D755B00C856B1 /* libjson-c-ios */,
DA0978D81E9A81EE00F0BFE8 /* libsodium-ios */,
DAA1759319D86C610044227B /* AttributedMarkdown */,
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */,
@@ -3092,15 +3160,12 @@
DAFE45FC15039823003ABA7C /* Pearl-Crypto */ = {
isa = PBXGroup;
children = (
DA5E5C6317248959003798D8 /* lib */,
DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */,
DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */,
DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */,
DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */,
DA45711C1F572F1E00D54152 /* PearlCryptUtils.h */,
DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */,
DAFE460015039823003ABA7C /* PearlKeyChain.h */,
DAFE460115039823003ABA7C /* PearlKeyChain.m */,
DAFE460215039823003ABA7C /* PearlRSAKey.h */,
DAFE460315039823003ABA7C /* PearlRSAKey.m */,
DAFE460615039823003ABA7C /* README */,
);
path = "Pearl-Crypto";
@@ -3128,10 +3193,6 @@
DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */,
DAFE461015039823003ABA7C /* PearlGradientView.h */,
DAFE461115039823003ABA7C /* PearlGradientView.m */,
DAFE461215039823003ABA7C /* PearlLayout.h */,
DAFE461315039823003ABA7C /* PearlLayout.m */,
DAFE461415039823003ABA7C /* PearlLayoutView.h */,
DAFE461515039823003ABA7C /* PearlLayoutView.m */,
DAFE461615039823003ABA7C /* PearlMessageView.h */,
DAFE461715039823003ABA7C /* PearlMessageView.m */,
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */,
@@ -3227,7 +3288,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
DA25C6B41980D3C50046CDCF /* openssl in Headers */,
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
@@ -3249,9 +3309,7 @@
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */,
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */,
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */,
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */,
@@ -3263,8 +3321,6 @@
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */,
DAFE4A4615039824003ABA7C /* PearlLayout.h in Headers */,
DAFE4A4815039824003ABA7C /* PearlLayoutView.h in Headers */,
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */,
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
@@ -3309,6 +3365,36 @@
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXLegacyTarget section */
DAB7AE3D1F3D464A00C856B1 /* libjson-c-ios */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = DAB7AE411F3D464A00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-ios" */;
buildPhases = (
);
buildToolPath = "Scripts/build_libjson-c-ios";
buildWorkingDirectory = "";
dependencies = (
);
name = "libjson-c-ios";
passBuildSettingsInEnvironment = 1;
productName = "libjson-c";
};
DAB7AE471F3D468300C856B1 /* libsodium-ios */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = DAB7AE481F3D468300C856B1 /* Build configuration list for PBXLegacyTarget "libsodium-ios" */;
buildPhases = (
);
buildToolPath = "Scripts/build_libsodium-ios";
dependencies = (
);
name = "libsodium-ios";
passBuildSettingsInEnvironment = 1;
productName = "libsodium-ios";
};
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
DA32D01F19D111C6004F3F0E /* KCOrderedAccessorFix */ = {
isa = PBXNativeTarget;
@@ -3332,7 +3418,6 @@
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
buildPhases = (
DA8D88E019DA412A00B189D0 /* Run Script: genassets */,
DA0E86A81E9BED2C00F4D60E /* Run Script: libsodium/dist-build/ios.sh */,
DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
@@ -3342,6 +3427,8 @@
buildRules = (
);
dependencies = (
DAB7AE4E1F3D618700C856B1 /* PBXTargetDependency */,
DAB7AE501F3D618700C856B1 /* PBXTargetDependency */,
);
name = MasterPassword;
productName = MasterPassword;
@@ -3403,6 +3490,7 @@
isa = PBXNativeTarget;
buildConfigurationList = DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */;
buildPhases = (
DAB7AE4C1F3D56AD00C856B1 /* ShellScript */,
DAC77CAB148291A600BCF976 /* Headers */,
DAC77CA9148291A600BCF976 /* Sources */,
DAC77CAA148291A600BCF976 /* Frameworks */,
@@ -3468,6 +3556,16 @@
CreatedOnToolsVersion = 6.0;
DevelopmentTeam = HL3Q45LX9N;
};
DAB7AE3D1F3D464A00C856B1 = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
};
DAB7AE471F3D468300C856B1 = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
};
DAC6325C1486805C0075AEA5 = {
DevelopmentTeam = HL3Q45LX9N;
};
@@ -3588,6 +3686,8 @@
DAFC5654172C573B00CB5CC5 /* InAppSettingsKit */,
DA32D01F19D111C6004F3F0E /* KCOrderedAccessorFix */,
DAA1757C19D86BE70044227B /* AttributedMarkdown */,
DAB7AE471F3D468300C856B1 /* libsodium-ios */,
DAB7AE3D1F3D464A00C856B1 /* libjson-c-ios */,
);
};
/* End PBXProject section */
@@ -3783,21 +3883,6 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
DA0E86A81E9BED2C00F4D60E /* Run Script: libsodium/dist-build/ios.sh */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script: libsodium/dist-build/ios.sh";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/sh -e";
shellScript = "cd External/libsodium\n[[ -d libsodium-ios ]] && exit\n\n# Xcode misinterpretes autogen.sh's stderr output as errors so we try to silence it.\n[[ -e configure ]] || { err=$(./autogen.sh 2>&1 >&3); } 3>&1 || { x=$?; echo >&2 \"$err\"; exit $x; }\n./dist-build/ios.sh";
showEnvVarsInLog = 0;
};
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -3828,6 +3913,19 @@
shellScript = "exec Scripts/genassets";
showEnvVarsInLog = 0;
};
DAB7AE4C1F3D56AD00C856B1 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "";
};
DAD3125D155288AA00A3F9ED /* Run Script: Fabric */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -3890,6 +3988,7 @@
DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */,
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */,
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */,
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */,
93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */,
DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
@@ -3904,6 +4003,7 @@
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */,
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
@@ -3964,18 +4064,14 @@
DAFE4A2B15039824003ABA7C /* PearlObjectUtils.m in Sources */,
DAFE4A2E15039824003ABA7C /* PearlStrings.m in Sources */,
DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */,
DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */,
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */,
DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */,
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */,
DAFE4A3F15039824003ABA7C /* PearlAlert.m in Sources */,
DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */,
DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */,
DAFE4A4515039824003ABA7C /* PearlGradientView.m in Sources */,
DAFE4A4715039824003ABA7C /* PearlLayout.m in Sources */,
DA250A19195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.m in Sources */,
DAFE4A4915039824003ABA7C /* PearlLayoutView.m in Sources */,
DAE2726319CE9CB3007C5262 /* UITableViewCell+PearlDeque.m in Sources */,
DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */,
DACE2F6519BA6A0A0010F92E /* PearlProfiler.m in Sources */,
@@ -4051,6 +4147,19 @@
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
DAB7AE4E1F3D618700C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DAB7AE471F3D468300C856B1 /* libsodium-ios */;
targetProxy = DAB7AE4D1F3D618700C856B1 /* PBXContainerItemProxy */;
};
DAB7AE501F3D618700C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DAB7AE3D1F3D464A00C856B1 /* libjson-c-ios */;
targetProxy = DAB7AE4F1F3D618700C856B1 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
DA0CC4F51EAB99BA009A8ED9 /* IASKLocalizable.strings */ = {
isa = PBXVariantGroup;
@@ -4174,6 +4283,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-ios/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/include\"",
"$(inherited)",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -4212,8 +4323,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
@@ -4356,6 +4471,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-ios/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/include\"",
"$(inherited)",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -4444,6 +4561,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-ios/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/include\"",
"$(inherited)",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -4480,8 +4599,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO;
TARGETED_DEVICE_FAMILY = 1;
@@ -4510,8 +4633,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-ios/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
@@ -4535,6 +4662,128 @@
};
name = Release;
};
DAB7AE3E1F3D464A00C856B1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DAB7AE3F1F3D464A00C856B1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DAB7AE401F3D464A00C856B1 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DAB7AE491F3D468300C856B1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DAB7AE4A1F3D468300C856B1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DAB7AE4B1F3D468300C856B1 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DAC632661486805C0075AEA5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -4650,6 +4899,26 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DAB7AE411F3D464A00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-ios" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DAB7AE3E1F3D464A00C856B1 /* Debug */,
DAB7AE3F1F3D464A00C856B1 /* Release */,
DAB7AE401F3D464A00C856B1 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DAB7AE481F3D468300C856B1 /* Build configuration list for PBXLegacyTarget "libsodium-ios" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DAB7AE491F3D468300C856B1 /* Debug */,
DAB7AE4A1F3D468300C856B1 /* Release */,
DAB7AE4B1F3D468300C856B1 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DAC632651486805C0075AEA5 /* Build configuration list for PBXNativeTarget "uicolor-utilities" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -27,7 +27,6 @@
DA0979681E9A834C00F0BFE8 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
DA0CC53E1EB57B69009A8ED9 /* Fabric.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA0CC53D1EB57B69009A8ED9 /* Fabric.plist */; };
DA0CC5591EB6AE45009A8ED9 /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA0CC54F1EB6AE45009A8ED9 /* MasterPassword.xcdatamodeld */; };
DA1000801998A4C6002B873F /* openssl in Headers */ = {isa = PBXBuildFile; fileRef = DAE8E65719867AF500416A0F /* openssl */; settings = {ATTRIBUTES = (Public, ); }; };
DA16B341170661DB000A0EAB /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B340170661DB000A0EAB /* Carbon.framework */; };
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
@@ -78,6 +77,7 @@
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711E1F572F3200D54152 /* PearlCryptUtils.m */; };
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
@@ -117,7 +117,6 @@
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
DA8ED896192906920099B726 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED892192906920099B726 /* PearlTween.h */; };
DA8ED897192906920099B726 /* map-macro.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8ED894192906920099B726 /* map-macro.h */; };
DA92614B1BE1A4EA00369DE5 /* libopensslcrypto-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE8E65319867ADA00416A0F /* libopensslcrypto-osx.a */; };
DA9261511BE1A86700369DE5 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA92614F1BE1A86700369DE5 /* SystemConfiguration.framework */; };
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; };
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
@@ -130,6 +129,10 @@
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; };
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
DAB7AE5A1F3D74E700C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; };
DAB7AE941F3D757B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE901F3D757B00C856B1 /* libjson-c.a */; };
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DACA26FE1705DF81002C6C22 /* logo-bare.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA241C1705DF7D002C6C22 /* logo-bare.png */; };
@@ -216,12 +219,8 @@
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45F415039823003ABA7C /* PearlStringUtils.h */; };
DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45F515039823003ABA7C /* PearlStringUtils.m */; };
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */; };
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */; };
DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */; };
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460015039823003ABA7C /* PearlKeyChain.h */; };
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460115039823003ABA7C /* PearlKeyChain.m */; };
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460215039823003ABA7C /* PearlRSAKey.h */; };
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460315039823003ABA7C /* PearlRSAKey.m */; };
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAFE45FA15039823003ABA7C /* Pearl.strings */; };
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */; };
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */; };
@@ -230,6 +229,48 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
DAB7AE341F3D423600C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DA5B0B611F3D416500B663F0;
remoteInfo = "libsodium-osx";
};
DAB7AE361F3D423D00C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DA5B0B611F3D416500B663F0;
remoteInfo = "libsodium-osx";
};
DAB7AE381F3D424200C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DA5B0B611F3D416500B663F0;
remoteInfo = "libsodium-osx";
};
DAB7AE3A1F3D424700C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DA5B0B611F3D416500B663F0;
remoteInfo = "libsodium-osx";
};
DAB7AE511F3D649400C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DAB7AE421F3D466D00C856B1;
remoteInfo = "libjson-c";
};
DAB7AE571F3D64A600C856B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
proxyType = 1;
remoteGlobalIDString = DAB7AE421F3D466D00C856B1;
remoteInfo = "libjson-c";
};
DABFA071176E3FDF00E83589 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */;
@@ -453,6 +494,11 @@
DA3B8454190FC89700246EEA /* MPFixable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFixable.m; sourceTree = "<group>"; };
DA3B8455190FC89700246EEA /* MPFixable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixable.h; sourceTree = "<group>"; };
DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Regular.otf"; sourceTree = "<group>"; };
DA456CA21F5307B700D54152 /* blf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blf.h; sourceTree = "<group>"; };
DA4571171F552C9500D54152 /* bcrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bcrypt.h; sourceTree = "<group>"; };
DA4571181F552C9500D54152 /* blowfish.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blowfish.h; sourceTree = "<group>"; };
DA45711E1F572F3200D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
DA45711F1F572F3200D54152 /* PearlCryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlCryptUtils.h; sourceTree = "<group>"; };
DA4DAE911A7D8117003E5423 /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; };
DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
DA4DAE931A7D8117003E5423 /* MPTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypes.m; sourceTree = "<group>"; };
@@ -488,7 +534,7 @@
DA5E5CB51724A667003798D8 /* MPMacConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPMacConfig.h; sourceTree = "<group>"; };
DA5E5CB61724A667003798D8 /* MPMacConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMacConfig.m; sourceTree = "<group>"; };
DA5E5CBA1724A667003798D8 /* MasterPassword-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MasterPassword-Info.plist"; sourceTree = "<group>"; };
DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
DA5E5CBF1724A667003798D8 /* MasterPassword.entitlements */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text.xml; path = MasterPassword.entitlements; sourceTree = "<group>"; };
DA5E5CC31724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DA5E5CC51724A667003798D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
DA5E5CC61724A667003798D8 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
@@ -929,6 +975,30 @@
DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKCOrderedAccessorFix.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAADCC6619FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSManagedObjectModel+KCOrderedAccessorFix.h"; sourceTree = "<group>"; };
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; sourceTree = "<group>"; };
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
DAB7AE591F3D74E700C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libjson-c.a"; path = "External/libjson-c/libjson-c-osx/lib/libjson-c.a"; sourceTree = "<group>"; };
DAB7AE7B1F3D757B00C856B1 /* arraylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arraylist.h; sourceTree = "<group>"; };
DAB7AE7C1F3D757B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
DAB7AE7D1F3D757B00C856B1 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
DAB7AE7E1F3D757B00C856B1 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; };
DAB7AE7F1F3D757B00C856B1 /* json_c_version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_c_version.h; sourceTree = "<group>"; };
DAB7AE801F3D757B00C856B1 /* json_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_config.h; sourceTree = "<group>"; };
DAB7AE811F3D757B00C856B1 /* json_inttypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_inttypes.h; sourceTree = "<group>"; };
DAB7AE821F3D757B00C856B1 /* json_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object.h; sourceTree = "<group>"; };
DAB7AE831F3D757B00C856B1 /* json_object_iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object_iterator.h; sourceTree = "<group>"; };
DAB7AE841F3D757B00C856B1 /* json_object_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_object_private.h; sourceTree = "<group>"; };
DAB7AE851F3D757B00C856B1 /* json_pointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_pointer.h; sourceTree = "<group>"; };
DAB7AE861F3D757B00C856B1 /* json_tokener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_tokener.h; sourceTree = "<group>"; };
DAB7AE871F3D757B00C856B1 /* json_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_util.h; sourceTree = "<group>"; };
DAB7AE881F3D757B00C856B1 /* json_visit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_visit.h; sourceTree = "<group>"; };
DAB7AE891F3D757B00C856B1 /* linkhash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linkhash.h; sourceTree = "<group>"; };
DAB7AE8A1F3D757B00C856B1 /* math_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = math_compat.h; sourceTree = "<group>"; };
DAB7AE8B1F3D757B00C856B1 /* printbuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = printbuf.h; sourceTree = "<group>"; };
DAB7AE8C1F3D757B00C856B1 /* random_seed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = random_seed.h; sourceTree = "<group>"; };
DAB7AE8D1F3D757B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.h; sourceTree = "<group>"; };
DAB7AE8E1F3D757B00C856B1 /* vasprintf_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vasprintf_compat.h; sourceTree = "<group>"; };
DAB7AE901F3D757B00C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libjson-c.a"; sourceTree = "<group>"; };
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
@@ -977,7 +1047,7 @@
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; };
DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-Black.otf"; sourceTree = "<group>"; };
DACA29711705E1A8002C6C22 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29721705E1A8002C6C22 /* dictionary.lst */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = dictionary.lst; sourceTree = "<group>"; };
DACA29771705E2BD002C6C22 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRSwizzle.h; sourceTree = "<group>"; };
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
DACBFCDB1C59B22E007EF90F /* NSMutableSet+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableSet+Pearl.h"; sourceTree = "<group>"; };
@@ -995,8 +1065,6 @@
DAD0C60019FD6034009CB08D /* icon.sketch */ = {isa = PBXFileReference; lastKnownFileType = file; path = icon.sketch; sourceTree = "<group>"; };
DAD9B5E1176299B9001835F9 /* MasterPassword-Mac-LoginHelper.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "MasterPassword-Mac-LoginHelper.xcodeproj"; path = "MasterPassword-Mac-LoginHelper/MasterPassword-Mac-LoginHelper.xcodeproj"; sourceTree = "<group>"; };
DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
DAE8E65319867ADA00416A0F /* libopensslcrypto-osx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopensslcrypto-osx.a"; sourceTree = "<group>"; };
DAE8E65719867AF500416A0F /* openssl */ = {isa = PBXFileReference; lastKnownFileType = folder; path = openssl; sourceTree = "<group>"; };
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
DAF4EF52190A828100023C90 /* Exo2.0-Thin.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Thin.otf"; sourceTree = "<group>"; };
DAF4EF53190A828100023C90 /* Exo2.0-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Exo2.0-Regular.otf"; sourceTree = "<group>"; };
@@ -1030,16 +1098,12 @@
DAFE45F315039823003ABA7C /* PearlStrings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStrings.m; sourceTree = "<group>"; };
DAFE45F415039823003ABA7C /* PearlStringUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlStringUtils.h; sourceTree = "<group>"; };
DAFE45F515039823003ABA7C /* PearlStringUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStringUtils.m; sourceTree = "<group>"; };
DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = "<group>"; };
DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; fileEncoding = 2483028224; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = "<group>"; };
DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-Crypto.h"; sourceTree = "<group>"; };
DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlCryptUtils.h; sourceTree = "<group>"; };
DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
DAFE460015039823003ABA7C /* PearlKeyChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlKeyChain.h; sourceTree = "<group>"; };
DAFE460115039823003ABA7C /* PearlKeyChain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlKeyChain.m; sourceTree = "<group>"; };
DAFE460215039823003ABA7C /* PearlRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRSAKey.h; sourceTree = "<group>"; };
DAFE460315039823003ABA7C /* PearlRSAKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRSAKey.m; sourceTree = "<group>"; };
DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PearlKVO.m"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlKVO.h"; sourceTree = "<group>"; };
DAFE4A63150399FF003ABA91 /* NSDateFormatter+RFC3339.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDateFormatter+RFC3339.m"; sourceTree = "<group>"; };
@@ -1051,6 +1115,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DAB7AE5A1F3D74E700C856B1 /* libjson-c.a in Frameworks */,
DA1C7AAF1F1A8F24009A3551 /* libsodium.a in Frameworks */,
DA1C7AB01F1A8F24009A3551 /* libxml2.tbd in Frameworks */,
);
@@ -1069,9 +1134,11 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DAB7AE5B1F3D750B00C856B1 /* libjson-c.a in Frameworks */,
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */,
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */,
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */,
DAB7AE941F3D757B00C856B1 /* libjson-c.a in Frameworks */,
DADD5DFA1EA173B0005E7D96 /* libsodium.a in Frameworks */,
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */,
DA9261511BE1A86700369DE5 /* SystemConfiguration.framework in Frameworks */,
@@ -1116,7 +1183,6 @@
DAADCC4B19FB000C00987B1D /* QuartzCore.framework in Frameworks */,
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */,
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */,
DA92614B1BE1A4EA00369DE5 /* libopensslcrypto-osx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1225,7 +1291,12 @@
DA1C7AB71F1A8F6E009A3551 /* cli */ = {
isa = PBXGroup;
children = (
DA4571171F552C9500D54152 /* bcrypt.h */,
DA456CA21F5307B700D54152 /* blf.h */,
DA4571181F552C9500D54152 /* blowfish.h */,
DA1C7AB81F1A8F6E009A3551 /* mpw-bench.c */,
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */,
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */,
DA1C7AB91F1A8F6E009A3551 /* mpw-cli.c */,
DA1C7ABA1F1A8F6E009A3551 /* mpw-tests-util.c */,
DA1C7ABB1F1A8F6E009A3551 /* mpw-tests-util.h */,
@@ -1284,6 +1355,7 @@
DA5BFA47147E415C00F98B1E /* Frameworks */ = {
isa = PBXGroup;
children = (
DAB7AE591F3D74E700C856B1 /* libjson-c.a */,
DA09745D1E99586600F0BFE8 /* libxml2.tbd */,
DA6701B716406A4100B61001 /* Accounts.framework */,
DA16B340170661DB000A0EAB /* Carbon.framework */,
@@ -1303,15 +1375,6 @@
name = Frameworks;
sourceTree = "<group>";
};
DA5E5C7917248AA1003798D8 /* lib */ = {
isa = PBXGroup;
children = (
DAEB938518AB0FFD000490CC /* include */,
DAE8E65319867ADA00416A0F /* libopensslcrypto-osx.a */,
);
path = lib;
sourceTree = "<group>";
};
DA5E5C961724A667003798D8 /* Source */ = {
isa = PBXGroup;
children = (
@@ -1865,6 +1928,59 @@
path = KCOrderedAccessorFix;
sourceTree = "<group>";
};
DAB7AE781F3D757B00C856B1 /* libjson-c-osx */ = {
isa = PBXGroup;
children = (
DAB7AE791F3D757B00C856B1 /* include */,
DAB7AE8F1F3D757B00C856B1 /* lib */,
);
name = "libjson-c-osx";
path = "libjson-c/libjson-c-osx";
sourceTree = "<group>";
};
DAB7AE791F3D757B00C856B1 /* include */ = {
isa = PBXGroup;
children = (
DAB7AE7A1F3D757B00C856B1 /* json-c */,
);
path = include;
sourceTree = "<group>";
};
DAB7AE7A1F3D757B00C856B1 /* json-c */ = {
isa = PBXGroup;
children = (
DAB7AE7B1F3D757B00C856B1 /* arraylist.h */,
DAB7AE7C1F3D757B00C856B1 /* bits.h */,
DAB7AE7D1F3D757B00C856B1 /* debug.h */,
DAB7AE7E1F3D757B00C856B1 /* json.h */,
DAB7AE7F1F3D757B00C856B1 /* json_c_version.h */,
DAB7AE801F3D757B00C856B1 /* json_config.h */,
DAB7AE811F3D757B00C856B1 /* json_inttypes.h */,
DAB7AE821F3D757B00C856B1 /* json_object.h */,
DAB7AE831F3D757B00C856B1 /* json_object_iterator.h */,
DAB7AE841F3D757B00C856B1 /* json_object_private.h */,
DAB7AE851F3D757B00C856B1 /* json_pointer.h */,
DAB7AE861F3D757B00C856B1 /* json_tokener.h */,
DAB7AE871F3D757B00C856B1 /* json_util.h */,
DAB7AE881F3D757B00C856B1 /* json_visit.h */,
DAB7AE891F3D757B00C856B1 /* linkhash.h */,
DAB7AE8A1F3D757B00C856B1 /* math_compat.h */,
DAB7AE8B1F3D757B00C856B1 /* printbuf.h */,
DAB7AE8C1F3D757B00C856B1 /* random_seed.h */,
DAB7AE8D1F3D757B00C856B1 /* strdup_compat.h */,
DAB7AE8E1F3D757B00C856B1 /* vasprintf_compat.h */,
);
path = "json-c";
sourceTree = "<group>";
};
DAB7AE8F1F3D757B00C856B1 /* lib */ = {
isa = PBXGroup;
children = (
DAB7AE901F3D757B00C856B1 /* libjson-c.a */,
);
path = lib;
sourceTree = "<group>";
};
DAC77CAF148291A600BCF976 /* Pearl */ = {
isa = PBXGroup;
children = (
@@ -1879,6 +1995,7 @@
DACA22121705DDC5002C6C22 /* External */ = {
isa = PBXGroup;
children = (
DAB7AE781F3D757B00C856B1 /* libjson-c-osx */,
DA0979181E9A824700F0BFE8 /* libsodium-osx */,
DACA29751705E2BD002C6C22 /* jrswizzle */,
DAADCC6819FB007F00987B1D /* KCOrderedAccessorFix */,
@@ -2027,14 +2144,6 @@
name = Products;
sourceTree = "<group>";
};
DAEB938518AB0FFD000490CC /* include */ = {
isa = PBXGroup;
children = (
DAE8E65719867AF500416A0F /* openssl */,
);
path = include;
sourceTree = "<group>";
};
DAFE45D715039823003ABA7C /* Pearl */ = {
isa = PBXGroup;
children = (
@@ -2114,15 +2223,12 @@
DAFE45FC15039823003ABA7C /* Pearl-Crypto */ = {
isa = PBXGroup;
children = (
DA5E5C7917248AA1003798D8 /* lib */,
DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */,
DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */,
DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */,
DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */,
DA45711F1F572F3200D54152 /* PearlCryptUtils.h */,
DA45711E1F572F3200D54152 /* PearlCryptUtils.m */,
DAFE460015039823003ABA7C /* PearlKeyChain.h */,
DAFE460115039823003ABA7C /* PearlKeyChain.m */,
DAFE460215039823003ABA7C /* PearlRSAKey.h */,
DAFE460315039823003ABA7C /* PearlRSAKey.m */,
DAFE460615039823003ABA7C /* README */,
);
path = "Pearl-Crypto";
@@ -2144,7 +2250,6 @@
buildActionMask = 2147483647;
files = (
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */,
DA1000801998A4C6002B873F /* openssl in Headers */,
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */,
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
@@ -2166,9 +2271,7 @@
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */,
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
DAFE4A3815039824003ABA7C /* PearlRSAKey.h in Headers */,
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
@@ -2185,6 +2288,37 @@
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXLegacyTarget section */
DA5B0B611F3D416500B663F0 /* libsodium-osx */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = DA5B0B621F3D416500B663F0 /* Build configuration list for PBXLegacyTarget "libsodium-osx" */;
buildPhases = (
);
buildToolPath = "Scripts/build_libsodium-osx";
buildWorkingDirectory = "";
dependencies = (
);
name = "libsodium-osx";
passBuildSettingsInEnvironment = 1;
productName = "libsodium-osx";
};
DAB7AE421F3D466D00C856B1 /* libjson-c-osx */ = {
isa = PBXLegacyTarget;
buildArgumentsString = "$(ACTION)";
buildConfigurationList = DAB7AE431F3D466D00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-osx" */;
buildPhases = (
);
buildToolPath = "Scripts/build_libjson-c-osx";
buildWorkingDirectory = "";
dependencies = (
);
name = "libjson-c-osx";
passBuildSettingsInEnvironment = 1;
productName = "libjson-c";
};
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
DA1C7AA61F1A8F24009A3551 /* mpw-cli */ = {
isa = PBXNativeTarget;
@@ -2197,6 +2331,8 @@
buildRules = (
);
dependencies = (
DAB7AE581F3D64A600C856B1 /* PBXTargetDependency */,
DAB7AE3B1F3D424700C856B1 /* PBXTargetDependency */,
);
name = "mpw-cli";
productName = "mpw-test";
@@ -2214,6 +2350,7 @@
buildRules = (
);
dependencies = (
DAB7AE391F3D424200C856B1 /* PBXTargetDependency */,
);
name = "mpw-bench";
productName = "mpw-test";
@@ -2225,7 +2362,6 @@
buildConfigurationList = DA5BFA6D147E415C00F98B1E /* Build configuration list for PBXNativeTarget "MasterPassword" */;
buildPhases = (
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */,
DA0E86A91E9BED9300F4D60E /* Run Script: libsodium/dist-build/osx.sh */,
DA5BFA40147E415C00F98B1E /* Sources */,
DA5BFA41147E415C00F98B1E /* Frameworks */,
DA5BFA42147E415C00F98B1E /* Resources */,
@@ -2236,6 +2372,8 @@
buildRules = (
);
dependencies = (
DAB7AE521F3D649400C856B1 /* PBXTargetDependency */,
DAB7AE351F3D423600C856B1 /* PBXTargetDependency */,
DABFA072176E3FDF00E83589 /* PBXTargetDependency */,
);
name = MasterPassword;
@@ -2254,6 +2392,7 @@
buildRules = (
);
dependencies = (
DAB7AE371F3D423D00C856B1 /* PBXTargetDependency */,
);
name = "mpw-test";
productName = "mpw-test";
@@ -2330,6 +2469,11 @@
DA1C7AC61F1A8FD8009A3551 = {
DevelopmentTeam = HL3Q45LX9N;
};
DA5B0B611F3D416500B663F0 = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
};
DA5BFA43147E415C00F98B1E = {
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
@@ -2347,6 +2491,11 @@
CreatedOnToolsVersion = 6.0.1;
DevelopmentTeam = HL3Q45LX9N;
};
DAB7AE421F3D466D00C856B1 = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = HL3Q45LX9N;
ProvisioningStyle = Automatic;
};
DAC6326B148680650075AEA5 = {
DevelopmentTeam = HL3Q45LX9N;
};
@@ -2381,6 +2530,8 @@
DA67743A1A474A03004F356A /* mpw-test */,
DA1C7AC61F1A8FD8009A3551 /* mpw-bench */,
DA1C7AA61F1A8F24009A3551 /* mpw-cli */,
DA5B0B611F3D416500B663F0 /* libsodium-osx */,
DAB7AE421F3D466D00C856B1 /* libjson-c-osx */,
);
};
/* End PBXProject section */
@@ -2468,21 +2619,6 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
DA0E86A91E9BED9300F4D60E /* Run Script: libsodium/dist-build/osx.sh */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script: libsodium/dist-build/osx.sh";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/bin/sh -e";
shellScript = "cd External/libsodium\nif ! [[ -d libsodium-osx ]]; then\n # Xcode misinterpretes autogen.sh's stderr output as errors so we try to silence it.\n [[ -e configure ]] || { err=$(./autogen.sh 2>&1 >&3); } 3>&1 || { x=$?; echo >&2 \"$err\"; exit $x; }\n./dist-build/osx.sh\nfi\n\n# Xcode incorrectly links the dynamic libraries if they're present instead of linking the .a.\nrm -f libsodium-osx/lib/*.dylib";
showEnvVarsInLog = 0;
};
DA4EF9CB19FD4B600032ECB5 /* Run Script: genassets */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -2537,6 +2673,7 @@
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */,
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
DA5B0B3D1F36467900B663F0 /* base64.c in Sources */,
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */,
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */,
@@ -2569,6 +2706,7 @@
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */,
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */,
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */,
DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
DA6774311A4746AF004F356A /* mpw-util.c in Sources */,
@@ -2654,10 +2792,8 @@
DAFE4A2B15039824003ABA7C /* PearlObjectUtils.m in Sources */,
DAFE4A2E15039824003ABA7C /* PearlStrings.m in Sources */,
DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */,
DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */,
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */,
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */,
DA8ED895192906920099B726 /* PearlTween.m in Sources */,
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */,
DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */,
@@ -2677,6 +2813,36 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
DAB7AE351F3D423600C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DA5B0B611F3D416500B663F0 /* libsodium-osx */;
targetProxy = DAB7AE341F3D423600C856B1 /* PBXContainerItemProxy */;
};
DAB7AE371F3D423D00C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DA5B0B611F3D416500B663F0 /* libsodium-osx */;
targetProxy = DAB7AE361F3D423D00C856B1 /* PBXContainerItemProxy */;
};
DAB7AE391F3D424200C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DA5B0B611F3D416500B663F0 /* libsodium-osx */;
targetProxy = DAB7AE381F3D424200C856B1 /* PBXContainerItemProxy */;
};
DAB7AE3B1F3D424700C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DA5B0B611F3D416500B663F0 /* libsodium-osx */;
targetProxy = DAB7AE3A1F3D424700C856B1 /* PBXContainerItemProxy */;
};
DAB7AE521F3D649400C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DAB7AE421F3D466D00C856B1 /* libjson-c-osx */;
targetProxy = DAB7AE511F3D649400C856B1 /* PBXContainerItemProxy */;
};
DAB7AE581F3D64A600C856B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DAB7AE421F3D466D00C856B1 /* libjson-c-osx */;
targetProxy = DAB7AE571F3D64A600C856B1 /* PBXContainerItemProxy */;
};
DABFA072176E3FDF00E83589 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "MasterPassword-Mac-LoginHelper";
@@ -2791,6 +2957,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-osx/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/include\"",
"$(inherited)",
);
LD_DYLIB_INSTALL_NAME = "@rpath/$(EXECUTABLE_PATH)";
@@ -2828,8 +2996,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword.Mac;
SKIP_INSTALL = NO;
WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}";
@@ -2875,18 +3047,17 @@
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2",
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
};
name = Test;
@@ -2895,19 +3066,16 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
"-DMPW_JSON=1",
"-DMPW_COLOR=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2917,19 +3085,16 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
"-DMPW_JSON=1",
"-DMPW_COLOR=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2939,19 +3104,16 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
"-DMPW_JSON=1",
"-DMPW_COLOR=1",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2961,19 +3123,13 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2983,19 +3139,13 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -3005,24 +3155,77 @@
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)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DA5B0B631F3D416500B663F0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_DYNAMIC_NO_PIC = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DA5B0B641F3D416500B663F0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DA5B0B651F3D416500B663F0 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DA5BFA6B147E415C00F98B1E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -3097,6 +3300,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-osx/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/include\"",
"$(inherited)",
);
LD_DYLIB_INSTALL_NAME = "@rpath/$(EXECUTABLE_PATH)";
@@ -3188,6 +3393,8 @@
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"\"$(PROJECT_DIR)/External/libsodium/libsodium-osx/include\"",
"\"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/include\"",
"$(inherited)",
);
LD_DYLIB_INSTALL_NAME = "@rpath/$(EXECUTABLE_PATH)";
@@ -3225,8 +3432,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword.Mac;
SKIP_INSTALL = NO;
WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}";
@@ -3253,8 +3464,12 @@
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
"$(PROJECT_DIR)/External/libjson-c/libjson-c-osx/lib",
);
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
OTHER_CFLAGS = "-DHAS_SODIUM=1";
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword.Mac;
SKIP_INSTALL = NO;
WRAPPER_NAME = "Master Password.${WRAPPER_EXTENSION}";
@@ -3266,18 +3481,17 @@
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2",
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
};
name = Debug;
@@ -3287,18 +3501,17 @@
buildSettings = {
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2",
"$(inherited)",
/usr/include/libxml2,
/usr/local/include,
);
LIBRARY_SEARCH_PATHS = (
"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib",
/usr/local/lib,
"$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-osx/lib",
);
OTHER_CFLAGS = (
"-DHAS_CPERCIVA=0",
"-DHAS_SODIUM=1",
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
};
name = Release;
@@ -3319,6 +3532,65 @@
};
name = Release;
};
DAB7AE441F3D466D00C856B1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUGGING_SYMBOLS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_DYNAMIC_NO_PIC = NO;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
DAB7AE451F3D466D00C856B1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
DAB7AE461F3D466D00C856B1 /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_WARN_UNUSED_FUNCTION = YES;
OTHER_CFLAGS = "";
OTHER_LDFLAGS = "";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Test;
};
DAC63275148680650075AEA5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -3394,6 +3666,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DA5B0B621F3D416500B663F0 /* Build configuration list for PBXLegacyTarget "libsodium-osx" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA5B0B631F3D416500B663F0 /* Debug */,
DA5B0B641F3D416500B663F0 /* Release */,
DA5B0B651F3D416500B663F0 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword-macOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -3434,6 +3716,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DAB7AE431F3D466D00C856B1 /* Build configuration list for PBXLegacyTarget "libjson-c-osx" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DAB7AE441F3D466D00C856B1 /* Debug */,
DAB7AE451F3D466D00C856B1 /* Release */,
DAB7AE461F3D466D00C856B1 /* Test */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Test;
};
DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AC61F1A8FD8009A3551"
BuildableName = "mpw-bench"
BlueprintName = "mpw-bench"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AC61F1A8FD8009A3551"
BuildableName = "mpw-bench"
BlueprintName = "mpw-bench"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AC61F1A8FD8009A3551"
BuildableName = "mpw-bench"
BlueprintName = "mpw-bench"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AC61F1A8FD8009A3551"
BuildableName = "mpw-bench"
BlueprintName = "mpw-bench"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0830"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AA61F1A8F24009A3551"
BuildableName = "mpw-cli"
BlueprintName = "mpw-cli"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AA61F1A8F24009A3551"
BuildableName = "mpw-cli"
BlueprintName = "mpw-cli"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AA61F1A8F24009A3551"
BuildableName = "mpw-cli"
BlueprintName = "mpw-cli"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA1C7AA61F1A8F24009A3551"
BuildableName = "mpw-cli"
BlueprintName = "mpw-cli"
ReferencedContainer = "container:MasterPassword-macOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -11,6 +11,7 @@
"2FE140B36B7D26140DC8D5E5C639DC5900EFCF35" : 9223372036854775807,
"4DDCFFD91B41F00326AD14553BD66CFD366ABD91" : 9223372036854775807,
"3ED8592497DB6A564366943C9AAD5A46341B5076" : 9223372036854775807,
"B38C14663FCFBB7024902D2DB1D013964189DC3B" : 9223372036854775807,
"81A28796384A028E6C2D47C039DB8B3E5DD6D0FC" : 9223372036854775807,
"F788B28042EDBEF29EFE34687DA79A778C2CC260" : 0
},
@@ -23,6 +24,7 @@
"2FE140B36B7D26140DC8D5E5C639DC5900EFCF35" : "MasterPassword\/platform-darwin\/External\/uicolor-utilities\/",
"4DDCFFD91B41F00326AD14553BD66CFD366ABD91" : "MasterPassword\/platform-darwin\/External\/Pearl\/",
"3ED8592497DB6A564366943C9AAD5A46341B5076" : "MasterPassword\/platform-darwin\/External\/AttributedMarkdown\/",
"B38C14663FCFBB7024902D2DB1D013964189DC3B" : "MasterPassword\/platform-darwin\/External\/libjson-c\/",
"81A28796384A028E6C2D47C039DB8B3E5DD6D0FC" : "MasterPassword\/platform-darwin\/External\/libsodium\/",
"F788B28042EDBEF29EFE34687DA79A778C2CC260" : "MasterPassword\/"
},
@@ -70,6 +72,11 @@
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8A15A8EA0B3D0B497C4883425BC74DF995224BB3"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/json-c\/json-c.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "B38C14663FCFBB7024902D2DB1D013964189DC3B"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:Lyndir\/MasterPassword.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}/../External/libjson-c"
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
# Prepare
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
rm -rf "${prefix=$PWD/libjson-c-ios}"
mkdir -p "$prefix/lib" \
"${prefix_i386=$prefix/tmp/i386}" \
"${prefix_x86_64=$prefix/tmp/x86_64}" \
"${prefix_armv7=$prefix/tmp/armv7}" \
"${prefix_armv7s=$prefix/tmp/armv7s}" \
"${prefix_arm64=$prefix/tmp/arm64}"
# Targets
(
## ARCH: i386
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386"
make -j3 install
)
(
## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64"
make -j3 install
)
(
## ARCH: armv7
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7"
make -j3 install
)
(
## ARCH: armv7s
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s"
make -j3 install
)
(
## ARCH: arm64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64"
make -j3 install
)
# Merge Binaries
mv -f -- "$prefix_arm64/include" "$prefix/"
lipo -create \
"$prefix_i386/lib/libjson-c.a" \
"$prefix_x86_64/lib/libjson-c.a" \
"$prefix_armv7/lib/libjson-c.a" \
"$prefix_armv7s/lib/libjson-c.a" \
"$prefix_arm64/lib/libjson-c.a" \
-output "$prefix/lib/libjson-c.a"
# Cleanup
rm -rf -- "$prefix/tmp"
make -s really-clean

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}/../External/libjson-c"
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
# Prepare
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
rm -rf "${prefix=$PWD/libjson-c-osx}"
mkdir -p "$prefix"
# Targets
(
## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g $CFLAGS" # -flto
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s clean
./configure --disable-shared --prefix="$prefix"
make -j3 check
make -j3 install
)
# Cleanup
make -s really-clean

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}/../External/libsodium"
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
# Prepare
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
rm -rf "${prefix=$PWD/libsodium-ios}"
mkdir -p "$prefix/lib" \
"${prefix_i386=$prefix/tmp/i386}" \
"${prefix_x86_64=$prefix/tmp/x86_64}" \
"${prefix_armv7=$prefix/tmp/armv7}" \
"${prefix_armv7s=$prefix/tmp/armv7s}" \
"${prefix_arm64=$prefix/tmp/arm64}"
# Targets
(
## ARCH: i386
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386"
make -j3 install
)
(
## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64"
make -j3 install
)
(
## ARCH: armv7
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7"
make -j3 install
)
(
## ARCH: armv7s
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s"
make -j3 install
)
(
## ARCH: arm64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64"
make -j3 install
)
# Merge Binaries
mv -f -- "$prefix_arm64/include" "$prefix/"
lipo -create \
"$prefix_i386/lib/libsodium.a" \
"$prefix_x86_64/lib/libsodium.a" \
"$prefix_armv7/lib/libsodium.a" \
"$prefix_armv7s/lib/libsodium.a" \
"$prefix_arm64/lib/libsodium.a" \
-output "$prefix/lib/libsodium.a"
# Cleanup
rm -rf -- "$prefix/tmp"
make -s distclean

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}/../External/libsodium"
[[ -e "${prefix=$PWD/libsodium-osx}/lib/libsodium.a" ]] && exit
# Inspired by libsodium/dist-build/osx.sh
# Prepare
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
rm -rf "${prefix=$PWD/libsodium-osx}"
mkdir -p "$prefix"
# Targets
(
## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g -flto $CFLAGS"
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean
./configure --disable-shared --prefix="$prefix"
make -j3 check
make -j3 install
)
# Cleanup
make -s distclean

View File

@@ -52,49 +52,44 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (NSData *)keyIDForKey:(MPMasterKey)masterKey;
- (NSData *)keyDataForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword;
- (NSString *)nameOfType:(MPSiteType)type;
- (NSString *)shortNameOfType:(MPSiteType)type;
- (NSString *)classNameOfType:(MPSiteType)type;
- (Class)classOfType:(MPSiteType)type;
- (NSString *)nameOfType:(MPResultType)type;
- (NSString *)shortNameOfType:(MPResultType)type;
- (NSString *)classNameOfType:(MPResultType)type;
- (Class)classOfType:(MPResultType)type;
- (NSArray *)allTypes;
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType;
- (MPSiteType)defaultType;
- (MPSiteType)nextType:(MPSiteType)type;
- (MPSiteType)previousType:(MPSiteType)type;
- (NSArray *)allTypesStartingWith:(MPResultType)startingType;
- (MPResultType)defaultType;
- (MPResultType)nextType:(MPResultType)type;
- (MPResultType)previousType:(MPResultType)type;
- (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key;
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key;
- (NSString *)generateAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key;
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant context:(NSString *)context usingKey:(MPKey *)key;
- (NSString *)mpwLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key;
- (NSString *)mpwTemplateForSiteNamed:(NSString *)name ofType:(MPResultType)type
withCounter:(MPCounterValue)counter usingKey:(MPKey *)key;
- (NSString *)mpwAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key;
- (NSString *)mpwResultForSiteNamed:(NSString *)name ofType:(MPResultType)type parameter:(NSString *)parameter
withCounter:(MPCounterValue)counter variant:(MPKeyPurpose)purpose context:(NSString *)context usingKey:(MPKey *)key;
- (NSString *)storedLoginForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key;
- (NSString *)storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key;
- (BOOL)savePassword:(NSString *)clearPassword toSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (BOOL)savePassword:(NSString *)clearPassword toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)key;
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey;
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey
- (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)key
result:(void ( ^ )(NSString *result))resultBlock;
- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey
- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)key
result:(void ( ^ )(NSString *result))resultBlock;
- (void)importProtectedPassword:(NSString *)protectedPassword protectedByKey:(MPKey *)importKey
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (void)importClearTextPassword:(NSString *)clearPassword intoSite:(MPSiteEntity *)site
usingKey:(MPKey *)siteKey;
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey;
- (void)importPassword:(NSString *)protectedPassword protectedByKey:(MPKey *)importKey
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPSiteType)type byAttacker:(MPAttacker)attacker;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPResultType)type byAttacker:(MPAttacker)attacker;
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordString:(NSString *)password byAttacker:(MPAttacker)attacker;
@end

View File

@@ -133,7 +133,7 @@ static NSOperationQueue *_mpwQueue = nil;
keyData = [NSData dataWithBytes:masterKey length:MPMasterKeySize];
trc( @"User: %@, password: %@ derives to key ID: %@ (took %0.2fs)", //
fullName, masterPassword, [self keyIDForKey:masterKey], -[start timeIntervalSinceNow] );
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
}
}];
@@ -145,126 +145,135 @@ static NSOperationQueue *_mpwQueue = nil;
return [[NSData dataWithBytesNoCopy:(void *)masterKey length:MPMasterKeySize] hashWith:PearlHashSHA256];
}
- (NSString *)nameOfType:(MPSiteType)type {
- (NSString *)nameOfType:(MPResultType)type {
if (!type)
return nil;
switch (type) {
case MPSiteTypeGeneratedMaximum:
case MPResultTypeTemplateMaximum:
return @"Maximum Security Password";
case MPSiteTypeGeneratedLong:
case MPResultTypeTemplateLong:
return @"Long Password";
case MPSiteTypeGeneratedMedium:
case MPResultTypeTemplateMedium:
return @"Medium Password";
case MPSiteTypeGeneratedBasic:
case MPResultTypeTemplateBasic:
return @"Basic Password";
case MPSiteTypeGeneratedShort:
case MPResultTypeTemplateShort:
return @"Short Password";
case MPSiteTypeGeneratedPIN:
case MPResultTypeTemplatePIN:
return @"PIN";
case MPSiteTypeGeneratedName:
case MPResultTypeTemplateName:
return @"Name";
case MPSiteTypeGeneratedPhrase:
case MPResultTypeTemplatePhrase:
return @"Phrase";
case MPSiteTypeStoredPersonal:
case MPResultTypeStatefulPersonal:
return @"Personal Password";
case MPSiteTypeStoredDevicePrivate:
case MPResultTypeStatefulDevice:
return @"Device Private Password";
case MPResultTypeDeriveKey:
return @"Crypto Key";
}
Throw( @"Type not supported: %lu", (long)type );
}
- (NSString *)shortNameOfType:(MPSiteType)type {
- (NSString *)shortNameOfType:(MPResultType)type {
if (!type)
return nil;
switch (type) {
case MPSiteTypeGeneratedMaximum:
case MPResultTypeTemplateMaximum:
return @"Maximum";
case MPSiteTypeGeneratedLong:
case MPResultTypeTemplateLong:
return @"Long";
case MPSiteTypeGeneratedMedium:
case MPResultTypeTemplateMedium:
return @"Medium";
case MPSiteTypeGeneratedBasic:
case MPResultTypeTemplateBasic:
return @"Basic";
case MPSiteTypeGeneratedShort:
case MPResultTypeTemplateShort:
return @"Short";
case MPSiteTypeGeneratedPIN:
case MPResultTypeTemplatePIN:
return @"PIN";
case MPSiteTypeGeneratedName:
case MPResultTypeTemplateName:
return @"Name";
case MPSiteTypeGeneratedPhrase:
case MPResultTypeTemplatePhrase:
return @"Phrase";
case MPSiteTypeStoredPersonal:
case MPResultTypeStatefulPersonal:
return @"Personal";
case MPSiteTypeStoredDevicePrivate:
case MPResultTypeStatefulDevice:
return @"Device";
case MPResultTypeDeriveKey:
return @"Key";
}
Throw( @"Type not supported: %lu", (long)type );
}
- (NSString *)classNameOfType:(MPSiteType)type {
- (NSString *)classNameOfType:(MPResultType)type {
return NSStringFromClass( [self classOfType:type] );
}
- (Class)classOfType:(MPSiteType)type {
- (Class)classOfType:(MPResultType)type {
if (!type)
Throw( @"No type given." );
switch (type) {
case MPSiteTypeGeneratedMaximum:
case MPResultTypeTemplateMaximum:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedLong:
case MPResultTypeTemplateLong:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedMedium:
case MPResultTypeTemplateMedium:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedBasic:
case MPResultTypeTemplateBasic:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedShort:
case MPResultTypeTemplateShort:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedPIN:
case MPResultTypeTemplatePIN:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedName:
case MPResultTypeTemplateName:
return [MPGeneratedSiteEntity class];
case MPSiteTypeGeneratedPhrase:
case MPResultTypeTemplatePhrase:
return [MPGeneratedSiteEntity class];
case MPSiteTypeStoredPersonal:
case MPResultTypeStatefulPersonal:
return [MPStoredSiteEntity class];
case MPSiteTypeStoredDevicePrivate:
case MPResultTypeStatefulDevice:
return [MPStoredSiteEntity class];
case MPResultTypeDeriveKey:
break;
}
Throw( @"Type not supported: %lu", (long)type );
@@ -272,13 +281,13 @@ static NSOperationQueue *_mpwQueue = nil;
- (NSArray *)allTypes {
return [self allTypesStartingWith:MPSiteTypeGeneratedPhrase];
return [self allTypesStartingWith:MPResultTypeTemplatePhrase];
}
- (NSArray *)allTypesStartingWith:(MPSiteType)startingType {
- (NSArray *)allTypesStartingWith:(MPResultType)startingType {
NSMutableArray *allTypes = [[NSMutableArray alloc] initWithCapacity:8];
MPSiteType currentType = startingType;
MPResultType currentType = startingType;
do {
[allTypes addObject:@(currentType)];
} while ((currentType = [self nextType:currentType]) != startingType);
@@ -286,199 +295,173 @@ static NSOperationQueue *_mpwQueue = nil;
return allTypes;
}
- (MPSiteType)defaultType {
- (MPResultType)defaultType {
return MPSiteTypeGeneratedLong;
return MPResultTypeTemplateLong;
}
- (MPSiteType)nextType:(MPSiteType)type {
- (MPResultType)nextType:(MPResultType)type {
switch (type) {
case MPSiteTypeGeneratedPhrase:
return MPSiteTypeGeneratedName;
case MPSiteTypeGeneratedName:
return MPSiteTypeGeneratedMaximum;
case MPSiteTypeGeneratedMaximum:
return MPSiteTypeGeneratedLong;
case MPSiteTypeGeneratedLong:
return MPSiteTypeGeneratedMedium;
case MPSiteTypeGeneratedMedium:
return MPSiteTypeGeneratedBasic;
case MPSiteTypeGeneratedBasic:
return MPSiteTypeGeneratedShort;
case MPSiteTypeGeneratedShort:
return MPSiteTypeGeneratedPIN;
case MPSiteTypeGeneratedPIN:
return MPSiteTypeStoredPersonal;
case MPSiteTypeStoredPersonal:
return MPSiteTypeStoredDevicePrivate;
case MPSiteTypeStoredDevicePrivate:
return MPSiteTypeGeneratedPhrase;
case MPResultTypeTemplatePhrase:
return MPResultTypeTemplateName;
case MPResultTypeTemplateName:
return MPResultTypeTemplateMaximum;
case MPResultTypeTemplateMaximum:
return MPResultTypeTemplateLong;
case MPResultTypeTemplateLong:
return MPResultTypeTemplateMedium;
case MPResultTypeTemplateMedium:
return MPResultTypeTemplateBasic;
case MPResultTypeTemplateBasic:
return MPResultTypeTemplateShort;
case MPResultTypeTemplateShort:
return MPResultTypeTemplatePIN;
case MPResultTypeTemplatePIN:
return MPResultTypeStatefulPersonal;
case MPResultTypeStatefulPersonal:
return MPResultTypeStatefulDevice;
case MPResultTypeStatefulDevice:
return MPResultTypeTemplatePhrase;
case MPResultTypeDeriveKey:
break;
}
return [self defaultType];
}
- (MPSiteType)previousType:(MPSiteType)type {
- (MPResultType)previousType:(MPResultType)type {
MPSiteType previousType = type, nextType = type;
MPResultType previousType = type, nextType = type;
while ((nextType = [self nextType:nextType]) != type)
previousType = nextType;
return previousType;
}
- (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key {
- (NSString *)mpwLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:MPSiteTypeGeneratedName withCounter:1
variant:MPKeyPurposeIdentification context:nil usingKey:key];
return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplateName parameter:nil withCounter:MPCounterValueInitial
variant:MPKeyPurposeIdentification context:nil usingKey:key];
}
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
usingKey:(MPKey *)key {
- (NSString *)mpwTemplateForSiteNamed:(NSString *)name ofType:(MPResultType)type
withCounter:(MPCounterValue)counter usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:type withCounter:counter
variant:MPKeyPurposeAuthentication context:nil usingKey:key];
return [self mpwResultForSiteNamed:name ofType:type parameter:nil withCounter:counter
variant:MPKeyPurposeAuthentication context:nil usingKey:key];
}
- (NSString *)generateAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key {
- (NSString *)mpwAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key {
return [self generateContentForSiteNamed:name ofType:MPSiteTypeGeneratedPhrase withCounter:1
variant:MPKeyPurposeRecovery context:question usingKey:key];
return [self mpwResultForSiteNamed:name ofType:MPResultTypeTemplatePhrase parameter:nil withCounter:MPCounterValueInitial
variant:MPKeyPurposeRecovery context:question usingKey:key];
}
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant context:(NSString *)context usingKey:(MPKey *)key {
- (NSString *)mpwResultForSiteNamed:(NSString *)name ofType:(MPResultType)type parameter:(NSString *)parameter
withCounter:(MPCounterValue)counter variant:(MPKeyPurpose)purpose context:(NSString *)context
usingKey:(MPKey *)key {
__block NSString *content = nil;
__block NSString *result = nil;
[self mpw_perform:^{
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];
mpw_free_string( contentBytes );
char const *resultBytes = mpw_siteResult( [key keyForAlgorithm:self],
name.UTF8String, counter, purpose, context.UTF8String, type, parameter.UTF8String, [self version] );
if (resultBytes) {
result = [NSString stringWithCString:resultBytes encoding:NSUTF8StringEncoding];
mpw_free_string( &resultBytes );
}
}];
return content;
return result;
}
- (NSString *)storedLoginForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key {
- (BOOL)savePassword:(NSString *)plainText toSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
return nil;
}
- (NSString *)storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *)key {
return [self decryptContent:site.contentObject usingKey:key];
}
- (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
wrn( @"Cannot save content to site with generated type %lu.", (long)site.type );
return NO;
}
case MPSiteTypeStoredPersonal: {
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
return NO;
}
NSData *encryptionKey = [siteKey keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:encryptionKey padding:YES];
if ([((MPStoredSiteEntity *)site).contentObject isEqualToData:encryptedContent])
return NO;
((MPStoredSiteEntity *)site).contentObject = encryptedContent;
return YES;
}
case MPSiteTypeStoredDevicePrivate: {
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
return NO;
}
NSData *encryptionKey = [siteKey keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:encryptionKey padding:YES];
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
if (!encryptedContent)
[PearlKeyChain deleteItemForQuery:siteQuery];
else
[PearlKeyChain addOrUpdateItemForQuery:siteQuery withAttributes:@{
(__bridge id)kSecValueData : encryptedContent,
#if TARGET_OS_IPHONE
(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
#endif
}];
((MPStoredSiteEntity *)site).contentObject = nil;
return YES;
}
if (!(site.type & MPResultTypeClassStateful)) {
wrn( @"Can only save content to site with a stateful type: %lu.", (long)site.type );
return NO;
}
Throw( @"Unsupported type: %ld", (long)site.type );
NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
return NO;
}
__block NSData *state = nil;
if (plainText)
[self mpw_perform:^{
char const *stateBytes = mpw_siteState( [key keyForAlgorithm:self], site.name.UTF8String,
MPCounterValueInitial, MPKeyPurposeAuthentication, NULL, site.type, plainText.UTF8String, [self version] );
if (stateBytes) {
state = [[NSString stringWithCString:stateBytes encoding:NSUTF8StringEncoding] decodeBase64];
mpw_free_string( &stateBytes );
}
}];
NSDictionary *siteQuery = [self queryForSite:site];
if (!state)
[PearlKeyChain deleteItemForQuery:siteQuery];
else
[PearlKeyChain addOrUpdateItemForQuery:siteQuery withAttributes:@{
(__bridge id)kSecValueData: state,
#if TARGET_OS_IPHONE
(__bridge id)kSecAttrAccessible:
site.type & MPSiteFeatureDevicePrivate? (__bridge id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly
: (__bridge id)kSecAttrAccessibleWhenUnlocked,
#endif
}];
((MPStoredSiteEntity *)site).contentObject = nil;
return YES;
}
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (NSString *)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
return PearlAwait( ^(void (^setResult)(id)) {
[self resolveLoginForSite:site usingKey:siteKey result:^(NSString *result_) {
[self resolveLoginForSite:site usingKey:key result:^(NSString *result_) {
setResult( result_ );
}];
} );
}
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (NSString *)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
return PearlAwait( ^(void (^setResult)(id)) {
[self resolvePasswordForSite:site usingKey:siteKey result:^(NSString *result_) {
[self resolvePasswordForSite:site usingKey:key result:^(NSString *result_) {
setResult( result_ );
}];
} );
}
- (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (NSString *)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
return PearlAwait( ^(void (^setResult)(id)) {
[self resolveAnswerForSite:site usingKey:siteKey result:^(NSString *result_) {
[self resolveAnswerForSite:site usingKey:key result:^(NSString *result_) {
setResult( result_ );
}];
} );
}
- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey {
- (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)key {
return PearlAwait( ^(void (^setResult)(id)) {
[self resolveAnswerForQuestion:question usingKey:siteKey result:^(NSString *result_) {
[self resolveAnswerForQuestion:question usingKey:key result:^(NSString *result_) {
setResult( result_ );
}];
} );
}
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {
- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)key result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSString *name = site.name;
BOOL loginGenerated = site.loginGenerated && [[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateLogins];
NSString *loginName = site.loginName;
id<MPAlgorithm> algorithm = nil;
if (!name.length)
err( @"Missing name." );
else if (!siteKey)
else if (!key)
err( @"Missing key." );
else
algorithm = site.algorithm;
@@ -487,244 +470,144 @@ static NSOperationQueue *_mpwQueue = nil;
resultBlock( loginName );
else
PearlNotMainQueue( ^{
resultBlock( [algorithm generateLoginForSiteNamed:name usingKey:siteKey] );
resultBlock( [algorithm mpwLoginForSiteNamed:name usingKey:key] );
} );
}
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {
- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSString *name = site.name;
MPResultType type = site.type;
id<MPAlgorithm> algorithm = nil;
if (!site.name.length)
err( @"Missing name." );
else if (!key)
err( @"Missing key." );
else
algorithm = site.algorithm;
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
case MPResultTypeTemplateMaximum:
case MPResultTypeTemplateLong:
case MPResultTypeTemplateMedium:
case MPResultTypeTemplateBasic:
case MPResultTypeTemplateShort:
case MPResultTypeTemplatePIN:
case MPResultTypeTemplateName:
case MPResultTypeTemplatePhrase: {
if (![site isKindOfClass:[MPGeneratedSiteEntity class]]) {
wrn( @"Site with generated type %lu is not an MPGeneratedSiteEntity, but a %@.",
(long)site.type, [site class] );
break;
}
NSString *name = site.name;
MPSiteType type = site.type;
NSUInteger counter = ((MPGeneratedSiteEntity *)site).counter;
id<MPAlgorithm> algorithm = nil;
if (!site.name.length)
err( @"Missing name." );
else if (!siteKey)
err( @"Missing key." );
else
algorithm = site.algorithm;
MPCounterValue counter = ((MPGeneratedSiteEntity *)site).counter;
PearlNotMainQueue( ^{
resultBlock( [algorithm generatePasswordForSiteNamed:name ofType:type withCounter:counter usingKey:siteKey] );
resultBlock( [algorithm mpwTemplateForSiteNamed:name ofType:type withCounter:counter usingKey:key] );
} );
break;
}
case MPSiteTypeStoredPersonal: {
case MPResultTypeStatefulPersonal:
case MPResultTypeStatefulDevice: {
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
break;
}
NSData *encryptedContent = ((MPStoredSiteEntity *)site).contentObject;
NSDictionary *siteQuery = [self queryForSite:site];
NSData *state = [PearlKeyChain dataOfItemForQuery:siteQuery];
state = state?: ((MPStoredSiteEntity *)site).contentObject;
PearlNotMainQueue( ^{
resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] );
resultBlock( [algorithm mpwResultForSiteNamed:name ofType:type parameter:[state encodeBase64]
withCounter:MPCounterValueInitial variant:MPKeyPurposeAuthentication context:nil
usingKey:key] );
} );
break;
}
case MPSiteTypeStoredDevicePrivate: {
NSAssert( [site isKindOfClass:[MPStoredSiteEntity class]],
@"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.", (long)site.type,
[site class] );
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
NSData *encryptedContent = [PearlKeyChain dataOfItemForQuery:siteQuery];
PearlNotMainQueue( ^{
resultBlock( [self decryptContent:encryptedContent usingKey:siteKey] );
} );
case MPResultTypeDeriveKey:
break;
}
}
Throw( @"Type not supported: %lu", (long)type );
}
- (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {
- (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)key result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSString *name = site.name;
id<MPAlgorithm> algorithm = nil;
if (!site.name.length)
err( @"Missing name." );
else if (!siteKey)
else if (!key)
err( @"Missing key." );
else
algorithm = site.algorithm;
PearlNotMainQueue( ^{
resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:nil usingKey:siteKey] );
resultBlock( [algorithm mpwAnswerForSiteNamed:name onQuestion:nil usingKey:key] );
} );
}
- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey
- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)key
result:(void ( ^ )(NSString *result))resultBlock {
NSAssert( [[siteKey keyIDForAlgorithm:question.site.user.algorithm] isEqualToData:question.site.user.keyID],
NSAssert( [[key keyIDForAlgorithm:question.site.user.algorithm] isEqualToData:question.site.user.keyID],
@"Site does not belong to current user." );
NSString *name = question.site.name;
NSString *keyword = question.keyword;
id<MPAlgorithm> algorithm = nil;
if (!name.length)
err( @"Missing name." );
else if (!siteKey)
else if (!key)
err( @"Missing key." );
else if ([[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateAnswers])
algorithm = question.site.algorithm;
PearlNotMainQueue( ^{
resultBlock( [algorithm generateAnswerForSiteNamed:name onQuestion:keyword usingKey:siteKey] );
resultBlock( [algorithm mpwAnswerForSiteNamed:name onQuestion:keyword usingKey:key] );
} );
}
- (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPKey *)importKey
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (void)importPassword:(NSString *)cipherText protectedByKey:(MPKey *)importKey
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase:
break;
case MPSiteTypeStoredPersonal: {
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
break;
}
if ([[importKey keyIDForAlgorithm:self] isEqualToData:[siteKey keyIDForAlgorithm:self]])
((MPStoredSiteEntity *)site).contentObject = [protectedContent decodeBase64];
else {
NSString *clearContent = [self decryptContent:[protectedContent decodeBase64] usingKey:importKey];
[self importClearTextPassword:clearContent intoSite:site usingKey:siteKey];
}
break;
}
case MPSiteTypeStoredDevicePrivate:
break;
NSAssert( [[key keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
if (cipherText && cipherText.length && site.type & MPResultTypeClassStateful) {
NSString *plainText = [self mpwResultForSiteNamed:site.name ofType:site.type parameter:cipherText
withCounter:MPCounterValueInitial variant:MPKeyPurposeAuthentication context:nil
usingKey:importKey];
if (plainText)
[self savePassword:plainText toSite:site usingKey:key];
}
}
- (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (NSDictionary *)queryForSite:(MPSiteEntity *)site {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase:
break;
case MPSiteTypeStoredPersonal: {
[self savePassword:clearContent toSite:site usingKey:siteKey];
break;
}
case MPSiteTypeStoredDevicePrivate:
break;
}
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword attributes:@{
(__bridge id)kSecAttrService: site.type & MPSiteFeatureDevicePrivate? @"DevicePrivate": @"Private",
(__bridge id)kSecAttrAccount: site.name
} matches:nil];
}
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {
- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)key {
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
if (!(site.type & MPSiteFeatureExportContent))
return nil;
NSString *result = nil;
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
case MPSiteTypeGeneratedMedium:
case MPSiteTypeGeneratedBasic:
case MPSiteTypeGeneratedShort:
case MPSiteTypeGeneratedPIN:
case MPSiteTypeGeneratedName:
case MPSiteTypeGeneratedPhrase: {
result = nil;
break;
}
case MPSiteTypeStoredPersonal: {
if (![site isKindOfClass:[MPStoredSiteEntity class]]) {
wrn( @"Site with stored type %lu is not an MPStoredSiteEntity, but a %@.",
(long)site.type, [site class] );
break;
}
result = [((MPStoredSiteEntity *)site).contentObject encodeBase64];
break;
}
case MPSiteTypeStoredDevicePrivate: {
result = nil;
break;
}
}
return result;
NSDictionary *siteQuery = [self queryForSite:site];
NSData *state = [PearlKeyChain dataOfItemForQuery:siteQuery];
return [state?: ((MPStoredSiteEntity *)site).contentObject encodeBase64];
}
- (BOOL)migrateExplicitly:(BOOL)explicit {
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPResultType)type byAttacker:(MPAttacker)attacker {
return NO;
}
- (NSDictionary *)queryForDevicePrivateSiteNamed:(NSString *)name {
return [PearlKeyChain createQueryForClass:kSecClassGenericPassword
attributes:@{
(__bridge id)kSecAttrService: @"DevicePrivate",
(__bridge id)kSecAttrAccount: name
}
matches:nil];
}
- (NSString *)decryptContent:(NSData *)encryptedContent usingKey:(MPKey *)key {
if (!key)
return nil;
NSData *decryptedContent = nil;
if ([encryptedContent length]) {
NSData *encryptionKey = [key keyForAlgorithm:self trimmedLength:PearlCryptKeySize];
decryptedContent = [encryptedContent decryptWithSymmetricKey:encryptionKey padding:YES];
}
if (!decryptedContent)
return nil;
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
}
- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPSiteType)type byAttacker:(MPAttacker)attacker {
if (!(type & MPSiteTypeClassGenerated))
if (!(type & MPResultTypeClassTemplate))
return NO;
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );

View File

@@ -33,7 +33,7 @@
return NO;
if (!explicit) {
if (site.type & MPSiteTypeClassGenerated) {
if (site.type & MPResultTypeClassTemplate) {
// This migration requires explicit permission for types of the generated class.
site.requiresExplicitMigration = YES;
return NO;

View File

@@ -33,7 +33,7 @@
return NO;
if (!explicit) {
if (site.type & MPSiteTypeClassGenerated && site.name.length != [site.name dataUsingEncoding:NSUTF8StringEncoding].length) {
if (site.type & MPResultTypeClassTemplate && site.name.length != [site.name dataUsingEncoding:NSUTF8StringEncoding].length) {
// This migration requires explicit permission for types of the generated class.
site.requiresExplicitMigration = YES;
return NO;

View File

@@ -33,7 +33,7 @@
return NO;
if (!explicit) {
if (site.type & MPSiteTypeClassGenerated &&
if (site.type & MPResultTypeClassTemplate &&
site.user.name.length != [site.user.name dataUsingEncoding:NSUTF8StringEncoding].length) {
// This migration requires explicit permission for types of the generated class.
site.requiresExplicitMigration = YES;

View File

@@ -248,9 +248,9 @@
#endif
for (MPSiteEntity *site in user.sites) {
if (site.type & MPSiteTypeClassStored) {
if (site.type & MPResultTypeClassStateful) {
NSString *content;
while (!(content = [site.algorithm storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:recoverKey])) {
while (!(content = [site.algorithm resolvePasswordForSite:(MPStoredSiteEntity *)site usingKey:recoverKey])) {
// Failed to decrypt site with the current recoveryKey. Ask user for a new one to use.
NSString *masterPassword = nil;

View File

@@ -20,14 +20,6 @@
#import "MPFixable.h"
typedef NS_ENUM( NSUInteger, MPImportResult ) {
MPImportResultSuccess,
MPImportResultCancelled,
MPImportResultInvalidPassword,
MPImportResultMalformedInput,
MPImportResultInternalError,
};
@interface MPAppDelegate_Shared(Store)
+ (NSManagedObjectContext *)managedObjectContextForMainThreadIfReady;
@@ -42,10 +34,13 @@ typedef NS_ENUM( NSUInteger, MPImportResult ) {
/** @param completion The block to execute after adding the site, executed from the main thread with the new site in the main MOC. */
- (void)addSiteNamed:(NSString *)siteName completion:(void ( ^ )(MPSiteEntity *site, NSManagedObjectContext *context))completion;
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPSiteType)type;
- (MPImportResult)importSites:(NSString *)importedSitesString
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPResultType)type;
- (void)importSites:(NSString *)importData
askImportPassword:(NSString *( ^ )(NSString *userName))importPassword
askUserPassword:(NSString *( ^ )(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords;
askUserPassword:(NSString *( ^ )(NSString *userName))userPassword
result:(void ( ^ )(NSError *error))resultBlock;
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
result:(void ( ^ )(NSString *mpsites, NSError *error))resultBlock;
@end

View File

@@ -18,6 +18,7 @@
#import "MPAppDelegate_Store.h"
#import "mpw-marshall.h"
#import "mpw-util.h"
#if TARGET_OS_IPHONE
#define STORE_OPTIONS NSPersistentStoreFileProtectionKey : NSFileProtectionComplete,
@@ -489,7 +490,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
return;
}
MPSiteType type = activeUser.defaultType;
MPResultType type = activeUser.defaultType;
id<MPAlgorithm> algorithm = MPAlgorithmDefault;
Class entityType = [algorithm classOfType:type];
@@ -506,7 +507,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
}];
}
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPSiteType)type {
- (MPSiteEntity *)changeSite:(MPSiteEntity *)site saveInContext:(NSManagedObjectContext *)context toType:(MPResultType)type {
if (site.type == type)
return site;
@@ -539,328 +540,214 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
return site;
}
- (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *( ^ )(NSString *userName))importPassword
askUserPassword:(NSString *( ^ )(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword {
- (void)importSites:(NSString *)importData
askImportPassword:(NSString *( ^ )(NSString *userName))importPassword
askUserPassword:(NSString *( ^ )(NSString *userName))userPassword
result:(void ( ^ )(NSError *error))resultBlock {
NSAssert( ![[NSThread currentThread] isMainThread], @"This method should not be invoked from the main thread." );
__block MPImportResult result = MPImportResultCancelled;
do {
if ([MPAppDelegate_Shared managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
result = [self importSites:importedSitesString askImportPassword:importPassword askUserPassword:userPassword
saveInContext:context];
NSError *error = [self importSites:importData askImportPassword:importPassword askUserPassword:userPassword
saveInContext:context];
PearlMainQueue( ^{
resultBlock( error );
} );
}])
break;
usleep( (useconds_t)(USEC_PER_SEC * 0.2) );
} while (YES);
return result;
}
- (MPImportResult)importSites:(NSString *)importedSitesString
askImportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
askUserPassword:(NSString *( ^ )(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))askUserPassword
saveInContext:(NSManagedObjectContext *)context {
- (NSError *)importSites:(NSString *)importData
askImportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
askUserPassword:(NSString *( ^ )(NSString *userName))askUserPassword
saveInContext:(NSManagedObjectContext *)context {
// Compile patterns.
static NSRegularExpression *headerPattern;
static NSArray *sitePatterns;
NSError *error = nil;
if (!headerPattern) {
headerPattern = [[NSRegularExpression alloc]
initWithPattern:@"^#[[:space:]]*([^:]+): (.*)"
options:(NSRegularExpressionOptions)0 error:&error];
if (error) {
MPError( error, @"Error loading the header pattern." );
return MPImportResultInternalError;
// Read metadata for the import file.
MPMarshallInfo *info = mpw_marshall_read_info( importData.UTF8String );
if (info->format == MPMarshallFormatNone)
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
@"type" : @(MPMarshallErrorFormat),
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
}]), @"While importing sites." );
// Get master password for import file.
MPKey *importKey;
NSString *importMasterPassword;
do {
importMasterPassword = askImportPassword( @(info->fullName) );
if (!importMasterPassword) {
inf( @"Import cancelled." );
mpw_marshal_info_free( &info );
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
}
}
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;
}
}
importKey = [[MPKey alloc] initForFullName:@(info->fullName) withMasterPassword:importMasterPassword];
} while ([[[importKey keyIDForAlgorithm:MPAlgorithmForVersion( info->algorithm )] encodeHex]
caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
// Parse import data.
inf( @"Importing sites." );
NSUInteger importFormat = 0;
__block MPUserEntity *user = nil;
NSUInteger importAvatar = NSNotFound;
NSData *importKeyID = nil;
NSString *importBundleVersion = nil, *importUserName = nil;
id<MPAlgorithm> importAlgorithm = nil;
MPSiteType importDefaultType = (MPSiteType)0;
BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
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;
MPMarshallError importError = { .type = MPMarshallSuccess };
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
mpw_marshal_info_free( &info );
@try {
if (!importUser || importError.type != MPMarshallSuccess)
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
@"type" : @(importError.type),
NSLocalizedDescriptionKey: @(importError.description),
}]), @"While importing sites." );
// Find an existing user to update.
NSError *error = nil;
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", @(importUser->fullName)];
NSArray *users = [context executeFetchRequest:userFetchRequest error:&error];
if (!users)
return MPError( error, @"While looking for user: %@.", @(importUser->fullName) );
if ([users count] > 1)
return MPMakeError( @"While looking for user: %@, found more than one: %zu",
@(importUser->fullName), (size_t)[users count] );
// Get master key for user.
MPUserEntity *user = [users lastObject];
MPKey *userKey = importKey;
while (user && ![[userKey keyIDForAlgorithm:user.algorithm] isEqualToData:user.keyID]) {
NSString *userMasterPassword = askUserPassword( user.name );
if (!userMasterPassword) {
inf( @"Import cancelled." );
return MPError( ([NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil]), @"" );
}
// 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;
userKey = [[MPKey alloc] initForFullName:@(importUser->fullName) withMasterPassword:userMasterPassword];
}
// 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];
}
// Update or create user.
if (!user) {
user = [MPUserEntity insertNewObjectInContext:context];
user.name = @(importUser->fullName);
}
[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.algorithm = MPAlgorithmForVersion( importUser->algorithm );
user.keyID = [userKey keyIDForAlgorithm:user.algorithm];
user.defaultType = importDefaultType?: user.algorithm.defaultType;
if (importAvatar != NSNotFound)
user.avatar = importAvatar;
dbg( @"Created User: %@", [user debugDescription] );
}
user.avatar = importUser->avatar;
user.defaultType = importUser->defaultType;
user.lastUsed = [NSDate dateWithTimeIntervalSince1970:MAX( user.lastUsed.timeIntervalSince1970, importUser->lastUsed )];
dbg( @"Importing 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]: nil;
NSString *siteName = siteElements[6];
NSString *exportContent = siteElements[7];
// Update or create sites.
for (size_t s = 0; s < importUser->sites_count; ++s) {
MPMarshalledSite *importSite = &importUser->sites[s];
// 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;
// Find an existing site to update.
NSFetchRequest *siteFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )];
siteFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", @(importSite->name), user];
NSArray *existingSites = [context executeFetchRequest:siteFetchRequest error:&error];
if (!existingSites)
return MPError( error, @"Lookup of existing sites failed for site: %@, user: %@", @(importSite->name), user.userID );
if ([existingSites count])
// Update existing site.
for (MPSiteEntity *site in existingSites) {
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
dbg( @"Updated site: %@", [site debugDescription] );
}
else {
// Create new site.
id<MPAlgorithm> algorithm = MPAlgorithmForVersion( importSite->algorithm );
Class entityType = [algorithm classOfType:importSite->type];
if (!entityType)
return MPMakeError( @"Invalid site type in import file: %@ has type %lu", @(importSite->name), (long)importSite->type );
MPSiteEntity *site = (MPSiteEntity *)[entityType insertNewObjectInContext:context];
site.user = user;
[self importSite:importSite protectedByKey:importKey intoSite:site usingKey:userKey];
dbg( @"Created site: %@", [site debugDescription] );
}
}
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 MPMakeError( @"Failed saving imported changes." );
inf( @"Import completed successfully." );
[[NSNotificationCenter defaultCenter] postNotificationName:MPSitesImportedNotification object:nil userInfo:@{
MPSitesImportedNotificationUserKey: user
}];
return nil;
}
@finally {
mpw_marshal_free( &importUser );
}
if (![context saveToStore])
return MPImportResultInternalError;
inf( @"Import completed successfully." );
[[NSNotificationCenter defaultCenter] postNotificationName:MPSitesImportedNotification object:nil userInfo:@{
MPSitesImportedNotificationUserKey: user
}];
return MPImportResultSuccess;
}
- (NSString *)exportSitesRevealPasswords:(BOOL)revealPasswords {
- (void)importSite:(const MPMarshalledSite *)importSite protectedByKey:(MPKey *)importKey intoSite:(MPSiteEntity *)site
usingKey:(MPKey *)userKey {
MPUserEntity *activeUser = [self activeUserForMainThread];
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", activeUser.userID );
site.name = @(importSite->name);
if (importSite->content)
[site.algorithm importPassword:@(importSite->content) protectedByKey:importKey intoSite:site usingKey:userKey];
site.type = importSite->type;
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
((MPGeneratedSiteEntity *)site).counter = importSite->counter;
site.algorithm = MPAlgorithmForVersion( importSite->algorithm );
site.loginName = importSite->loginContent? @(importSite->loginContent): nil;
site.loginGenerated = importSite->loginType & MPResultTypeClassTemplate;
site.url = importSite->url? @(importSite->url): nil;
site.uses = importSite->uses;
site.lastUsed = [NSDate dateWithTimeIntervalSince1970:importSite->lastUsed];
}
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;
- (void)exportSitesRevealPasswords:(BOOL)revealPasswords
askExportPassword:(NSString *( ^ )(NSString *userName))askImportPassword
result:(void ( ^ )(NSString *mpsites, NSError *error))resultBlock {
[MPAppDelegate_Shared managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPUserEntity *user = [self activeUserInContext:context];
NSString *masterPassword = askImportPassword( user.name );
for (MPSiteEntity *site in activeUser.sites) {
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;
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID );
MPMarshalledUser *exportUser = mpw_marshall_user( user.name.UTF8String, masterPassword.UTF8String, user.algorithm.version );
exportUser->redacted = !revealPasswords;
exportUser->avatar = (unsigned int)user.avatar;
exportUser->defaultType = user.defaultType;
exportUser->lastUsed = (time_t)user.lastUsed.timeIntervalSince1970;
for (MPSiteQuestionEntity *siteQuestion in site.questions)
mpw_marshal_question( &exportSite, siteQuestion.keyword.UTF8String );
}
for (MPSiteEntity *site in user.sites) {
MPCounterValue counter = MPCounterValueInitial;
if ([site isKindOfClass:[MPGeneratedSiteEntity class]])
counter = ((MPGeneratedSiteEntity *)site).counter;
NSString *content = revealPasswords
? [site.algorithm exportPasswordForSite:site usingKey:self.key]
: [site.algorithm resolvePasswordForSite:site usingKey:self.key];
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser );
MPMarshalledSite *exportSite = mpw_marshall_site( exportUser,
site.name.UTF8String, site.type, counter, site.algorithm.version );
exportSite->content = content.UTF8String;
exportSite->loginContent = site.loginName.UTF8String;
exportSite->loginType = site.loginGenerated? MPResultTypeTemplateName: MPResultTypeStatefulPersonal;
exportSite->url = site.url.UTF8String;
exportSite->uses = (unsigned int)site.uses;
exportSite->lastUsed = (time_t)site.lastUsed.timeIntervalSince1970;
for (MPSiteQuestionEntity *siteQuestion in site.questions)
mpw_marshal_question( exportSite, siteQuestion.keyword.UTF8String );
}
char *export = NULL;
MPMarshallError exportError = (MPMarshallError){ .type= MPMarshallSuccess };
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser, &exportError );
NSString *mpsites = nil;
if (export && exportError.type == MPMarshallSuccess)
mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
mpw_free_string( &export );
resultBlock( mpsites, exportError.type == MPMarshallSuccess? nil:
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
@"type" : @(exportError.type),
NSLocalizedDescriptionKey: @(exportError.description),
}] );
}];
}
@end

View File

@@ -48,7 +48,7 @@
@interface MPSiteEntity(MP)<MPFixable>
@property(assign) BOOL loginGenerated;
@property(assign) MPSiteType type;
@property(assign) MPResultType type;
@property(readonly) NSString *typeName;
@property(readonly) NSString *typeShortName;
@property(readonly) NSString *typeClassName;
@@ -71,7 +71,7 @@
@interface MPGeneratedSiteEntity(MP)
@property(assign) NSUInteger counter;
@property(assign) MPCounterValue counter;
@end
@@ -80,7 +80,7 @@
@property(assign) NSUInteger avatar;
@property(assign) BOOL saveKey;
@property(assign) BOOL touchID;
@property(assign) MPSiteType defaultType;
@property(assign) MPResultType defaultType;
@property(readonly) NSString *userID;
@property(strong) id<MPAlgorithm> algorithm;

View File

@@ -82,9 +82,9 @@
return MPFixableResultNoProblems;
}
- (MPSiteType)type {
- (MPResultType)type {
return (MPSiteType)[self.type_ unsignedIntegerValue];
return (MPResultType)[self.type_ unsignedIntegerValue];
}
- (void)setLoginGenerated:(BOOL)aLoginGenerated {
@@ -97,7 +97,7 @@
return [self.loginGenerated_ boolValue];
}
- (void)setType:(MPSiteType)aType {
- (void)setType:(MPResultType)aType {
self.type_ = @(aType);
}
@@ -251,7 +251,7 @@
MPFixableResult result = [super findAndFixInconsistenciesInContext:context];
if (!self.type || self.type == (MPSiteType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
if (!self.type || self.type == (MPResultType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.type
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
@@ -259,7 +259,7 @@
self.type = self.user.defaultType;
return MPFixableResultProblemsFixed;
} );
if (!self.type || self.type == (MPSiteType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
if (!self.type || self.type == (MPResultType)NSNotFound || ![[self.algorithm allTypes] containsObject:self.type_])
// Invalid self.user.defaultType
result = MPApplyFix( result, ^MPFixableResult {
wrn( @"Invalid type for: %@ of %@, type: %ld. Will use %ld instead.",
@@ -270,7 +270,7 @@
if (![self isKindOfClass:[self.algorithm classOfType:self.type]])
// Mismatch between self.type and self.class
result = MPApplyFix( result, ^MPFixableResult {
for (MPSiteType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
for (MPResultType newType = self.type; self.type != (newType = [self.algorithm nextType:newType]);)
if ([self isKindOfClass:[self.algorithm classOfType:newType]]) {
wrn( @"Mismatching type for: %@ of %@, type: %lu, class: %@. Will use %ld instead.",
self.name, self.user.name, (long)self.type, self.class, (long)newType );
@@ -286,12 +286,12 @@
return result;
}
- (NSUInteger)counter {
- (MPCounterValue)counter {
return [self.counter_ unsignedIntegerValue];
return (MPCounterValue)[self.counter_ unsignedIntegerValue];
}
- (void)setCounter:(NSUInteger)aCounter {
- (void)setCounter:(MPCounterValue)aCounter {
self.counter_ = @(aCounter);
}
@@ -354,12 +354,12 @@
self.touchID_ = @(aTouchID);
}
- (MPSiteType)defaultType {
- (MPResultType)defaultType {
return (MPSiteType)[self.defaultType_ unsignedIntegerValue]?: self.algorithm.defaultType;
return (MPResultType)[self.defaultType_ unsignedIntegerValue]?: self.algorithm.defaultType;
}
- (void)setDefaultType:(MPSiteType)aDefaultType {
- (void)setDefaultType:(MPResultType)aDefaultType {
self.defaultType_ = @(aDefaultType);
}

View File

@@ -22,6 +22,7 @@
__BEGIN_DECLS
extern NSString *const MPErrorDomain;
extern NSInteger const MPErrorHangCode;
extern NSInteger const MPErrorMarshallCode;
extern NSString *const MPSignedInNotification;
extern NSString *const MPSignedOutNotification;
@@ -38,16 +39,26 @@ __END_DECLS
#ifdef CRASHLYTICS
#define MPError(error_, message, ...) ({ \
err( message @"%@%@", ##__VA_ARGS__, error_? @"\n": @"", [error_ fullDescription]?: @"" ); \
NSError *__error = error_; \
err( message @"%@%@", ##__VA_ARGS__, __error && [message length]? @"\n": @"", [__error fullDescription]?: @"" ); \
\
if ([[MPConfig get].sendInfo boolValue]) { \
[[Crashlytics sharedInstance] recordError:error_ withAdditionalUserInfo:@{ \
if (__error && [[MPConfig get].sendInfo boolValue]) { \
[[Crashlytics sharedInstance] recordError:__error withAdditionalUserInfo:@{ \
@"location": strf( @"%@:%d %@", @(basename((char *)__FILE__)), __LINE__, NSStringFromSelector(_cmd) ), \
}]; \
} \
__error; \
})
#else
#define MPError(error_, message, ...) ({ \
err( message @"%@%@", ##__VA_ARGS__, error_? @"\n": @"", [error_ fullDescription]?: @"" ); \
NSError *__error = error_; \
err( message @"%@%@", ##__VA_ARGS__, __error? @"\n": @"", [__error fullDescription]?: @"" ); \
__error; \
})
#endif
#define MPMakeError(message, ...) ({ \
MPError( [NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{ \
NSLocalizedDescriptionKey: strf( message, ##__VA_ARGS__ ) \
}], @"" ); \
})

View File

@@ -20,6 +20,7 @@
NSString *const MPErrorDomain = @"MPErrorDomain";
NSInteger const MPErrorHangCode = 1;
NSInteger const MPErrorMarshallCode = 1;
NSString *const MPSignedInNotification = @"MPSignedInNotification";
NSString *const MPSignedOutNotification = @"MPSignedOutNotification";

View File

@@ -269,23 +269,22 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
[openPanel close];
[[[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:
^(NSData *importedSitesData, NSURLResponse *response, NSError *error) {
if (error)
MPError( error, @"While reading imported sites from %@.", url );
^(NSData *importedSitesData, NSURLResponse *response, NSError *urlError) {
if (urlError)
[[NSAlert alertWithError:MPError( urlError, @"While reading imported sites from %@.", url )] runModal];
if (!importedSitesData)
return;
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
[self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
__block NSString *masterPassword = nil;
PearlMainQueueWait( ^{
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Unlock"];
[alert addButtonWithTitle:@"Cancel"];
alert.messageText = @"Import File's Master Password";
alert.informativeText = strf( @"%@'s export was done using a different master password.\n"
@"Enter that master password to unlock the exported data.", userName );
alert.messageText = strf( @"Importing Sites For\n%@", userName );
alert.informativeText = @"Enter the master password used to create this export file.";
alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert layout];
if ([alert runModal] == NSAlertFirstButtonReturn)
@@ -293,16 +292,15 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
} );
return masterPassword;
} askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) {
} askUserPassword:^NSString *(NSString *userName) {
__block NSString *masterPassword = nil;
PearlMainQueueWait( ^{
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Import"];
[alert addButtonWithTitle:@"Cancel"];
alert.messageText = strf( @"Master Password for\n%@", userName );
alert.informativeText = strf( @"Imports %lu sites, overwriting %lu.",
(unsigned long)importCount, (unsigned long)deleteCount );
alert.messageText = strf( @"Master Password For\n%@", userName );
alert.informativeText = @"Enter the current master password for this user.";
alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert layout];
if ([alert runModal] == NSAlertFirstButtonReturn)
@@ -310,37 +308,12 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
} );
return masterPassword;
} result:^(NSError *error) {
[self updateUsers];
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError))
[[NSAlert alertWithError:error] runModal];
}];
PearlMainQueue( ^{
switch (result) {
case MPImportResultSuccess: {
[self updateUsers];
NSAlert *alert = [NSAlert new];
alert.messageText = @"Successfully imported sites.";
[alert runModal];
break;
}
case MPImportResultCancelled:
break;
case MPImportResultInternalError:
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey: @"Import failed because of an internal error."
}]] runModal];
break;
case MPImportResultMalformedInput:
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey: @"The import doesn't look like a Master Password export."
}]] runModal];
break;
case MPImportResultInvalidPassword:
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
NSLocalizedDescriptionKey: @"Incorrect master password for the import sites."
}]] runModal];
break;
}
} );
}] resume];
}
@@ -509,25 +482,43 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
if ([savePanel runModal] == NSFileHandlingPanelCancelButton)
return;
NSError *coordinateError = nil;
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
[[[NSFileCoordinator alloc] initWithFilePresenter:nil] coordinateWritingItemAtURL:savePanel.URL options:0
error:&coordinateError byAccessor:
^(NSURL *newURL) {
NSError *writeError = nil;
if (![exportedSites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
MPError( writeError, @"Could not write to the export file." );
[self exportSitesRevealPasswords:revealPasswords
askExportPassword:^NSString *(NSString *userName) {
return PearlMainQueueAwait( ^id {
NSAlert *alert = [NSAlert new];
[alert addButtonWithTitle:@"Import"];
[alert addButtonWithTitle:@"Cancel"];
alert.messageText = strf( @"Master Password For\n%@", userName );
alert.informativeText = @"Enter the current master password for this user.";
alert.accessoryView = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
[alert layout];
if ([alert runModal] == NSAlertFirstButtonReturn)
return ((NSTextField *)alert.accessoryView).stringValue;
else
return nil;
} );
} result:^(NSString *mpsites, NSError *error) {
if (!mpsites || error) {
PearlMainQueue( ^{
[[NSAlert alertWithError:MPError( error, @"Failed to export mpsites." )] runModal];
} );
return;
}
NSError *coordinateError = nil;
[[[NSFileCoordinator alloc] initWithFilePresenter:nil]
coordinateWritingItemAtURL:savePanel.URL options:0 error:&coordinateError byAccessor:^(NSURL *newURL) {
NSError *writeError = nil;
if (![mpsites writeToURL:newURL atomically:NO encoding:NSUTF8StringEncoding error:&writeError])
PearlMainQueue( ^{
[[NSAlert alertWithError:writeError] runModal];
[[NSAlert alertWithError:MPError( writeError, @"Could not write to the export file." )] runModal];
} );
}];
if (coordinateError) {
MPError( coordinateError, @"Write access to the export file could not be obtained." );
PearlMainQueue( ^{
[[NSAlert alertWithError:coordinateError] runModal];
} );
}
}];
if (coordinateError)
PearlMainQueue( ^{
[[NSAlert alertWithError:MPError( coordinateError, @"Could not gain access to the export file." )] runModal];
} );
}];
}
- (void)updateUsers {

View File

@@ -27,7 +27,7 @@
@property(nonatomic) NSString *name;
@property(nonatomic) NSAttributedString *displayedName;
@property(nonatomic) MPSiteType type;
@property(nonatomic) MPResultType type;
@property(nonatomic) NSString *typeName;
@property(nonatomic) NSString *content;
@property(nonatomic) NSString *displayedContent;
@@ -36,7 +36,7 @@
@property(nonatomic) NSString *loginName;
@property(nonatomic) BOOL loginGenerated;
@property(nonatomic) NSNumber *uses;
@property(nonatomic) NSUInteger counter;
@property(nonatomic) MPCounterValue counter;
@property(nonatomic) NSDate *lastUsed;
@property(nonatomic) id<MPAlgorithm> algorithm;
@property(nonatomic) MPAlgorithmVersion algorithmVersion;

View File

@@ -81,7 +81,7 @@
self.type = entity.type;
self.typeName = entity.typeName;
self.uses = entity.uses_;
self.counter = [entity isKindOfClass:[MPGeneratedSiteEntity class]]? [(MPGeneratedSiteEntity *)entity counter]: 0;
self.counter = [entity isKindOfClass:[MPGeneratedSiteEntity class]]? [(MPGeneratedSiteEntity *)entity counter]: MPCounterValueInitial;
self.loginGenerated = entity.loginGenerated;
// Find all password types and the index of the current type amongst them.
@@ -104,7 +104,7 @@
self.type = user.defaultType;
self.typeName = [self.algorithm nameOfType:self.type];
self.uses = @0;
self.counter = 1;
self.counter = MPCounterValueDefault;
// Find all password types and the index of the current type amongst them.
[self updateContent];
@@ -116,14 +116,14 @@
return nil;
NSError *error;
MPSiteEntity *entity = (MPSiteEntity *)[moc existingObjectWithID:self.entityOID error:&error];
MPSiteEntity *entity = [moc existingObjectWithID:self.entityOID error:&error];
if (!entity)
MPError( error, @"Couldn't retrieve active site." );
return entity;
}
- (void)setCounter:(NSUInteger)counter {
- (void)setCounter:(MPCounterValue)counter {
if (self.counter == counter)
return;
@@ -210,12 +210,12 @@
- (BOOL)generated {
return self.type & MPSiteTypeClassGenerated;
return self.type & MPResultTypeClassTemplate;
}
- (BOOL)stored {
return self.type & MPSiteTypeClassStored;
return self.type & MPResultTypeClassStateful;
}
- (BOOL)transient {
@@ -233,14 +233,14 @@
else
PearlNotMainQueue( ^{
[self updatePasswordWithResult:
[self.algorithm generatePasswordForSiteNamed:self.name ofType:self.type withCounter:self.counter
usingKey:[MPAppDelegate_Shared get].key]];
[self.algorithm mpwTemplateForSiteNamed:self.name ofType:self.type withCounter:self.counter
usingKey:[MPAppDelegate_Shared get].key]];
[self updateLoginNameWithResult:
[self.algorithm generateLoginForSiteNamed:self.name
usingKey:[MPAppDelegate_Shared get].key]];
[self.algorithm mpwLoginForSiteNamed:self.name
usingKey:[MPAppDelegate_Shared get].key]];
[self updateAnswerWithResult:
[self.algorithm generateAnswerForSiteNamed:self.name onQuestion:self.question
usingKey:[MPAppDelegate_Shared get].key]];
[self.algorithm mpwAnswerForSiteNamed:self.name onQuestion:self.question
usingKey:[MPAppDelegate_Shared get].key]];
} );
}
@@ -252,8 +252,8 @@
[entity resolveLoginUsingKey:[MPAppDelegate_Shared get].key result:^(NSString *result) {
[self updateLoginNameWithResult:result];
}];
[self updateAnswerWithResult:[self.algorithm generateAnswerForSiteNamed:self.name onQuestion:self.question
usingKey:[MPAppDelegate_Shared get].key]];
[self updateAnswerWithResult:[self.algorithm mpwAnswerForSiteNamed:self.name onQuestion:self.question
usingKey:[MPAppDelegate_Shared get].key]];
}
- (void)updatePasswordWithResult:(NSString *)result {

View File

@@ -373,11 +373,11 @@
NSArray *types = [site.algorithm allTypes];
[self.passwordTypesMatrix renewRows:(NSInteger)[types count] columns:1];
for (NSUInteger t = 0; t < [types count]; ++t) {
MPSiteType type = (MPSiteType)[types[t] unsignedIntegerValue];
MPResultType type = (MPResultType)[types[t] unsignedIntegerValue];
NSString *title = [site.algorithm nameOfType:type];
if (type & MPSiteTypeClassGenerated)
title = strf( @"%@ %@", [site.algorithm generatePasswordForSiteNamed:site.name ofType:type withCounter:site.counter
usingKey:[MPMacAppDelegate get].key], title );
if (type & MPResultTypeClassTemplate)
title = strf( @"%@ %@", [site.algorithm mpwTemplateForSiteNamed:site.name ofType:type withCounter:site.counter
usingKey:[MPMacAppDelegate get].key], title );
NSButtonCell *cell = [self.passwordTypesMatrix cellAtRow:(NSInteger)t column:0];
cell.tag = type;
@@ -397,7 +397,7 @@
switch (returnCode) {
case NSAlertFirstButtonReturn: {
// "Save" button.
MPSiteType type = (MPSiteType)[self.passwordTypesMatrix.selectedCell tag];
MPResultType type = (MPResultType)[self.passwordTypesMatrix.selectedCell tag];
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *entity = [[MPMacAppDelegate get] changeSite:[self.selectedSite entityInContext:context]
saveInContext:context toType:type];

View File

@@ -137,9 +137,9 @@
- (void)updatePassword {
NSString *siteName = self.siteField.text;
MPSiteType siteType = [self siteType];
NSUInteger siteCounter = (NSUInteger)self.counterStepper.value;
self.counterLabel.text = strf( @"%lu", (unsigned long)siteCounter );
MPResultType siteType = [self siteType];
MPCounterValue siteCounter = (MPCounterValue)self.counterStepper.value;
self.counterLabel.text = strf( @"%u", siteCounter );
[self.passwordButton setTitle:nil forState:UIControlStateNormal];
[self.activity startAnimating];
@@ -147,8 +147,8 @@
[self.emergencyPasswordQueue addOperationWithBlock:^{
NSString *sitePassword = nil;
if (self.key && [siteName length])
sitePassword = [MPAlgorithmDefault generatePasswordForSiteNamed:siteName ofType:siteType withCounter:siteCounter
usingKey:self.key];
sitePassword = [MPAlgorithmDefault mpwTemplateForSiteNamed:siteName ofType:siteType withCounter:siteCounter
usingKey:self.key];
PearlMainQueue( ^{
[self.activity stopAnimating];
@@ -157,21 +157,21 @@
}];
}
- (enum MPSiteType)siteType {
- (MPResultType)siteType {
switch (self.typeControl.selectedSegmentIndex) {
case 0:
return MPSiteTypeGeneratedMaximum;
return MPResultTypeTemplateMaximum;
case 1:
return MPSiteTypeGeneratedLong;
return MPResultTypeTemplateLong;
case 2:
return MPSiteTypeGeneratedMedium;
return MPResultTypeTemplateMedium;
case 3:
return MPSiteTypeGeneratedBasic;
return MPResultTypeTemplateBasic;
case 4:
return MPSiteTypeGeneratedShort;
return MPResultTypeTemplateShort;
case 5:
return MPSiteTypeGeneratedPIN;
return MPResultTypeTemplatePIN;
default:
Throw( @"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex );
}

View File

@@ -60,15 +60,15 @@
self.touchIDSwitch.on = activeUser.touchID;
self.touchIDSwitch.enabled = self.savePasswordSwitch.on && [[MPiOSAppDelegate get] isFeatureUnlocked:MPProductTouchID];
MPSiteType defaultType = activeUser.defaultType;
MPResultType defaultType = activeUser.defaultType;
self.generated1TypeControl.selectedSegmentIndex = [self generated1SegmentIndexForType:defaultType];
self.generated2TypeControl.selectedSegmentIndex = [self generated2SegmentIndexForType:defaultType];
self.storedTypeControl.selectedSegmentIndex = [self storedSegmentIndexForType:defaultType];
PearlNotMainQueue( ^{
NSString *examplePassword = nil;
if (defaultType & MPSiteTypeClassGenerated)
examplePassword = [MPAlgorithmDefault generatePasswordForSiteNamed:@"test" ofType:defaultType
withCounter:1 usingKey:[MPiOSAppDelegate get].key];
if (defaultType & MPResultTypeClassTemplate)
examplePassword = [MPAlgorithmDefault mpwTemplateForSiteNamed:@"test" ofType:defaultType
withCounter:1 usingKey:[MPiOSAppDelegate get].key];
PearlMainQueue( ^{
self.typeSamplePassword.text = [examplePassword length]? [NSString stringWithFormat:@"eg. %@", examplePassword]: nil;
} );
@@ -164,7 +164,7 @@
if (sender != self.storedTypeControl)
self.storedTypeControl.selectedSegmentIndex = -1;
MPSiteType defaultType = [self typeForSelectedSegment];
MPResultType defaultType = [self typeForSelectedSegment];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[[MPiOSAppDelegate get] activeUserInContext:context].defaultType = defaultType;
[context saveToStore];
@@ -242,7 +242,7 @@
return nil;
}
- (MPSiteType)typeForSelectedSegment {
- (MPResultType)typeForSelectedSegment {
NSInteger selectedGenerated1Index = self.generated1TypeControl.selectedSegmentIndex;
NSInteger selectedGenerated2Index = self.generated2TypeControl.selectedSegmentIndex;
@@ -250,30 +250,30 @@
switch (selectedGenerated1Index) {
case 0:
return MPSiteTypeGeneratedPhrase;
return MPResultTypeTemplatePhrase;
case 1:
return MPSiteTypeGeneratedName;
return MPResultTypeTemplateName;
default:
switch (selectedGenerated2Index) {
case 0:
return MPSiteTypeGeneratedMaximum;
return MPResultTypeTemplateMaximum;
case 1:
return MPSiteTypeGeneratedLong;
return MPResultTypeTemplateLong;
case 2:
return MPSiteTypeGeneratedMedium;
return MPResultTypeTemplateMedium;
case 3:
return MPSiteTypeGeneratedBasic;
return MPResultTypeTemplateBasic;
case 4:
return MPSiteTypeGeneratedShort;
return MPResultTypeTemplateShort;
case 5:
return MPSiteTypeGeneratedPIN;
return MPResultTypeTemplatePIN;
default:
switch (selectedStoredIndex) {
case 0:
return MPSiteTypeStoredPersonal;
return MPResultTypeStatefulPersonal;
case 1:
return MPSiteTypeStoredDevicePrivate;
return MPResultTypeStatefulDevice;
default:
Throw( @"unsupported selected type index: generated1=%ld, generated2=%ld, stored=%ld",
(long)selectedGenerated1Index, (long)selectedGenerated2Index, (long)selectedStoredIndex );
@@ -282,44 +282,44 @@
}
}
- (NSInteger)generated1SegmentIndexForType:(MPSiteType)type {
- (NSInteger)generated1SegmentIndexForType:(MPResultType)type {
switch (type) {
case MPSiteTypeGeneratedPhrase:
case MPResultTypeTemplatePhrase:
return 0;
case MPSiteTypeGeneratedName:
case MPResultTypeTemplateName:
return 1;
default:
return -1;
}
}
- (NSInteger)generated2SegmentIndexForType:(MPSiteType)type {
- (NSInteger)generated2SegmentIndexForType:(MPResultType)type {
switch (type) {
case MPSiteTypeGeneratedMaximum:
case MPResultTypeTemplateMaximum:
return 0;
case MPSiteTypeGeneratedLong:
case MPResultTypeTemplateLong:
return 1;
case MPSiteTypeGeneratedMedium:
case MPResultTypeTemplateMedium:
return 2;
case MPSiteTypeGeneratedBasic:
case MPResultTypeTemplateBasic:
return 3;
case MPSiteTypeGeneratedShort:
case MPResultTypeTemplateShort:
return 4;
case MPSiteTypeGeneratedPIN:
case MPResultTypeTemplatePIN:
return 5;
default:
return -1;
}
}
- (NSInteger)storedSegmentIndexForType:(MPSiteType)type {
- (NSInteger)storedSegmentIndexForType:(MPResultType)type {
switch (type) {
case MPSiteTypeStoredPersonal:
case MPResultTypeStatefulPersonal:
return 0;
case MPSiteTypeStoredDevicePrivate:
case MPResultTypeStatefulDevice:
return 1;
default:
return -1;

View File

@@ -284,7 +284,7 @@
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic
initSheet:^(UIActionSheet *sheet) {
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
MPSiteType type = (MPSiteType)[typeNumber unsignedIntegerValue];
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
NSString *typeName = [mainSite.algorithm nameOfType:type];
if (type == mainSite.type)
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
@@ -295,7 +295,7 @@
if (buttonIndex == [sheet cancelButtonIndex])
return;
MPSiteType type = (MPSiteType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
MPResultType type = (MPResultType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?:
mainSite.user.defaultType?: mainSite.algorithm.defaultType;
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
@@ -311,7 +311,7 @@
self.loginNameField.enabled = YES;
self.passwordField.enabled = YES;
if ([self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPSiteTypeClassStored)
if ([self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].type & MPResultTypeClassStateful)
[self.passwordField becomeFirstResponder];
else
[self.loginNameField becomeFirstResponder];
@@ -537,7 +537,7 @@
self.loginNameContainer.visible = settingsMode || mainSite.loginGenerated || [mainSite.loginName length];
self.modeButton.visible = !self.transientSite;
self.modeButton.alpha = settingsMode? 0.5f: 0.1f;
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPSiteTypeClassGenerated;
self.counterLabel.visible = self.counterButton.visible = mainSite.type & MPResultTypeClassTemplate;
self.modeButton.selected = settingsMode;
self.strengthLabel.gone = !settingsMode;
self.modeScrollView.scrollEnabled = !self.transientSite;
@@ -565,8 +565,8 @@
// Site Password
self.passwordField.secureTextEntry = [[MPiOSConfig get].hidePasswords boolValue];
self.passwordField.attributedPlaceholder = stra(
mainSite.type & MPSiteTypeClassStored? strl( @"No password" ):
mainSite.type & MPSiteTypeClassGenerated? strl( @"..." ): @"", @{
mainSite.type & MPResultTypeClassStateful? strl( @"No password" ):
mainSite.type & MPResultTypeClassTemplate? strl( @"..." ): @"", @{
NSForegroundColorAttributeName: [UIColor whiteColor]
} );
@@ -585,10 +585,10 @@
BOOL loginGenerated = site.loginGenerated;
NSString *password = nil, *loginName = [site resolveLoginUsingKey:key];
MPSiteType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
if (self.transientSite && transientType & MPSiteTypeClassGenerated)
password = [MPAlgorithmDefault generatePasswordForSiteNamed:self.transientSite ofType:transientType
withCounter:1 usingKey:key];
MPResultType transientType = [[MPiOSAppDelegate get] activeUserInContext:context].defaultType?: MPAlgorithmDefault.defaultType;
if (self.transientSite && transientType & MPResultTypeClassTemplate)
password = [MPAlgorithmDefault mpwTemplateForSiteNamed:self.transientSite ofType:transientType
withCounter:1 usingKey:key];
else if (site)
password = [site resolvePasswordUsingKey:key];

View File

@@ -23,8 +23,8 @@
@protocol MPTypeDelegate<NSObject>
@required
- (void)didSelectType:(MPSiteType)type;
- (MPSiteType)selectedType;
- (void)didSelectType:(MPResultType)type;
- (MPResultType)selectedType;
@optional
- (MPSiteEntity *)selectedSite;

View File

@@ -22,7 +22,7 @@
@interface MPTypeViewController()
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath;
- (MPResultType)typeAtIndexPath:(NSIndexPath *)indexPath;
@end
@@ -75,21 +75,21 @@
if ([self.delegate respondsToSelector:@selector( selectedSite )])
selectedSite = [self.delegate selectedSite];
MPSiteType cellType = [self typeAtIndexPath:indexPath];
MPSiteType selectedType = selectedSite? selectedSite.type: [self.delegate selectedType];
MPResultType cellType = [self typeAtIndexPath:indexPath];
MPResultType selectedType = selectedSite? selectedSite.type: [self.delegate selectedType];
cell.selected = (selectedType == cellType);
if (cellType != (MPSiteType)NSNotFound && cellType & MPSiteTypeClassGenerated) {
if (cellType != (MPResultType)NSNotFound && cellType & MPResultTypeClassTemplate) {
[(UITextField *)[cell viewWithTag:2] setText:@"..."];
NSString *name = selectedSite.name;
NSUInteger counter = 0;
MPCounterValue counter = 0;
if ([selectedSite isKindOfClass:[MPGeneratedSiteEntity class]])
counter = ((MPGeneratedSiteEntity *)selectedSite).counter;
PearlNotMainQueue( ^{
NSString *typeContent = [MPAlgorithmDefault generatePasswordForSiteNamed:name ofType:cellType
withCounter:counter usingKey:[MPiOSAppDelegate get].key];
NSString *typeContent = [MPAlgorithmDefault mpwTemplateForSiteNamed:name ofType:cellType
withCounter:counter usingKey:[MPiOSAppDelegate get].key];
PearlMainQueue( ^{
[(UITextField *)[[tableView cellForRowAtIndexPath:indexPath] viewWithTag:2] setText:typeContent];
@@ -104,8 +104,8 @@
NSAssert( self.navigationController.topViewController == self, @"Not the currently active navigation item." );
MPSiteType type = [self typeAtIndexPath:indexPath];
if (type == (MPSiteType)NSNotFound)
MPResultType type = [self typeAtIndexPath:indexPath];
if (type == (MPResultType)NSNotFound)
// Selected a non-type row.
return;
@@ -113,28 +113,28 @@
[self.navigationController popViewControllerAnimated:YES];
}
- (MPSiteType)typeAtIndexPath:(NSIndexPath *)indexPath {
- (MPResultType)typeAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: {
// Generated
switch (indexPath.row) {
case 0:
return (MPSiteType)NSNotFound;
return (MPResultType)NSNotFound;
case 1:
return MPSiteTypeGeneratedMaximum;
return MPResultTypeTemplateMaximum;
case 2:
return MPSiteTypeGeneratedLong;
return MPResultTypeTemplateLong;
case 3:
return MPSiteTypeGeneratedMedium;
return MPResultTypeTemplateMedium;
case 4:
return MPSiteTypeGeneratedBasic;
return MPResultTypeTemplateBasic;
case 5:
return MPSiteTypeGeneratedShort;
return MPResultTypeTemplateShort;
case 6:
return MPSiteTypeGeneratedPIN;
return MPResultTypeTemplatePIN;
case 7:
return (MPSiteType)NSNotFound;
return (MPResultType)NSNotFound;
default: {
Throw( @"Unsupported row: %ld, when selecting generated site type.", (long)indexPath.row );
@@ -146,13 +146,13 @@
// Stored
switch (indexPath.row) {
case 0:
return (MPSiteType)NSNotFound;
return (MPResultType)NSNotFound;
case 1:
return MPSiteTypeStoredPersonal;
return MPResultTypeStatefulPersonal;
case 2:
return MPSiteTypeStoredDevicePrivate;
return MPResultTypeStatefulDevice;
case 3:
return (MPSiteType)NSNotFound;
return (MPResultType)NSNotFound;
default: {
Throw( @"Unsupported row: %ld, when selecting stored site type.", (long)indexPath.row );

View File

@@ -20,6 +20,7 @@
#import "MPAppDelegate_Key.h"
#import "MPAppDelegate_Store.h"
#import "MPStoreViewController.h"
#import "mpw-marshall.h"
@interface MPiOSAppDelegate()<UIDocumentInteractionControllerDelegate>
@@ -177,62 +178,46 @@
return YES;
}
- (void)importSites:(NSString *)importedSitesString {
- (void)importSites:(NSString *)importData {
if ([NSThread isMainThread]) {
PearlNotMainQueue( ^{
[self importSites:importedSitesString];
[self importSites:importData];
} );
return;
}
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
[self importSites:importData askImportPassword:^NSString *(NSString *userName) {
return PearlAwait( ^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:@"Import File's Master Password"
message:strf( @"%@'s export was done using a different master password.\n"
@"Enter that master password to unlock the exported data.", userName )
[PearlAlert showAlertWithTitle:strf( @"Importing Sites For\n%@", userName )
message:@"Enter the master password used to create this export file."
viewStyle:UIAlertViewStyleSecureTextInput
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == [alert_ cancelButtonIndex])
setResult( nil );
else
setResult( [alert_ textFieldAtIndex:0].text );
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
} );
} askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) {
} askUserPassword:^NSString *(NSString *userName) {
return PearlAwait( (id)^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:strf( @"Master Password for\n%@", userName )
message:strf( @"Imports %lu sites, overwriting %lu.",
(unsigned long)importCount, (unsigned long)deleteCount )
[PearlAlert showAlertWithTitle:strf( @"Master Password For\n%@", userName )
message:@"Enter the current master password for this user."
viewStyle:UIAlertViewStyleSecureTextInput
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == [alert_ cancelButtonIndex])
setResult( nil );
else
setResult( [alert_ textFieldAtIndex:0].text );
}
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
} );
} result:^(NSError *error) {
[activityOverlay cancelOverlayAnimated:YES];
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError))
[PearlAlert showError:error.localizedDescription];
}];
switch (result) {
case MPImportResultSuccess:
case MPImportResultCancelled:
break;
case MPImportResultInternalError:
[PearlAlert showError:@"Import failed because of an internal error."];
break;
case MPImportResultMalformedInput:
[PearlAlert showError:@"The import doesn't look like a Master Password export."];
break;
case MPImportResultInvalidPassword:
[PearlAlert showError:@"Incorrect master password for the import sites."];
break;
}
[activityOverlay cancelOverlayAnimated:YES];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
@@ -250,10 +235,9 @@
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
PearlNotMainQueue( ^{
NSString *importHeader = @"# Master Password site export";
NSString *importedSitesString = [UIPasteboard generalPasteboard].string;
if ([importedSitesString length] > [importHeader length] &&
[[importedSitesString substringToIndex:[importHeader length]] isEqualToString:importHeader])
NSString *importData = [UIPasteboard generalPasteboard].string;
MPMarshallInfo *importInfo = mpw_marshall_read_info( importData.UTF8String );
if (importInfo->format != MPMarshallFormatNone)
[PearlAlert showAlertWithTitle:@"Import Sites?" message:
@"We've detected Master Password import sites on your pasteboard, would you like to import them?"
viewStyle:UIAlertViewStyleDefault initAlert:nil
@@ -261,9 +245,10 @@
if (buttonIndex == [alert cancelButtonIndex])
return;
[self importSites:importedSitesString];
[self importSites:importData];
[UIPasteboard generalPasteboard].string = @"";
} cancelTitle:@"No" otherTitles:@"Import Sites", nil];
mpw_marshal_info_free( &importInfo );
} );
[super applicationDidBecomeActive:application];
@@ -449,62 +434,84 @@
return;
}
NSString *exportedSites = [self exportSitesRevealPasswords:revealPasswords];
NSString *message;
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
return PearlAwait( ^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:strf( @"Master Password For:\n%@", userName )
message:@"Enter the user's master password to create an export file."
viewStyle:UIAlertViewStyleSecureTextInput
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
if (buttonIndex_ == [alert_ cancelButtonIndex])
setResult( nil );
else
setResult( [alert_ textFieldAtIndex:0].text );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Export", nil];
} );
} result:^(NSString *mpsites, NSError *error) {
if (!mpsites || error) {
MPError( error, @"Failed to export mpsites." );
[PearlAlert showAlertWithTitle:@"Export Error"
message:error.localizedDescription
viewStyle:UIAlertViewStyleDefault
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay
otherTitles:nil];
return;
}
if (revealPasswords)
message = strf( @"Export of Master Password sites with passwords included.\n\n"
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
else
message = strf( @"Backup of Master Password sites.\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == [sheet cancelButtonIndex])
return;
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
NSString *exportFileName = strf( @"%@ (%@).mpsites",
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
NSString *exportFileName = strf( @"%@ (%@).mpsites",
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == [sheet cancelButtonIndex])
return;
if (buttonIndex == [sheet firstOtherButtonIndex]) {
NSString *message;
if (revealPasswords)
message = strf( @"Export of Master Password sites with passwords included.\n\n"
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
else
message = strf( @"Backup of Master Password sites.\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
if (buttonIndex == [sheet firstOtherButtonIndex]) {
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
attachments:[[PearlEMailAttachment alloc]
initWithContent:[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
mimeType:@"text/plain" fileName:exportFileName],
nil];
return;
}
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
attachments:[[PearlEMailAttachment alloc]
initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
mimeType:@"text/plain" fileName:exportFileName],
nil];
return;
}
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *exportURL = [[applicationSupportURL
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
URLByAppendingPathComponent:exportFileName isDirectory:NO];
NSError *error = nil;
if (![[exportedSites dataUsingEncoding:NSUTF8StringEncoding]
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&error])
MPError( error, @"Failed to write export data to URL %@.", exportURL );
else {
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
self.interactionController.delegate = self;
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
}
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *exportURL = [[applicationSupportURL
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
URLByAppendingPathComponent:exportFileName isDirectory:NO];
NSError *writeError = nil;
if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
else {
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
self.interactionController.delegate = self;
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
}
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
}];
}
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {

11
platform-independent/cli-c/.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
*.o
*.dSYM
mpw
mpw-bench
mpw-tests
TAG
VERSION
mpw-*.tar.gz
mpw-*.tar.gz.sig

View File

@@ -0,0 +1,84 @@
# Native CLI
This is a command-line terminal interface to the Master Password standard implementation.
To use the app, you'll first need to build it, then install it into your system's PATH.
## Building
To build the code to run on your specific system, run the `build` command:
./build
Note that the build depends on your system having certain dependencies already installed.
By default, you'll need to have at least `libsodium`, `libjson-c` and `libncurses` installed.
### Details
The build script comes with a default configuration which can be adjusted. Full details on the build script are available by opening the build script file.
[targets='...'] [mpw_feature=0|1 ...] [CFLAGS='...'] [LDFLAGS='...'] ./build [cc arguments ...]
By default, the build script only builds the `mpw` target. You can specify other targets or `all` to build all available targets. These are the currently available targets:
- `mpw` : The main app. It needs: `mpw_sodium`, optionally supports: `mpw_color`, `mpw_json`.
- `mpw-bench` : A benchmark utility. It needs: `mpw_sodium`.
- `mpw-tests` : An algorithm test suite. It needs: `mpw_sodium`, `mpw_xml`.
It is smart to build the test suite along with the app, eg.:
targets='mpw mpw-tests' ./build
The needed and supported features determine the dependencies that the build will require. The following features exist:
- `mpw_sodium` : Use Sodium for the crypto implementation. It needs libsodium.
- `mpw_json` : Support JSON-based user configuration format. It needs libjson-c.
- `mpw_color` : Show a colorized identicon. It needs libncurses.
- `mpw_xml` : Support XML parsing. It needs libxml2.
By default, all features are enabled. Each feature can be disabled or enabled explicitly by prefixing the build command with an assignment of it to `0` or `1`, eg.:
mpw_color=0 ./build
As a result of this command, you'd build the `mpw` target (which supports `mpw_color`) without color support. The build no longer requires `libncurses` but the resulting `mpw` binary will not have support for colorized identicons.
You can also pass CFLAGS or LDFLAGS to the build, or extra custom compiler arguments as arguments to the build script.
For instance, to add a custom library search path, you could use:
LDFLAGS='-L/usr/local/lib' ./build
## Testing
Once the client is built, you should run a test suite to make sure everything works as intended.
There are currently two test suites:
- `mpw-tests` : Tests the Master Password algorithm implementation.
- `mpw-cli-tests` : Tests the CLI application.
The `mpw-tests` suite is only available if you enabled its target during build (see "Details" above).
The `mpw-cli-tests` is a Bash shell script, hence depends on your system having Bash available.
## Installing
Once you're happy with the result, you can install the `mpw` application into your system's `PATH`.
Generally, all you need to do is copy the `mpw` file into a PATH directory, eg.:
cp mpw /usr/local/bin/
The directory that you should copy the `mpw` file into will depend on your system. Also note that `cp` is a POSIX command, if your system is not a POSIX system (eg. Windows) you'll need to adjust accordingly.
There is also an `install` script to help with this process, though it is a Bash script and therefore requires that you have Bash installed:
./install
After installing, you should be able to run `mpw` and use it from anywhere in the terminal:
mpw -h
mpw google.com

View File

@@ -1,16 +1,19 @@
#!/usr/bin/env bash
#
# TROUBLESHOOTING
# - If you see 'undefined reference to `AES_encrypt'',
# make sure you have openssl installed.
# If libcrypto.a is in a non-standard directory, try ./build -L[your-lib-dir]
# - If you see 'undefined reference to `clock_gettime'',
# try ./build -lrt instead.
# - If you see 'x86.S:202: Error: junk at end of line, first unrecognized character is `,'',
# try commenting the line in lib/bcrypt/x86.S.
# - Take a look at the "Optional features" section. Some features have dependencies,
# either make sure you have them or disable those features.
# eg. mpw_color=0 ./build
# USAGE
# [targets='...'] [mpw_feature=0|1 ...] [CFLAGS='...'] [LDFLAGS='...'] ./build [cc arguments ...]
#
# By default, you should only need to run ./build
#
# You can customize the targets that are built using targets='...'. Use targets='all' to build all targets.
# By default, we only build the 'mpw' target.
# See targets_all for all possible targets as well as the features they support and require.
#
# Several features can be enabled or disabled using feature flags.
# See the Features section for an overview of the features, their default setting, their meaning and their dependencies.
# You will need to have each of the feature's dependencies installed for the build to succeed with that feature enabled.
#
# Finally, the C compiler can be tuned using CFLAGS, LDFLAGS and compiler arguments passed to the script.
#
# BUGS
# masterpassword@lyndir.com
@@ -24,333 +27,110 @@ set -e
### CONFIGURATION
# Targets to build.
if [[ $targets ]]; then
read -ra targets <<< "$targets"
else
# Default targets.
# Modify here or override using targets='mpw mpw-bench' ./build
targets=(
mpw # C CLI version of Master Password, requires libsodium or openssl-dev.
#mpw-bench # C CLI Master Password benchmark utility.
#mpw-tests # C Master Password algorithm test suite, requires libxml2.
)
fi
targets_all=(
mpw # C CLI version of Master Password (needs: mpw_sodium, optional: mpw_color, mpw_json).
mpw-bench # C CLI Master Password benchmark utility (needs: mpw_sodium).
mpw-tests # C Master Password algorithm test suite (needs: mpw_sodium, mpw_xml).
)
targets_default='mpw' # Override with: targets='...' ./build
# 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.
# Features.
mpw_sodium=${mpw_sodium:-1} # Implement crypto functions with sodium (depends on libsodium).
mpw_json=${mpw_json:-1} # Support JSON-based user configuration format (depends on libjson-c).
mpw_color=${mpw_color:-1} # Colorized identicon (depends on libncurses).
mpw_xml=${mpw_xml:-1} # XML parsing (depends on libxml2).
# Default build flags.
export CFLAGS="-O3 $CFLAGS"
export LDFLAGS="$LDFLAGS"
cflags=( -O3 $CFLAGS )
ldflags=( $LDFLAGS )
# Version.
if { mpw_version=$(git describe --match '*-cli*' --long --dirty --broken) || mpw_version=$(<VERSION); } 2>/dev/null; then
CFLAGS+=" -DMP_VERSION=$mpw_version"
cflags+=( -D"MP_VERSION=$mpw_version" )
fi
echo 2>&1 "Building mpw version ${mpw_version:-<unknown>}..."
# Distribution specific configuration.
# Homebrew - openssl for scrypt
if hash brew 2>/dev/null; then
opensslPath=$(brew --prefix openssl)
CFLAGS+=" -I$opensslPath/include"
LDFLAGS+=" -L$opensslPath/lib"
fi
### DEPENDENCIES
digest() {
openssl sha -sha256 -binary < "$1" | od -t x1 -An -v | tr -d '[:space:]'
}
fetch() {
if hash wget 2>/dev/null; then
wget -O "${1##*/}" "$1"
elif hash curl 2>/dev/null; then
curl "$1" > "${1##*/}"
fi
}
unpack() {
printf 'Verifying package: %s, against digest: %s...' "$1" "$2"
[[ $(digest "$1") = $2 ]] || {
printf ' mismatch!\n'
echo 2>&1 "Downloaded package doesn't match digest."
exit 1
}
printf ' OK!\n'
if [[ $1 = *.tar.gz || $1 = *.tgz ]]; then
tar -xvzf "$1"
elif [[ $1 = *.tar.bz2 || $1 = *.tbz2 ]]; then
tar -xvjf "$1"
elif [[ $1 = *.tar ]]; then
tar -xvf "$1"
else
echo 2>&1 "Don't know how to unpack: $1"
fi
files=( * )
if [[ -d $files ]] && (( ${#files[@]} == 1 )); then
mv "$files"/* .
rmdir "$files"
fi
}
fetchSource() (
local name=${PWD##*/}
source .source
if [[ -e .unpacked ]]; then
true
elif [[ $pkg && -e "${pkg##*/}" ]]; then
[[ -e src ]] || {
echo
echo "Unpacking: $name, using package..."
( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" )
touch .unpacked
}
elif [[ $git ]] && hash git 2>/dev/null; then
[[ -e .git ]] || {
echo
echo "Fetching: $name, using git..."
git clone "$git" src
touch .unpacked
}
elif [[ $svn ]] && hash git 2>/dev/null && [[ -x "$(git --exec-path)/git-svn" ]]; then
[[ -e .git ]] || {
echo
echo "Fetching: $name, using git-svn..."
git svn clone --prefix=origin/ --stdlayout "$svn" src
touch .unpacked
}
elif [[ $svn ]] && hash svn 2>/dev/null; then
[[ -e .svn ]] || {
echo
echo "Fetching: $name, using svn..."
svn checkout "$svn/trunk" src
touch .unpacked
}
elif [[ $pkg ]]; then
[[ -e src ]] || {
echo
echo "Fetching: $name, using package..."
fetch "$pkg"
( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" )
touch .unpacked
}
else
echo >&2 "error: Missing git-svn or svn."
echo >&2 "error: Please install either or manually check out the sources"
echo >&2 "error: from: $home"
echo >&2 "error: into: $PWD/src"
exit 1
fi
if [[ ! -e .patched ]] && (( ${#patches[@]} )); then
pushd src
for patch in "${patches[@]}"; do
echo
echo "Patching: $name, for $patch..."
patch -p0 < "../$patch.patch"
done
popd
touch .patched
fi
)
depend() {
local name=$1
echo
echo "Checking dependency: $name..."
[[ -e "lib/include/$name" ]] && return
pushd "lib/$name"
fetchSource
pushd "src"
echo
echo "Configuring dependency: $name..."
if [[ -e configure.ac ]]; then
if [[ ! -e configure ]]; then
# create configure using autotools.
if ! hash aclocal || ! hash automake; then
echo >&2 "Need autotools to build $name. Please install automake and autoconf."
exit 1
fi
aclocal
autoheader
autoconf
mkdir -p config.aux
automake --add-missing
fi
fi
if [[ -e configure ]]; then
./configure
fi
echo
echo "Building dependency: $name..."
if [[ -e Makefile ]]; then
if ! hash make; then
echo >&2 "Need make to build $name. Please install GNU make."
exit 1
fi
make
install -d "../../include/$name/"
find . -name '*.h' -exec install -m 444 {} "../../include/$name/" \;
else
echo >&2 "error: Don't know how to build: $name"
exit 1
fi
popd
popd
}
depend_scrypt() {
if (( mpw_sodium )) && haslib sodium; then
if [[ $CFLAGS != *HAS_SODIUM=1* ]]; then
CFLAGS+=" -DHAS_SODIUM=1"
LDFLAGS+=" -lsodium"
fi
return
fi
depend scrypt
if [[ $CFLAGS != *HAS_CPERCIVA=1* ]]; then
local objects=(
"lib/scrypt/src/libcperciva/"*/*.o
"lib/scrypt/src/lib/crypto/"*.o
)
CFLAGS+=" -DHAS_CPERCIVA=1"
LDFLAGS+=" -Llib/scrypt/src ${objects[*]}"
fi
}
echo 2>&1 "Current mpw source version ${mpw_version:-<unknown>}..."
### MPW
### TARGET: MPW
mpw() {
depend_scrypt
# dependencies
use_mpw_sodium
use_mpw_color
use_mpw_json
echo
echo "Building target: $target..."
local CFLAGS=(
$CFLAGS
# target
cflags=(
"${cflags[@]}"
# library paths
-I"lib/include"
# mpw paths
-I"core" -I"cli"
)
local LDFLAGS=(
$LDFLAGS
# link libraries
-l"crypto"
ldflags=(
"${ldflags[@]}"
)
# optional features
(( mpw_color )) && CFLAGS+=( -DMPW_COLOR ) LDFLAGS+=( -l"curses" )
(( mpw_json )) && CFLAGS+=( -DMPW_JSON ) LDFLAGS+=( -l"json-c" )
cc "${CFLAGS[@]}" "$@" -c core/base64.c -o core/base64.o
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[@]}" "$@" -c core/mpw-marshall-util.c -o core/mpw-marshall-util.o
cc "${CFLAGS[@]}" "$@" -c core/mpw-marshall.c -o core/mpw-marshall.o
cc "${CFLAGS[@]}" "$@" "core/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" "core/mpw-marshall-util.o" "core/mpw-marshall.o" \
"${LDFLAGS[@]}" "cli/mpw-cli.c" -o "mpw"
echo "done! Now run ./install or use ./mpw"
# build
cc "${cflags[@]}" "$@" "core/base64.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" "core/mpw-marshall-util.c" "core/mpw-marshall.c" "cli/mpw-cli-util.c" \
"${ldflags[@]}" "cli/mpw-cli.c" -o "mpw"
echo "done! You can now run ./mpw-cli-tests, ./install or use ./$_"
}
### MPW-BENCH
### TARGET: MPW-BENCH
mpw-bench() {
depend_scrypt
depend bcrypt
# dependencies
use_mpw_sodium
echo
echo "Building target: $target..."
local CFLAGS=(
$CFLAGS
# target
cflags=(
"${cflags[@]}"
# library paths
-I"lib/include"
# mpw paths
-I"core" -I"cli"
)
local LDFLAGS=(
$LDFLAGS
# bcrypt
"lib/bcrypt/src/crypt_blowfish.o"
"lib/bcrypt/src/crypt_gensalt.o"
"lib/bcrypt/src/wrapper.o"
"lib/bcrypt/src/x86.o"
# library paths
-L"lib/bcrypt/src"
# link libraries
-l"crypto"
ldflags=(
"${ldflags[@]}"
)
cc "${CFLAGS[@]}" "$@" -c core/base64.c -o core/base64.o
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/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \
"${LDFLAGS[@]}" "cli/mpw-bench.c" -o "mpw-bench"
echo "done! Now use ./mpw-bench"
# build
cc "${cflags[@]}" "$@" "core/base64.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" \
"${ldflags[@]}" "cli/mpw-bench.c" -o "mpw-bench"
echo "done! You can now use ./$_"
}
### MPW-TESTS
### TARGET: MPW-TESTS
mpw-tests() {
depend_scrypt
# dependencies
use_mpw_xml
use_mpw_sodium
echo
echo "Building target: $target..."
local CFLAGS=(
$CFLAGS
# target
cflags=(
"${cflags[@]}"
# library paths
-I"lib/include"
-I"/usr/include/libxml2"
-I"/usr/local/include/libxml2"
# mpw paths
-I"core" -I"cli"
)
local LDFLAGS=(
$LDFLAGS
# link libraries
-l"crypto" -l"xml2"
ldflags=(
"${ldflags[@]}"
)
cc "${CFLAGS[@]}" "$@" -c core/base64.c -o core/base64.o
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[@]}" "$@" -c cli/mpw-tests-util.c -o cli/mpw-tests-util.o
cc "${CFLAGS[@]}" "$@" "core/base64.o" "core/mpw-algorithm.o" "core/mpw-types.o" "core/mpw-util.o" \
"${LDFLAGS[@]}" "cli/mpw-tests-util.o" "cli/mpw-tests.c" -o "mpw-tests"
echo "done! Now use ./mpw-tests"
# build
cc "${cflags[@]}" "$@" "core/base64.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" "cli/mpw-tests-util.c" \
"${ldflags[@]}" "cli/mpw-tests.c" -o "mpw-tests"
echo "done! You can now use ./$_"
}
### TARGETS
### TOOLS
haslib() {
cc -l"$1" -x c -o /dev/null - <<< 'int main() { return 0; }'
}
@@ -367,7 +147,59 @@ cc() {
fi
}
echo "Will build targets: ${targets[*]}..."
for target in "${targets[@]}"; do
"$target" "$@"
### DEPENDENCIES
use_mpw_sodium() {
! (( mpw_sodium )) && return
if ! haslib sodium; then
echo >&2 "WARNING: mpw_sodium enabled but missing sodium library, will disable mpw_sodium."
else
echo >&2 "Enabled mpw_sodium (libsodium)."
cflags+=( -D"MPW_SODIUM=1" ) ldflags+=( -l"sodium" )
fi
}
use_mpw_color() {
! (( mpw_color )) && return
if ! haslib curses; then
echo >&2 "WARNING: mpw_color enabled but missing curses library, will disable mpw_color."
else
echo >&2 "Enabled mpw_color (libcurses)."
cflags+=( -D"MPW_COLOR=1" ) ldflags+=( -l"curses" )
fi
}
use_mpw_json() {
! (( mpw_json )) && return
if ! haslib json-c; then
echo >&2 "WARNING: mpw_json enabled but missing json-c library, will disable mpw_json."
else
echo >&2 "Enabled mpw_json (libjson-c)."
cflags+=( -D"MPW_JSON=1" ) ldflags+=( -l"json-c" )
fi
}
use_mpw_xml() {
! (( mpw_xml )) && return
if ! haslib xml2; then
echo >&2 "WARNING: mpw_xml enabled but missing xml2 library, will disable mpw_xml."
else
echo >&2 "Enabled mpw_xml (libxml2)."
cflags+=( -D"MPW_XML=1" -I"/usr/include/libxml2" -I"/usr/local/include/libxml2" ) ldflags+=( -l"xml2" )
fi
}
### BUILD TARGETS
for target in "${targets_all[@]}"; do
if [[ ${targets:-$targets_default} == 'all' || " ${targets:-$targets_default} " = *" $target "* ]]; then
echo
echo "Building target: $target..."
( "$target" "$@" )
fi
done

View File

@@ -0,0 +1,393 @@
/* $OpenBSD: bcrypt.c,v 1.57 2016/08/26 08:25:02 guenther Exp $ */
/*
* Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
* Copyright (c) 1997 Niels Provos <provos@umich.edu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* This password hashing algorithm was designed by David Mazieres
* <dm@lcs.mit.edu> and works as follows:
*
* 1. state := InitState ()
* 2. state := ExpandKey (state, salt, password)
* 3. REPEAT rounds:
* state := ExpandKey (state, 0, password)
* state := ExpandKey (state, 0, salt)
* 4. ctext := "OrpheanBeholderScryDoubt"
* 5. REPEAT 64:
* ctext := Encrypt_ECB (state, ctext);
* 6. RETURN Concatenate (salt, ctext);
*
*/
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "blf.h"
#include "blowfish.h"
/* This implementation is adaptable to current computing power.
* You can have up to 2^31 rounds which should be enough for some
* time to come.
*/
#define BCRYPT_VERSION '2'
#define BCRYPT_MAXSALT 16 /* Precomputation is just so nice */
#define BCRYPT_WORDS 6 /* Ciphertext words */
#define BCRYPT_MINLOGROUNDS 4 /* we have log2(rounds) in salt */
#define BCRYPT_SALTSPACE (7 + (BCRYPT_MAXSALT * 4 + 2) / 3 + 1)
#define BCRYPT_HASHSPACE 61
static int encode_base64(char *, const uint8_t *, size_t);
static int decode_base64(uint8_t *, size_t, const char *);
/*
* Generates a salt for this version of crypt.
*/
static int
bcrypt_initsalt(int log_rounds, uint8_t *salt, size_t saltbuflen) {
uint8_t csalt[BCRYPT_MAXSALT];
if (saltbuflen < BCRYPT_SALTSPACE) {
errno = EINVAL;
return -1;
}
arc4random_buf( csalt, sizeof( csalt ) );
if (log_rounds < 4)
log_rounds = 4;
else if (log_rounds > 31)
log_rounds = 31;
snprintf( (char *)salt, saltbuflen, "$2b$%2.2u$", log_rounds );
encode_base64( (char *)salt + 7, csalt, sizeof( csalt ) );
return 0;
}
/*
* the core bcrypt function
*/
static int
bcrypt_hashpass(const char *key, const uint8_t *salt, char *encrypted,
size_t encryptedlen) {
blf_ctx state;
uint32_t rounds, i, k;
uint16_t j;
size_t key_len;
uint8_t salt_len, logr, minor;
uint8_t ciphertext[4 * BCRYPT_WORDS] = "OrpheanBeholderScryDoubt";
uint8_t csalt[BCRYPT_MAXSALT];
uint32_t cdata[BCRYPT_WORDS];
if (encryptedlen < BCRYPT_HASHSPACE)
goto inval;
/* Check and discard "$" identifier */
if (salt[0] != '$')
goto inval;
salt += 1;
if (salt[0] != BCRYPT_VERSION)
goto inval;
/* Check for minor versions */
switch ((minor = salt[1])) {
case 'a':
key_len = (uint8_t)(strlen( key ) + 1);
break;
case 'b':
/* strlen() returns a size_t, but the function calls
* below result in implicit casts to a narrower integer
* type, so cap key_len at the actual maximum supported
* length here to avoid integer wraparound */
key_len = strlen( key );
if (key_len > 72)
key_len = 72;
key_len++; /* include the NUL */
break;
default:
goto inval;
}
if (salt[2] != '$')
goto inval;
/* Discard version + "$" identifier */
salt += 3;
/* Check and parse num rounds */
if (!isdigit( (unsigned char)salt[0] ) ||
!isdigit( (unsigned char)salt[1] ) || salt[2] != '$')
goto inval;
logr = (uint8_t)((salt[1] - '0') + ((salt[0] - '0') * 10));
if (logr < BCRYPT_MINLOGROUNDS || logr > 31)
goto inval;
/* Computer power doesn't increase linearly, 2^x should be fine */
rounds = 1U << logr;
/* Discard num rounds + "$" identifier */
salt += 3;
if (strlen( (char *)salt ) * 3 / 4 < BCRYPT_MAXSALT)
goto inval;
/* We dont want the base64 salt but the raw data */
if (decode_base64( csalt, BCRYPT_MAXSALT, (char *)salt ))
goto inval;
salt_len = BCRYPT_MAXSALT;
/* Setting up S-Boxes and Subkeys */
Blowfish_initstate( &state );
Blowfish_expandstate( &state, csalt, salt_len,
(uint8_t *)key, (uint16_t)key_len );
for (k = 0; k < rounds; k++) {
Blowfish_expand0state( &state, (uint8_t *)key, (uint16_t)key_len );
Blowfish_expand0state( &state, csalt, salt_len );
}
/* This can be precomputed later */
j = 0;
for (i = 0; i < BCRYPT_WORDS; i++)
cdata[i] = Blowfish_stream2word( ciphertext, 4 * BCRYPT_WORDS, &j );
/* Now do the encryption */
for (k = 0; k < 64; k++)
blf_enc( &state, cdata, BCRYPT_WORDS / 2 );
for (i = 0; i < BCRYPT_WORDS; i++) {
ciphertext[4 * i + 3] = (uint8_t)(cdata[i] & 0xff);
cdata[i] = cdata[i] >> 8;
ciphertext[4 * i + 2] = (uint8_t)(cdata[i] & 0xff);
cdata[i] = cdata[i] >> 8;
ciphertext[4 * i + 1] = (uint8_t)(cdata[i] & 0xff);
cdata[i] = cdata[i] >> 8;
ciphertext[4 * i + 0] = (uint8_t)(cdata[i] & 0xff);
}
snprintf( encrypted, 8, "$2%c$%2.2u$", minor, logr );
encode_base64( encrypted + 7, csalt, BCRYPT_MAXSALT );
encode_base64( encrypted + 7 + 22, ciphertext, 4 * BCRYPT_WORDS - 1 );
bzero( &state, sizeof( state ) );
bzero( ciphertext, sizeof( ciphertext ) );
bzero( csalt, sizeof( csalt ) );
bzero( cdata, sizeof( cdata ) );
return 0;
inval:
errno = EINVAL;
return -1;
}
/*
* user friendly functions
*/
static int
bcrypt_newhash(const char *pass, int log_rounds, char *hash, size_t hashlen) {
uint8_t salt[BCRYPT_SALTSPACE];
if (bcrypt_initsalt( log_rounds, salt, sizeof( salt ) ) != 0)
return -1;
if (bcrypt_hashpass( pass, salt, hash, hashlen ) != 0)
return -1;
bzero( salt, sizeof( salt ) );
return 0;
}
static int __unused
bcrypt_checkpass(const char *pass, const char *goodhash) {
char hash[BCRYPT_HASHSPACE];
if (bcrypt_hashpass( pass, (const uint8_t *)goodhash, hash, sizeof( hash ) ) != 0)
return -1;
if (strlen( hash ) != strlen( goodhash ) ||
timingsafe_bcmp( hash, goodhash, strlen( goodhash ) ) != 0) {
errno = EACCES;
return -1;
}
bzero( hash, sizeof( hash ) );
return 0;
}
/*
* Measure this system's performance by measuring the time for 8 rounds.
* We are aiming for something that takes around 0.1s, but not too much over.
*/
static int __unused
_bcrypt_autorounds(void) {
struct timespec before, after;
int r = 8;
char buf[_PASSWORD_LEN];
time_t duration;
clock_gettime( CLOCK_THREAD_CPUTIME_ID, &before );
bcrypt_newhash( "testpassword", r, buf, sizeof( buf ) );
clock_gettime( CLOCK_THREAD_CPUTIME_ID, &after );
duration = after.tv_sec - before.tv_sec;
duration *= 1000000;
duration += (after.tv_nsec - before.tv_nsec) / 1000;
/* too quick? slow it down. */
while (r < 16 && duration <= 60000) {
r += 1;
duration *= 2;
}
/* too slow? speed it up. */
while (r > 6 && duration > 120000) {
r -= 1;
duration /= 2;
}
return r;
}
/*
* internal utilities
*/
static const uint8_t Base64Code[] =
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static const uint8_t index_64[128] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 0, 1, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 255, 255,
255, 255, 255, 255, 255, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
255, 255, 255, 255, 255, 255, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 255, 255, 255, 255, 255
};
#define CHAR64(c) ( (c) > 127 ? (uint8_t)255 : index_64[(c)])
/*
* read buflen (after decoding) bytes of data from b64data
*/
static int
decode_base64(uint8_t *buffer, size_t len, const char *b64data) {
uint8_t *bp = buffer;
const uint8_t *p = (uint8_t *)b64data;
uint8_t c1, c2, c3, c4;
while (bp < buffer + len) {
c1 = CHAR64( *p );
/* Invalid data */
if (c1 == 255)
return -1;
c2 = CHAR64( *(p + 1) );
if (c2 == 255)
return -1;
*bp++ = (uint8_t)((c1 << 2) | ((c2 & 0x30) >> 4));
if (bp >= buffer + len)
break;
c3 = CHAR64( *(p + 2) );
if (c3 == 255)
return -1;
*bp++ = (uint8_t)(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2));
if (bp >= buffer + len)
break;
c4 = CHAR64( *(p + 3) );
if (c4 == 255)
return -1;
*bp++ = (uint8_t)(((c3 & 0x03) << 6) | c4);
p += 4;
}
return 0;
}
/*
* Turn len bytes of data into base64 encoded data.
* This works without = padding.
*/
static int
encode_base64(char *b64buffer, const uint8_t *data, size_t len) {
uint8_t *bp = (uint8_t *)b64buffer;
const uint8_t *p = data;
uint8_t c1, c2;
while (p < data + len) {
c1 = *p++;
*bp++ = Base64Code[(c1 >> 2)];
c1 = (uint8_t)((c1 & 0x03) << 4);
if (p >= data + len) {
*bp++ = Base64Code[c1];
break;
}
c2 = *p++;
c1 |= (c2 >> 4) & 0x0f;
*bp++ = Base64Code[c1];
c1 = (uint8_t)((c2 & 0x0f) << 2);
if (p >= data + len) {
*bp++ = Base64Code[c1];
break;
}
c2 = *p++;
c1 |= (c2 >> 6) & 0x03;
*bp++ = Base64Code[c1];
*bp++ = Base64Code[c2 & 0x3f];
}
*bp = '\0';
return 0;
}
/*
* classic interface
*/
static uint8_t *
bcrypt_gensalt(uint8_t log_rounds) {
static uint8_t gsalt[BCRYPT_SALTSPACE];
bcrypt_initsalt( log_rounds, gsalt, sizeof( gsalt ) );
return gsalt;
}
static char *
bcrypt(const char *pass, const uint8_t *salt) {
static char gencrypted[BCRYPT_HASHSPACE];
if (bcrypt_hashpass( pass, salt, gencrypted, sizeof( gencrypted ) ) != 0)
return NULL;
return gencrypted;
}

View File

@@ -0,0 +1,81 @@
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
/*
* Blowfish - a fast block cipher designed by Bruce Schneier
*
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _BLF_H_
#define _BLF_H_
/* Schneier specifies a maximum key length of 56 bytes.
* This ensures that every key bit affects every cipher
* bit. However, the subkeys can hold up to 72 bytes.
* Warning: For normal blowfish encryption only 56 bytes
* of the key affect all cipherbits.
*/
#define BLF_N 16 /* Number of Subkeys */
#define BLF_MAXKEYLEN ((BLF_N-2)*4) /* 448 bits */
#define BLF_MAXUTILIZED ((BLF_N+2)*4) /* 576 bits */
/* Blowfish context */
typedef struct BlowfishContext {
u_int32_t S[4][256]; /* S-Boxes */
u_int32_t P[BLF_N + 2]; /* Subkeys */
} blf_ctx;
/* Raw access to customized Blowfish
* blf_key is just:
* Blowfish_initstate( state )
* Blowfish_expand0state( state, key, keylen )
*/
void Blowfish_encipher(blf_ctx *, u_int32_t *, u_int32_t *);
void Blowfish_decipher(blf_ctx *, u_int32_t *, u_int32_t *);
void Blowfish_initstate(blf_ctx *);
void Blowfish_expand0state(blf_ctx *, const u_int8_t *, u_int16_t);
void Blowfish_expandstate(blf_ctx *, const u_int8_t *, u_int16_t, const u_int8_t *, u_int16_t);
/* Standard Blowfish */
void blf_key(blf_ctx *, const u_int8_t *, u_int16_t);
void blf_enc(blf_ctx *, u_int32_t *, u_int16_t);
void blf_dec(blf_ctx *, u_int32_t *, u_int16_t);
void blf_ecb_encrypt(blf_ctx *, u_int8_t *, u_int32_t);
void blf_ecb_decrypt(blf_ctx *, u_int8_t *, u_int32_t);
void blf_cbc_encrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
void blf_cbc_decrypt(blf_ctx *, u_int8_t *, u_int8_t *, u_int32_t);
/* Converts u_int8_t to u_int32_t */
u_int32_t Blowfish_stream2word(const u_int8_t *, u_int16_t, u_int16_t *);
#endif

View File

@@ -0,0 +1,640 @@
/* $OpenBSD: blowfish.c,v 1.19 2015/09/11 09:18:27 guenther Exp $ */
/*
* Blowfish block cipher for OpenBSD
* Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
* All rights reserved.
*
* Implementation advice by David Mazieres <dm@lcs.mit.edu>.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niels Provos.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This code is derived from section 14.3 and the given source
* in section V of Applied Cryptography, second edition.
* Blowfish is an unpatented fast block cipher designed by
* Bruce Schneier.
*/
#if 0
#include <stdio.h> /* used for debugging */
#include <string.h>
#endif
#include "blf.h"
#undef inline
#ifdef __GNUC__
#define inline __inline
#else /* !__GNUC__ */
#define inline
#endif /* !__GNUC__ */
/* Function for Feistel Networks */
#define F(s, x) ((((s)[ (((x)>>24)&0xFF)] \
+ (s)[0x100 + (((x)>>16)&0xFF)]) \
^ (s)[0x200 + (((x)>> 8)&0xFF)]) \
+ (s)[0x300 + ( (x) &0xFF)])
#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n])
void
Blowfish_encipher(blf_ctx *c, u_int32_t *xl, u_int32_t *xr)
{
u_int32_t Xl;
u_int32_t Xr;
u_int32_t *s = c->S[0];
u_int32_t *p = c->P;
Xl = *xl;
Xr = *xr;
Xl ^= p[0];
BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2);
BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4);
BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6);
BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8);
BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10);
BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12);
BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14);
BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16);
*xl = Xr ^ p[17];
*xr = Xl;
}
void
Blowfish_decipher(blf_ctx *c, u_int32_t *xl, u_int32_t *xr)
{
u_int32_t Xl;
u_int32_t Xr;
u_int32_t *s = c->S[0];
u_int32_t *p = c->P;
Xl = *xl;
Xr = *xr;
Xl ^= p[17];
BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15);
BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13);
BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11);
BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9);
BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7);
BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5);
BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3);
BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1);
*xl = Xr ^ p[0];
*xr = Xl;
}
void
Blowfish_initstate(blf_ctx *c)
{
/* P-box and S-box tables initialized with digits of Pi */
static const blf_ctx initstate =
{ {
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a},
{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7},
{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0},
{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}
},
{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
} };
*c = initstate;
}
u_int32_t
Blowfish_stream2word(const u_int8_t *data, u_int16_t databytes,
u_int16_t *current)
{
u_int8_t i;
u_int16_t j;
u_int32_t temp;
temp = 0x00000000;
j = *current;
for (i = 0; i < 4; i++, j++) {
if (j >= databytes)
j = 0;
temp = (temp << 8) | data[j];
}
*current = j;
return temp;
}
void
Blowfish_expand0state(blf_ctx *c, const u_int8_t *key, u_int16_t keybytes)
{
u_int16_t i;
u_int16_t j;
u_int16_t k;
u_int32_t temp;
u_int32_t datal;
u_int32_t datar;
j = 0;
for (i = 0; i < BLF_N + 2; i++) {
/* Extract 4 int8 to 1 int32 from keystream */
temp = Blowfish_stream2word(key, keybytes, &j);
c->P[i] = c->P[i] ^ temp;
}
j = 0;
datal = 0x00000000;
datar = 0x00000000;
for (i = 0; i < BLF_N + 2; i += 2) {
Blowfish_encipher(c, &datal, &datar);
c->P[i] = datal;
c->P[i + 1] = datar;
}
for (i = 0; i < 4; i++) {
for (k = 0; k < 256; k += 2) {
Blowfish_encipher(c, &datal, &datar);
c->S[i][k] = datal;
c->S[i][k + 1] = datar;
}
}
}
void
Blowfish_expandstate(blf_ctx *c, const u_int8_t *data, u_int16_t databytes,
const u_int8_t *key, u_int16_t keybytes)
{
u_int16_t i;
u_int16_t j;
u_int16_t k;
u_int32_t temp;
u_int32_t datal;
u_int32_t datar;
j = 0;
for (i = 0; i < BLF_N + 2; i++) {
/* Extract 4 int8 to 1 int32 from keystream */
temp = Blowfish_stream2word(key, keybytes, &j);
c->P[i] = c->P[i] ^ temp;
}
j = 0;
datal = 0x00000000;
datar = 0x00000000;
for (i = 0; i < BLF_N + 2; i += 2) {
datal ^= Blowfish_stream2word(data, databytes, &j);
datar ^= Blowfish_stream2word(data, databytes, &j);
Blowfish_encipher(c, &datal, &datar);
c->P[i] = datal;
c->P[i + 1] = datar;
}
for (i = 0; i < 4; i++) {
for (k = 0; k < 256; k += 2) {
datal ^= Blowfish_stream2word(data, databytes, &j);
datar ^= Blowfish_stream2word(data, databytes, &j);
Blowfish_encipher(c, &datal, &datar);
c->S[i][k] = datal;
c->S[i][k + 1] = datar;
}
}
}
void
__unused blf_key(blf_ctx *c, const u_int8_t *k, u_int16_t len)
{
/* Initialize S-boxes and subkeys with Pi */
Blowfish_initstate(c);
/* Transform S-boxes and subkeys with key */
Blowfish_expand0state(c, k, len);
}
void
blf_enc(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
{
u_int32_t *d;
u_int16_t i;
d = data;
for (i = 0; i < blocks; i++) {
Blowfish_encipher(c, d, d + 1);
d += 2;
}
}
void
__unused blf_dec(blf_ctx *c, u_int32_t *data, u_int16_t blocks)
{
u_int32_t *d;
u_int16_t i;
d = data;
for (i = 0; i < blocks; i++) {
Blowfish_decipher(c, d, d + 1);
d += 2;
}
}
void
__unused blf_ecb_encrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
{
u_int32_t l, r;
u_int32_t i;
for (i = 0; i < len; i += 8) {
l = (u_int32_t)data[0] << 24 | (u_int32_t)data[1] << 16 | (u_int32_t)data[2] << 8 | (u_int32_t)data[3];
r = (u_int32_t)data[4] << 24 | (u_int32_t)data[5] << 16 | (u_int32_t)data[6] << 8 | (u_int32_t)data[7];
Blowfish_encipher(c, &l, &r);
data[0] = (u_int8_t)(l >> 24 & 0xff);
data[1] = (u_int8_t)(l >> 16 & 0xff);
data[2] = (u_int8_t)(l >> 8 & 0xff);
data[3] = (u_int8_t)(l & 0xff);
data[4] = (u_int8_t)(r >> 24 & 0xff);
data[5] = (u_int8_t)(r >> 16 & 0xff);
data[6] = (u_int8_t)(r >> 8 & 0xff);
data[7] = (u_int8_t)(r & 0xff);
data += 8;
}
}
void
__unused blf_ecb_decrypt(blf_ctx *c, u_int8_t *data, u_int32_t len)
{
u_int32_t l, r;
u_int32_t i;
for (i = 0; i < len; i += 8) {
l = (u_int32_t)data[0] << 24 | (u_int32_t)data[1] << 16 | (u_int32_t)data[2] << 8 | (u_int32_t)data[3];
r = (u_int32_t)data[4] << 24 | (u_int32_t)data[5] << 16 | (u_int32_t)data[6] << 8 | (u_int32_t)data[7];
Blowfish_decipher(c, &l, &r);
data[0] = (u_int8_t)(l >> 24 & 0xff);
data[1] = (u_int8_t)(l >> 16 & 0xff);
data[2] = (u_int8_t)(l >> 8 & 0xff);
data[3] = (u_int8_t)(l & 0xff);
data[4] = (u_int8_t)(r >> 24 & 0xff);
data[5] = (u_int8_t)(r >> 16 & 0xff);
data[6] = (u_int8_t)(r >> 8 & 0xff);
data[7] = (u_int8_t)(r & 0xff);
data += 8;
}
}
void
__unused blf_cbc_encrypt(blf_ctx *c, u_int8_t *iv, u_int8_t *data, u_int32_t len)
{
u_int32_t l, r;
u_int32_t i, j;
for (i = 0; i < len; i += 8) {
for (j = 0; j < 8; j++)
data[j] ^= iv[j];
l = (u_int32_t)data[0] << 24 | (u_int32_t)data[1] << 16 | (u_int32_t)data[2] << 8 | (u_int32_t)data[3];
r = (u_int32_t)data[4] << 24 | (u_int32_t)data[5] << 16 | (u_int32_t)data[6] << 8 | (u_int32_t)data[7];
Blowfish_encipher(c, &l, &r);
data[0] = (u_int8_t)(l >> 24 & 0xff);
data[1] = (u_int8_t)(l >> 16 & 0xff);
data[2] = (u_int8_t)(l >> 8 & 0xff);
data[3] = (u_int8_t)(l & 0xff);
data[4] = (u_int8_t)(r >> 24 & 0xff);
data[5] = (u_int8_t)(r >> 16 & 0xff);
data[6] = (u_int8_t)(r >> 8 & 0xff);
data[7] = (u_int8_t)(r & 0xff);
iv = data;
data += 8;
}
}
void
__unused blf_cbc_decrypt(blf_ctx *c, u_int8_t *iva, u_int8_t *data, u_int32_t len)
{
u_int32_t l, r;
u_int8_t *iv;
u_int32_t i, j;
iv = data + len - 16;
data = data + len - 8;
for (i = len - 8; i >= 8; i -= 8) {
l = (u_int32_t)data[0] << 24 | (u_int32_t)data[1] << 16 | (u_int32_t)data[2] << 8 | (u_int32_t)data[3];
r = (u_int32_t)data[4] << 24 | (u_int32_t)data[5] << 16 | (u_int32_t)data[6] << 8 | (u_int32_t)data[7];
Blowfish_decipher(c, &l, &r);
data[0] = (u_int8_t)(l >> 24 & 0xff);
data[1] = (u_int8_t)(l >> 16 & 0xff);
data[2] = (u_int8_t)(l >> 8 & 0xff);
data[3] = (u_int8_t)(l & 0xff);
data[4] = (u_int8_t)(r >> 24 & 0xff);
data[5] = (u_int8_t)(r >> 16 & 0xff);
data[6] = (u_int8_t)(r >> 8 & 0xff);
data[7] = (u_int8_t)(r & 0xff);
for (j = 0; j < 8; j++)
data[j] ^= iv[j];
iv -= 8;
data -= 8;
}
l = (u_int32_t)data[0] << 24 | (u_int32_t)data[1] << 16 | (u_int32_t)data[2] << 8 | (u_int32_t)data[3];
r = (u_int32_t)data[4] << 24 | (u_int32_t)data[5] << 16 | (u_int32_t)data[6] << 8 | (u_int32_t)data[7];
Blowfish_decipher(c, &l, &r);
data[0] = (u_int8_t)(l >> 24 & 0xff);
data[1] = (u_int8_t)(l >> 16 & 0xff);
data[2] = (u_int8_t)(l >> 8 & 0xff);
data[3] = (u_int8_t)(l & 0xff);
data[4] = (u_int8_t)(r >> 24 & 0xff);
data[5] = (u_int8_t)(r >> 16 & 0xff);
data[6] = (u_int8_t)(r >> 8 & 0xff);
data[7] = (u_int8_t)(r & 0xff);
for (j = 0; j < 8; j++)
data[j] ^= iva[j];
}

View File

@@ -13,7 +13,7 @@
#include <errno.h>
#include <sys/time.h>
#include <bcrypt/ow-crypt.h>
#include "bcrypt.h"
#include "mpw-algorithm.h"
#include "mpw-util.h"
@@ -39,7 +39,7 @@ static const double mpw_showSpeed(struct timeval startTime, const unsigned int i
const double speed = iterations / elapsed;
fprintf( stderr, " done. " );
fprintf( stdout, "%d %s iterations in %llds %lldµs -> %.2f/s\n", iterations, operation, (long long)dsec, (long long)dusec, speed );
fprintf( stdout, "%d %s iterations in %lus %uµs -> %.2f/s\n", iterations, operation, dsec, dusec, speed );
return speed;
}
@@ -61,7 +61,7 @@ int main(int argc, char *const argv[]) {
// Start HMAC-SHA-256
// Similar to phase-two of mpw
uint8_t *sitePasswordInfo = malloc( 128 );
iterations = 3000000;
iterations = 4200000; /* tuned to ~10s on dev machine */
masterKey = mpw_masterKey( fullName, masterPassword, MPAlgorithmVersionCurrent );
if (!masterKey) {
ftl( "Could not allocate master key: %s\n", strerror( errno ) );
@@ -71,7 +71,7 @@ int main(int argc, char *const argv[]) {
for (int i = 1; i <= iterations; ++i) {
free( (void *)mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, 128 ) );
if (modff(100.f * i / iterations, &percent) == 0)
if (modff( 100.f * i / iterations, &percent ) == 0)
fprintf( stderr, "\rhmac-sha-256: iteration %d / %d (%.0f%%)..", i, iterations, percent );
}
const double hmacSha256Speed = mpw_showSpeed( startTime, iterations, "hmac-sha-256" );
@@ -79,32 +79,32 @@ int main(int argc, char *const argv[]) {
// Start BCrypt
// Similar to phase-one of mpw
int bcrypt_cost = 9;
iterations = 1000;
uint8_t bcrypt_rounds = 9;
iterations = 170; /* tuned to ~10s on dev machine */
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
crypt( masterPassword, crypt_gensalt( "$2b$", bcrypt_cost, fullName, strlen( fullName ) ) );
bcrypt( masterPassword, bcrypt_gensalt( bcrypt_rounds ) );
if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d (%.0f%%)..", bcrypt_cost, i, iterations, percent );
if (modff( 100.f * i / iterations, &percent ) == 0)
fprintf( stderr, "\rbcrypt (rounds 10^%d): iteration %d / %d (%.0f%%)..", bcrypt_rounds, i, iterations, percent );
}
const double bcrypt9Speed = mpw_showSpeed( startTime, iterations, "bcrypt9" );
const double bcrypt9Speed = mpw_showSpeed( startTime, iterations, "bcrypt" );
// Start SCrypt
// Phase one of mpw
iterations = 50;
iterations = 50; /* tuned to ~10s on dev machine */
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
free( (void *)mpw_masterKey( fullName, masterPassword, MPAlgorithmVersionCurrent ) );
if (modff(100.f * i / iterations, &percent) == 0)
if (modff( 100.f * i / iterations, &percent ) == 0)
fprintf( stderr, "\rscrypt_mpw: iteration %d / %d (%.0f%%)..", i, iterations, percent );
}
const double scryptSpeed = mpw_showSpeed( startTime, iterations, "scrypt_mpw" );
// Start MPW
// Both phases of mpw
iterations = 50;
iterations = 50; /* tuned to ~10s on dev machine */
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
masterKey = mpw_masterKey( fullName, masterPassword, MPAlgorithmVersionCurrent );
@@ -117,16 +117,16 @@ int main(int argc, char *const argv[]) {
masterKey, siteName, siteCounter, keyPurpose, keyContext, resultType, NULL, MPAlgorithmVersionCurrent ) );
free( (void *)masterKey );
if (modff(100.f * i / iterations, &percent) == 0)
if (modff( 100.f * i / iterations, &percent ) == 0)
fprintf( stderr, "\rmpw: iteration %d / %d (%.0f%%)..", i, iterations, percent );
}
const double mpwSpeed = mpw_showSpeed( startTime, iterations, "mpw" );
// Summarize.
fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" );
fprintf( stdout, " - mpw is %f times slower than hmac-sha-256 (reference: 320000 on an MBP Late 2013).\n", hmacSha256Speed / mpwSpeed );
fprintf( stdout, " - mpw is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / mpwSpeed );
fprintf( stdout, " - scrypt is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / scryptSpeed );
fprintf( stdout, " - mpw is %f times slower than hmac-sha-256.\n", hmacSha256Speed / mpwSpeed );
fprintf( stdout, " - mpw is %f times slower than bcrypt (rounds 10^%d).\n", bcrypt9Speed / mpwSpeed, bcrypt_rounds );
fprintf( stdout, " - scrypt is %f times slower than bcrypt (rounds 10^%d).\n", bcrypt9Speed / scryptSpeed, bcrypt_rounds );
return 0;
}

View File

@@ -0,0 +1,244 @@
//==============================================================================
// 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 "mpw-cli-util.h"
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <errno.h>
#include <sysexits.h>
#include "mpw-util.h"
/** Read the value of an environment variable.
* @return A newly allocated string or NULL if the variable doesn't exist. */
const char *mpw_getenv(const char *variableName) {
char *envBuf = getenv( variableName );
return envBuf? strdup( envBuf ): NULL;
}
/** Use the askpass program to prompt the user.
* @return A newly allocated string or NULL if askpass is not supported or an error occurred. */
char *mpw_askpass(const char *prompt) {
const char *askpass = mpw_getenv( MP_ENV_askpass );
if (!askpass)
return NULL;
int pipes[2];
if (pipe( pipes ) == ERR) {
wrn( "Couldn't pipe: %s\n", strerror( errno ) );
return NULL;
}
pid_t pid = fork();
if (pid == ERR) {
wrn( "Couldn't fork for askpass:\n %s: %s\n", askpass, strerror( errno ) );
return NULL;
}
if (!pid) {
// askpass fork
close( pipes[0] );
if (dup2( pipes[1], STDOUT_FILENO ) == ERR)
ftl( "Couldn't connect pipe to process: %s\n", strerror( errno ) );
else if (execlp( askpass, askpass, prompt, NULL ) == ERR)
ftl( "Couldn't execute askpass:\n %s: %s\n", askpass, strerror( errno ) );
exit( EX_SOFTWARE );
}
close( pipes[1] );
char *answer = mpw_read_fd( pipes[0] );
close( pipes[0] );
int status;
if (waitpid( pid, &status, 0 ) == ERR) {
wrn( "Couldn't wait for askpass: %s\n", strerror( errno ) );
mpw_free_string( &answer );
return NULL;
}
if (WIFEXITED( status ) && WEXITSTATUS( status ) == EXIT_SUCCESS && answer && strlen( answer )) {
// Remove trailing newline.
if (answer[strlen( answer ) - 1] == '\n')
answer[strlen( answer ) - 1] = '\0';
return answer;
}
mpw_free_string( &answer );
return NULL;
}
/** Ask the user a question.
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
const char *mpw_getline(const char *prompt) {
// Get answer from askpass.
char *answer = mpw_askpass( prompt );
if (answer)
return answer;
// Get password from terminal.
fprintf( stderr, "%s ", prompt );
size_t bufSize = 0;
ssize_t lineSize = getline( &answer, &bufSize, stdin );
if (lineSize <= 1) {
mpw_free_string( &answer );
return NULL;
}
// Remove trailing newline.
answer[lineSize - 1] = '\0';
return answer;
}
/** Ask the user for a password.
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
const char *mpw_getpass(const char *prompt) {
// Get password from askpass.
const char *password = mpw_askpass( prompt );
if (password)
return password;
// Get password from terminal.
char *answer = getpass( prompt );
if (!answer)
return NULL;
password = strdup( answer );
bzero( answer, strlen( answer ) );
return password;
}
/** Get the absolute path to the mpw configuration file with the given prefix name and file extension.
* Resolves the file <prefix.extension> as located in the <.mpw.d> directory inside the user's home directory
* or current directory if it couldn't be resolved.
* @return A newly allocated string. */
const char *mpw_path(const char *prefix, const char *extension) {
// Resolve user's home directory.
char *homeDir = NULL;
if (!homeDir)
if ((homeDir = getenv( "HOME" )))
homeDir = strdup( homeDir );
if (!homeDir)
if ((homeDir = getenv( "USERPROFILE" )))
homeDir = strdup( homeDir );
if (!homeDir) {
const char *homeDrive = getenv( "HOMEDRIVE" ), *homePath = getenv( "HOMEPATH" );
if (homeDrive && homePath)
homeDir = strdup( mpw_str( "%s%s", homeDrive, homePath ) );
}
if (!homeDir) {
struct passwd *passwd = getpwuid( getuid() );
if (passwd)
homeDir = strdup( passwd->pw_dir );
}
if (!homeDir)
homeDir = getcwd( NULL, 0 );
// Compose filename.
char *path = strdup( mpw_str( "%s.%s", prefix, extension ) );
// This is a filename, remove all potential directory separators.
for (char *slash; (slash = strstr( path, "/" )); *slash = '_');
// Compose pathname.
if (homeDir) {
const char *homePath = mpw_str( "%s/.mpw.d/%s", homeDir, path );
free( homeDir );
free( path );
if (homePath)
path = strdup( homePath );
}
return path;
}
/** mkdir all the directories up to the directory of the given file path.
* @return true if the file's path exists. */
bool mpw_mkdirs(const char *filePath) {
if (!filePath)
return false;
// The path to mkdir is the filePath without the last path component.
char *pathEnd = strrchr( filePath, '/' );
char *path = pathEnd? strndup( filePath, (size_t)(pathEnd - filePath) ): NULL;
if (!path)
return false;
// Save the cwd and for absolute paths, start at the root.
char *cwd = getcwd( NULL, 0 );
if (*filePath == '/')
chdir( "/" );
// Walk the path.
bool success = true;
for (char *dirName = strtok( path, "/" ); success && dirName; dirName = strtok( NULL, "/" )) {
if (!strlen( dirName ))
continue;
success &= (mkdir( dirName, 0700 ) != ERR || errno == EEXIST) && chdir( dirName ) != ERR;
}
free( path );
if (chdir( cwd ) == ERR)
wrn( "Could not restore cwd:\n %s: %s\n", cwd, strerror( errno ) );
free( cwd );
return success;
}
/** Read until EOF from the given file descriptor.
* @return A newly allocated string or NULL if the read buffer couldn't be allocated or an error occurred. */
char *mpw_read_fd(int fd) {
char *buf = NULL;
size_t blockSize = 4096, bufSize = 0, bufOffset = 0;
ssize_t readSize = 0;
while ((mpw_realloc( &buf, &bufSize, blockSize )) &&
((readSize = read( fd, buf + bufOffset, blockSize )) > 0));
if (readSize == ERR)
mpw_free( &buf, bufSize );
return buf;
}
/** Read the file contents of a given file.
* @return A newly allocated string or NULL if the read buffer couldn't be allocated. */
char *mpw_read_file(FILE *file) {
if (!file)
return NULL;
char *buf = NULL;
size_t blockSize = 4096, bufSize = 0, bufOffset = 0, readSize = 0;
while ((mpw_realloc( &buf, &bufSize, blockSize )) &&
(bufOffset += (readSize = fread( buf + bufOffset, 1, blockSize, file ))) &&
(readSize == blockSize));
return buf;
}

View File

@@ -0,0 +1,64 @@
//==============================================================================
// 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 <stdint.h>
#include <stdbool.h>
#ifndef MP_VERSION
#define MP_VERSION ?
#endif
#define MP_ENV_fullName "MPW_FULLNAME"
#define MP_ENV_algorithm "MPW_ALGORITHM"
#define MP_ENV_format "MPW_FORMAT"
#define MP_ENV_askpass "MPW_ASKPASS"
/** Read the value of an environment variable.
* @return A newly allocated string or NULL if the variable doesn't exist. */
const char *mpw_getenv(const char *variableName);
/** Use the askpass program to prompt the user.
* @return A newly allocated string or NULL if askpass is not supported or an error occurred. */
char *mpw_askpass(const char *prompt);
/** Ask the user a question.
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
const char *mpw_getline(const char *prompt);
/** Ask the user for a password.
* @return A newly allocated string or NULL if an error occurred trying to read from the user. */
const char *mpw_getpass(const char *prompt);
/** Get the absolute path to the mpw configuration file with the given prefix name and file extension.
* Resolves the file <prefix.extension> as located in the <.mpw.d> directory inside the user's home directory
* or current directory if it couldn't be resolved.
* @return A newly allocated string. */
const char *mpw_path(const char *prefix, const char *extension);
/** mkdir all the directories up to the directory of the given file path.
* @return true if the file's path exists. */
bool mpw_mkdirs(const char *filePath);
/** Read until EOF from the given file descriptor.
* @return A newly allocated string or NULL the read buffer couldn't be allocated. */
char *mpw_read_fd(int fd);
/** Read the file contents of a given file.
* @return A newly allocated string or NULL the read buffer couldn't be allocated. */
char *mpw_read_file(FILE *file);

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,7 @@ xmlNodePtr mpw_xmlTestCaseNode(xmlNodePtr testCaseNode, const char *nodeName) {
return child;
// Missing content, try to find parent case.
if (strcmp(nodeName, "parent") == 0)
if (strcmp( nodeName, "parent" ) == 0)
// Was just searching for testCaseNode's parent, none found.
return NULL;
xmlChar *parentId = mpw_xmlTestCaseString( testCaseNode, "parent" );

View File

@@ -56,7 +56,7 @@ int main(int argc, char *const argv[]) {
// 2. calculate the site password.
const char *sitePassword = mpw_siteResult(
masterKey, (char *)siteName, siteCounter, keyPurpose, (char *)keyContext, resultType, NULL, algorithm );
mpw_free( masterKey, MPMasterKeySize );
mpw_free( &masterKey, MPMasterKeySize );
if (!sitePassword) {
ftl( "Couldn't derive site password.\n" );
continue;
@@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) {
}
// Free test case.
mpw_free_string( sitePassword );
mpw_free_string( &sitePassword );
xmlFree( id );
xmlFree( fullName );
xmlFree( masterPassword );

View File

@@ -2,11 +2,11 @@
set -e
cd "${BASH_SOURCE%/*}"
tag=$(git describe --match '*-cli*')
commit=$(git describe --long --dirty --match '*-cli*')
[[ $commit != *-dirty ]] || { echo >&2 "Tree is dirty, first commit any changes."; exit 1; }
tag=$(git describe --exact-match --match '*-cli*') || { echo >&2 "Tree is not at a release tag."; exit 1; }
version=$(git describe --match '*-cli*' --long --dirty --broken)
[[ $version != *-dirty ]] || { echo >&2 "Tree is dirty, first commit any changes."; exit 1; }
mpwArchive=mpw-$commit.tar.gz
mpwArchive=mpw-$version.tar.gz
[[ -e $mpwArchive ]] && echo >&2 "WARNING: $mpwArchive already exists. Will overwrite."
read -n1 -p "Will prepare and release $mpwArchive. Press a key to continue or ^C to abort."
@@ -14,8 +14,9 @@ echo "Cleaning .."
( git clean -ffdx . && cd core && git clean -ffdx . )
echo "Creating archive $mpwArchive .."
git show --show-signature --pretty=format:%H --quiet "$tag" > VERSION
git ls-files -z . | xargs -0 tar -Lcvzf "$mpwArchive"
echo "$version" > VERSION
git show --show-signature --pretty=format:%H --quiet "$tag" > TAG
{ git ls-files -z .; printf '%s\0' VERSION TAG; } | xargs -0 tar -Lcvzf "$mpwArchive"
echo "Creating archive signature $mpwArchive.sig .."
gpg --detach-sign "$mpwArchive"

View File

@@ -45,9 +45,20 @@ fi
echo
inf "You can also save your user name in ~/.bashrc. Leave blank to skip this step."
if MP_FULLNAME=$(ask "Your full name:") && [[ $MP_FULLNAME ]] ; then
printf 'export MP_FULLNAME=%q\n' "$MP_FULLNAME" >> ~/.bashrc
if MPW_FULLNAME=$(ask "Your full name:") && [[ $MPW_FULLNAME ]] ; then
printf 'export MPW_FULLNAME=%q\n' "$MPW_FULLNAME" >> ~/.bashrc
fi
inf "If you have an askpass program you'd like to use, you can specify it here."
inf "An askpass program provides a graphical interface for entering things like your master password."
inf "Leave blank to skip this step and enter passwords using the terminal."
if [[ ! $MPW_ASKPASS ]] && hash ssh-askpass 2>/dev/null; then
MPW_ASKPASS=ssh-askpass
fi
if MPW_ASKPASS=$(ask +"$MPW_ASKPASS" "askpass program:") && [[ $MPW_ASKPASS ]] ; then
printf 'export MPW_ASKPASS=%q\n' "$MPW_ASKPASS" >> ~/.bashrc
fi
echo
inf "To begin using Master Password, type: mpw [site name]"
inf "Shell features installed."
inf "To load these convenience features into your already running shell, type: source ~/.bashrc"
inf "To begin using Master Password, type: mpw -h or mpw my-site-name"

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env bash
cd "${BASH_SOURCE%/*}"
# Tooling
errors=0
mpw_expect() {
local expect=$1; shift
printf '.'
result=$(./mpw -q "$@") err=$?
if (( err )); then
printf >&2 "Error (exit %d) mpw%s\n" "$err" "$(printf ' %q' "$@")"
return $(( ++errors ))
fi
if [[ $result != $expect ]]; then
printf >&2 "Error (got: %s != expected: %s) mpw%s\n" "$result" "$expect" "$(printf ' %q' "$@")"
return $(( ++errors ))
fi
}
# mpw_tests.xml
## V3
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' 'masterpasswordapp.com'
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -C '' 'masterpasswordapp.com'
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'NopaDajh8=Fene' -Fnone -u '⛄' -M 'banana colored duckling' -tlong -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'QesuHirv5-Xepl' -Fnone -u 'Robert Lee Mitchell' -M '⛄' -tlong -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'LiheCuwhSerz6)' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a3 -p 'authentication' -C '' '⛄'
mpw_expect 'wohzaqage' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -p 'identification' 'masterpasswordapp.com'
mpw_expect 'wohzaqage' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a3 -p 'identification' -C '' 'masterpasswordapp.com'
mpw_expect 'xin diyjiqoja hubu' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -p 'recovery' 'masterpasswordapp.com'
mpw_expect 'xin diyjiqoja hubu' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a3 -p 'recovery' -C '' 'masterpasswordapp.com'
mpw_expect 'xogx tem cegyiva jab' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a3 -p 'recovery' -C 'question' 'masterpasswordapp.com'
mpw_expect 'W6@692^B1#&@gVdSdLZ@' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmax -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2$Quv' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmed -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WAo2xIg6' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tbasic -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tshort -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect '7662' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tpin -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejraquvo' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejr quv cabsibu tam' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a3 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'XambHoqo6[Peni' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c4294967295 -a3 -p 'authentication' 'masterpasswordapp.com'
## V2
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WaqoGuho2[Xaxw' -Fnone -u '⛄' -M 'banana colored duckling' -tlong -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'QesuHirv5-Xepl' -Fnone -u 'Robert Lee Mitchell' -M '⛄' -tlong -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'LiheCuwhSerz6)' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a2 -p 'authentication' -C '' '⛄'
mpw_expect 'wohzaqage' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a2 -p 'identification' -C '' 'masterpasswordapp.com'
mpw_expect 'xin diyjiqoja hubu' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a2 -p 'recovery' -C '' 'masterpasswordapp.com'
mpw_expect 'xogx tem cegyiva jab' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a2 -p 'recovery' -C 'question' 'masterpasswordapp.com'
mpw_expect 'W6@692^B1#&@gVdSdLZ@' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmax -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2$Quv' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmed -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WAo2xIg6' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tbasic -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tshort -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect '7662' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tpin -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejraquvo' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejr quv cabsibu tam' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a2 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'XambHoqo6[Peni' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c4294967295 -a2 -p 'authentication' 'masterpasswordapp.com'
## V1
mpw_expect 'Jejr5[RepuSosp' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WaqoGuho2[Xaxw' -Fnone -u '⛄' -M 'banana colored duckling' -tlong -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'QesuHirv5-Xepl' -Fnone -u 'Robert Lee Mitchell' -M '⛄' -tlong -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WawiYarp2@Kodh' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a1 -p 'authentication' -C '' '⛄'
mpw_expect 'wohzaqage' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a1 -p 'identification' -C '' 'masterpasswordapp.com'
mpw_expect 'xin diyjiqoja hubu' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a1 -p 'recovery' -C '' 'masterpasswordapp.com'
mpw_expect 'xogx tem cegyiva jab' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a1 -p 'recovery' -C 'question' 'masterpasswordapp.com'
mpw_expect 'W6@692^B1#&@gVdSdLZ@' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmax -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2$Quv' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmed -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'WAo2xIg6' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tbasic -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Jej2' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tshort -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect '7662' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tpin -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejraquvo' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'jejr quv cabsibu tam' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a1 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'XambHoqo6[Peni' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c4294967295 -a1 -p 'authentication' 'masterpasswordapp.com'
## V0
mpw_expect 'Feji5@ReduWosh' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'HajrYudo7@Mamh' -Fnone -u '⛄' -M 'banana colored duckling' -tlong -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'MewmDini0]Meho' -Fnone -u 'Robert Lee Mitchell' -M '⛄' -tlong -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'HahiVana2@Nole' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a0 -p 'authentication' -C '' '⛄'
mpw_expect 'lozwajave' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a0 -p 'identification' -C '' 'masterpasswordapp.com'
mpw_expect 'miy lirfijoja dubu' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a0 -p 'recovery' -C '' 'masterpasswordapp.com'
mpw_expect 'movm bex gevrica jaf' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a0 -p 'recovery' -C 'question' 'masterpasswordapp.com'
mpw_expect 'w1!3bA3icmRAc)SS@lwl' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmax -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Fej7]Jug' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tmed -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'wvH7irC1' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tbasic -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'Fej7' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tshort -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect '2117' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tpin -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'fejrajugo' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tname -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'fejr jug gabsibu bax' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tphrase -c1 -a0 -p 'authentication' -C '' 'masterpasswordapp.com'
mpw_expect 'QateDojh1@Hecn' -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c4294967295 -a0 -p 'authentication' 'masterpasswordapp.com'
# Finish
printf 'Done!\n'
exit "$errors"