2
0

Compare commits

..

100 Commits

Author SHA1 Message Date
Maarten Billemont
344771dbdf Make site available under public/site 2018-04-22 09:33:16 -04:00
Maarten Billemont
d38dba7272 Site has moved to gh-pages. 2018-04-21 16:14:56 -04:00
Maarten Billemont
409f005eec Be a bit more specific about password storage. 2018-04-20 09:10:52 -04:00
Maarten Billemont
df7903e146 Add in video and resources. 2018-04-20 00:24:44 -04:00
Maarten Billemont
49edaef79d Some clean-up. 2018-04-19 23:34:42 -04:00
Maarten Billemont
fcbed9ef01 Improve wording. 2018-04-19 23:28:59 -04:00
Maarten Billemont
3edb414d23 Fix paroller issues. 2018-04-19 23:17:08 -04:00
Maarten Billemont
d779c21cc1 WIP - parallax hero image. 2018-04-19 15:49:04 -04:00
Maarten Billemont
8d32bc56ae Small print in footer. 2018-04-19 15:48:29 -04:00
Maarten Billemont
9d03ed06c3 Footer. 2018-04-18 12:18:58 -04:00
Maarten Billemont
ee290e5c14 Extensive content and style update. 2018-04-18 11:54:30 -04:00
Maarten Billemont
789761b177 Updates to new site layout. 2018-04-16 17:17:16 -04:00
Maarten Billemont
cd0876d58a project.lyndir.com is no longer in use, migrated to github. 2018-04-16 10:02:27 -04:00
Maarten Billemont
bfae4da56c Update to latest Xcode warnings. 2018-04-03 09:53:40 -04:00
Maarten Billemont
f342ed5940 Only define loggers if not yet provided. 2018-04-03 09:10:15 -04:00
Maarten Billemont
c7373fee28 Improve output alignment. 2018-04-03 08:50:45 -04:00
Maarten Billemont
44b2955652 Ignore cmake files. 2018-04-03 08:50:25 -04:00
Maarten Billemont
8a4af69008 Fix mpw_log override for iOS/macOS. 2018-03-24 16:49:55 -04:00
Maarten Billemont
6650382e19 Fix overriding of ftl behaviour for tests. 2018-03-24 15:27:13 -04:00
Maarten Billemont
a1f5e0ba1c Harmonize log methods by removing trailing \n. 2018-03-24 15:27:04 -04:00
Maarten Billemont
035bb6b285 Swift-compatible typing. 2018-03-24 15:25:43 -04:00
Maarten Billemont
c0107fb90e Move mpw_identicon into mpw-algorithm.h & define colors. 2018-03-24 15:25:32 -04:00
Maarten Billemont
138be9d14c Respect the user's default type when creating new sites. 2018-03-05 08:14:11 -05:00
Maarten Billemont
61f474217b Update Travis Xcode. 2018-02-18 23:59:15 -05:00
Maarten Billemont
d31c5eed0a Merge branch 'master' of github.com:Lyndir/MasterPassword 2018-02-18 23:47:35 -05:00
Maarten Billemont
5060de689b Match template character to source. 2018-02-18 23:47:23 -05:00
Maarten Billemont
b95424ddf3 Update macOS project configuration. 2018-02-10 23:43:42 -05:00
Maarten Billemont
e40a442a30 Build fixes, improvements and project cleanup. 2018-02-10 23:29:55 -05:00
Maarten Billemont
b5134a9faf Updates to project configuration. 2018-02-10 21:07:00 -05:00
Maarten Billemont
a791d449ce Updated info.plist syntax. 2018-02-10 20:52:30 -05:00
Maarten Billemont
43e1a9d539 Improved checks for external build scripts. 2018-02-10 20:51:50 -05:00
Maarten Billemont
e91f80d10e Remove externals. 2018-02-08 12:31:31 -05:00
Maarten Billemont
9db855c7fb Add documentation PDFs. 2018-01-06 15:44:20 -05:00
Maarten Billemont
2dc3636b26 Support empty site names. 2018-01-06 15:42:26 -05:00
Maarten Billemont
4d9df012f6 Fix check for whether there is a directory in the path. 2017-11-21 22:33:42 -05:00
Maarten Billemont
ff9d0d75ef Make additional libraries optional. 2017-11-06 21:58:51 -05:00
Maarten Billemont
4e160b3b33 libcurses is sometimes split off from libtinfo. 2017-11-06 18:41:18 -05:00
Maarten Billemont
5048acc9f9 cmake's find_package is case sensitive & be smarter about git. 2017-11-06 18:38:36 -05:00
Maarten Billemont
1841541bc4 --broken is new and not really needed. 2017-11-06 15:38:30 -05:00
Maarten Billemont
11d9af3844 Fix generation of valid random passwords for state test. 2017-11-06 14:14:37 -05:00
Maarten Billemont
e30b618241 Allow cmake to look up the mpw version from git. 2017-11-06 12:50:15 -05:00
Maarten Billemont
966327571d Fix cmake when VERSION doesn't exist. 2017-11-06 12:22:13 -05:00
Maarten Billemont
303d50c197 Use FindCurses.cmake to discover the right way to build with libcurses. 2017-11-06 12:07:13 -05:00
Maarten Billemont
bcdfdec211 Notify builds on Matrix channel #masterpassword:lyndir.com 2017-10-06 15:32:33 -04:00
Maarten Billemont
fb769d2ac5 Release mpw-2.6-cli-4. 2017-10-06 15:21:07 -04:00
Maarten Billemont
f8043ae16d Fix chdir test & make curses work when stdout is redirected. 2017-10-06 14:59:29 -04:00
Maarten Billemont
7150f2f5c5 Fix test to match context against question keyword. 2017-10-06 14:58:42 -04:00
Maarten Billemont
81bd2e3065 Make mpw_mkpw symlinkable. 2017-10-06 13:33:08 -04:00
Maarten Billemont
78c9618807 Test chdir. 2017-09-26 11:07:02 -04:00
Maarten Billemont
bed8939b8a Debug issue in testSiteState 2017-09-25 18:35:57 -04:00
Maarten Billemont
9443d93500 Remove MPW_COLOR from core, safer decryption, more standard password input & curses dialog. 2017-09-25 18:34:12 -04:00
Maarten Billemont
877eba66be strdup also isn't standard. 2017-09-25 10:51:14 -04:00
Maarten Billemont
3af8aba40c Make source more standard C11 w/POSIX:2008 CLI. 2017-09-25 10:33:31 -04:00
Maarten Billemont
7ece02c73d Remove stale 2.6-cli-3 2017-09-25 03:05:38 -04:00
Maarten Billemont
ebbd2b3ac4 Re-distribute 2.6-cli-3 with standard build fixes. 2017-09-25 03:01:24 -04:00
Maarten Billemont
a85eff4277 Include semi-standard getline. 2017-09-25 02:59:09 -04:00
Maarten Billemont
98f1c776be Fix some warnings. 2017-09-25 02:56:37 -04:00
Maarten Billemont
6b554c67ed More standard memset_s 2017-09-25 02:53:34 -04:00
Maarten Billemont
f2ae35080d mpw-2.6-cli-3 release. 2017-09-24 15:40:19 -04:00
Maarten Billemont
0ff6c93a95 Document default key size. 2017-09-24 13:18:33 -04:00
Maarten Billemont
9147600b97 Travis cache doesn't need to be disabled anymore. 2017-09-24 13:14:58 -04:00
Maarten Billemont
fafe56166e bzero is nonstandard. Replace with memset_s. 2017-09-24 13:14:16 -04:00
Maarten Billemont
0a024b2594 AES-CBC needs PKCS#7 padding. 2017-09-24 13:06:19 -04:00
Maarten Billemont
b4c2a393f1 Clean up aes state, default to 512 key size, improve log output. 2017-09-24 12:00:38 -04:00
Maarten Billemont
39dcef46d2 Show in Travis log why tests fail. 2017-09-24 00:26:58 -04:00
Maarten Billemont
d6a88583f5 AES needs to be CBC, not CTR. 2017-09-23 20:14:53 -04:00
Maarten Billemont
1c17b84dcf Some tweaks for Travis. 2017-09-23 19:24:06 -04:00
Maarten Billemont
cecaf1b5cc Log fixes, test improvements and some refactoring. 2017-09-23 19:11:06 -04:00
Maarten Billemont
888338e107 Fix siteKey algorithm for siteState. 2017-09-23 19:09:19 -04:00
Maarten Billemont
32055abf29 ciphers.plist is no longer needed. 2017-09-22 20:08:46 -04:00
Maarten Billemont
0f72dffaf1 Updated keyID in test case. 2017-09-22 19:05:59 -04:00
Maarten Billemont
5d1be43b65 Deep Java refactoring to match the C API logic and clean up some OO oddities. 2017-09-22 19:03:50 -04:00
Maarten Billemont
dc7089c38c mpw-tests was not checking mpw_tests.xml's keyID. 2017-09-22 18:23:08 -04:00
Maarten Billemont
34540f0844 Finish rename Marshall -> Marshal. 2017-09-22 15:20:14 -04:00
Maarten Billemont
e818713484 Fix filenames in build 2017-09-22 14:21:31 -04:00
Maarten Billemont
6e2289994c Fix gradle build with missing local.properties. 2017-09-21 10:32:38 -04:00
Maarten Billemont
05a9ba46d0 Marshal refactoring to prepare for new format. 2017-09-20 17:45:49 -04:00
Maarten Billemont
70bb30ba0c Skip masterpassword-android if not set up to build it. 2017-09-20 16:52:20 -04:00
Maarten Billemont
444d7e9b35 Source fix-ups: single l marshal, copyright, .travis. 2017-09-20 12:43:03 -04:00
Maarten Billemont
47164c7a92 Marshal has only one l. 2017-09-20 10:48:04 -04:00
Maarten Billemont
ad00ceb4ce Harmonize C/Java code more, WIP crypt/derive in Java. 2017-09-19 14:52:43 -04:00
Maarten Billemont
473e3ca11f Run gradle test in Travis. 2017-09-19 13:46:27 -04:00
Maarten Billemont
35c0431cec Update Java to match C's internal changes. 2017-09-19 13:45:51 -04:00
Maarten Billemont
70c784db83 Update MP_FULLNAME in mpw.bashrc. 2017-09-15 13:24:45 -04:00
Maarten Billemont
d448099a2d -s is -P now. 2017-09-14 23:14:00 -04:00
Maarten Billemont
e3a7ea57e0 Type key is K, subkey context is not bound by BYTES_MIN/MAX. 2017-09-14 23:03:39 -04:00
Maarten Billemont
fa6133200e Added bashlib. 2017-09-14 16:44:32 -04:00
Maarten Billemont
dfa67bdca9 Added some scripts to do math on password strength and generate random dictionary passphrases. 2017-09-14 16:31:11 -04:00
Maarten Billemont
8c9c4ef7b2 Describe how to use the cmake alternative build system. 2017-09-10 14:17:06 -04:00
Maarten Billemont
1adb18a7e7 Fixed #206 - 'p' trigger for phrase was missing. 2017-09-10 14:03:56 -04:00
Maarten Billemont
f50fdb7777 Some build tool updates, primarily cmake. 2017-09-10 13:57:14 -04:00
Maarten Billemont
33bf2c93d0 Some fixes to the CSS for videos. 2017-09-08 11:19:10 -04:00
Maarten Billemont
f2abcc9e43 A few fixes to the about video. 2017-09-08 10:31:43 -04:00
Maarten Billemont
5ef69aa045 Make bcrypt code more standard. 2017-09-07 00:05:55 -04:00
Maarten Billemont
1c0f274868 Include for waitpid. 2017-09-06 23:54:52 -04:00
Maarten Billemont
1f592f50a9 Release 2.6-cli-2 2017-09-06 00:34:09 -04:00
Maarten Billemont
30fdb54e94 Fix support for building without MPW_JSON enabled. 2017-09-06 00:32:57 -04:00
Maarten Billemont
4f552be5a9 Update cmake for source and improve feature checking in ./build 2017-09-06 00:31:49 -04:00
Maarten Billemont
1439df9f9a Add license headers to cli source files. 2017-09-04 19:37:36 -04:00
Maarten Billemont
e676a0e258 Release 2.6-cli-1. 2017-09-04 14:50:57 -04:00
409 changed files with 25686 additions and 24520 deletions

6
.gitmodules vendored
View File

@@ -25,3 +25,9 @@
[submodule "platform-darwin/External/libjson-c"] [submodule "platform-darwin/External/libjson-c"]
path = platform-darwin/External/libjson-c path = platform-darwin/External/libjson-c
url = https://github.com/lhunath/json-c.git url = https://github.com/lhunath/json-c.git
[submodule "public/site"]
path = public/site
url = https://github.com/Lyndir/MasterPassword.git
branch = gh-pages
shallow = true
update = none

View File

@@ -1,10 +1,20 @@
language: objective-c language: objective-c
osx_image: xcode8.3 os: osx
osx_image: xcode9.2
env: TERM=dumb SHLVL=0 env: TERM=dumb SHLVL=0
git: git:
submodules: true submodules: true
script: script:
- "( brew install libsodium json-c )" - "( brew install libsodium json-c )"
- "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )" - "( cd ./platform-independent/cli-c && ./clean && targets='mpw mpw-bench mpw-tests' ./build && ./mpw-tests && ./mpw-cli-tests )"
- "( cd ./gradle && ./gradlew --info clean test )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )" - "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )" - "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' )"
notifications:
webhooks:
urls:
- "https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MGxodW5hdGglM0FseW5kaXIuY29tLyUyMWR2S1JpaW1uc0Z3dWdseEpHSyUzQWx5bmRpci5jb20"
on_success: change # always|never|change
on_failure: always
on_start: never

606
core/c/aes.c Normal file
View File

@@ -0,0 +1,606 @@
/*
Source: https://github.com/kokke/tiny-AES-c
This is an implementation of the AES algorithm, specifically ECB and CBC mode.
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
The implementation is verified against the test vectors in:
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
ECB-AES128
----------
plain-text:
6bc1bee22e409f96e93d7e117393172a
ae2d8a571e03ac9c9eb76fac45af8e51
30c81c46a35ce411e5fbc1191a0a52ef
f69f2445df4f9b17ad2b417be66c3710
key:
2b7e151628aed2a6abf7158809cf4f3c
resulting cipher
3ad77bb40d7a3660a89ecaf32466ef97
f5d3d58503b9699de785895a96fdbaaf
43b1cd7f598ece23881b00e3ed030688
7b0c785e27e8ad3f8223207104725dd4
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
You should pad the end of the string with zeros if this is not the case.
For AES192/256 the block size is proportionally larger.
*/
/*****************************************************************************/
/* Includes: */
/*****************************************************************************/
#include <string.h>
#include "aes.h"
#include "mpw-util.h"
/*****************************************************************************/
/* Defines: */
/*****************************************************************************/
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
#define Nb 4
#if defined(AES_256) && (AES_256 == 1)
#define Nk 8
#define KEYLEN 32
#define Nr 14
#define keyExpSize 240
#elif defined(AES_192) && (AES_192 == 1)
#define Nk 6
#define KEYLEN 24
#define Nr 12
#define keyExpSize 208
#elif defined(AES_128) && (AES_128 == 1)
#define Nk 4 // The number of 32 bit words in a key.
#define KEYLEN 16 // Key length in bytes
#define Nr 10 // The number of rounds in AES Cipher.
#define keyExpSize 176
#else
#error Must define either AES_128, AES_192 or AES_256.
#endif
// jcallan@github points out that declaring Multiply as a function
// reduces code size considerably with the Keil ARM compiler.
// See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3
#ifndef MULTIPLY_AS_A_FUNCTION
#define MULTIPLY_AS_A_FUNCTION 0
#endif
/*****************************************************************************/
/* Private variables: */
/*****************************************************************************/
// state - array holding the intermediate results during decryption.
typedef uint8_t state_t[4][4];
static state_t* state;
// The array that stores the round keys.
static uint8_t RoundKey[keyExpSize];
// The Key input to the AES Program
static const uint8_t* Key;
#if defined(AES_CBC) && AES_CBC
// Initial Vector used only for CBC mode
static uint8_t* Iv;
#endif
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
// The numbers below can be computed dynamically trading ROM for RAM -
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
static const uint8_t sbox[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
static const uint8_t rsbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
// The round constant word array, Rcon[i], contains the values given by
// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
static const uint8_t Rcon[11] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
/*
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES128-C/pull/12),
* that you can remove most of the elements in the Rcon array, because they are unused.
*
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
*
* "Only the first some of these constants are actually used up to rcon[10] for AES-128 (as 11 round keys are needed),
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
*
* ... which is why the full array below has been 'disabled' below.
*/
#if 0
static const uint8_t Rcon[256] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d };
#endif
/*****************************************************************************/
/* Private functions: */
/*****************************************************************************/
static uint8_t getSBoxValue(uint8_t num)
{
return sbox[num];
}
static uint8_t getSBoxInvert(uint8_t num)
{
return rsbox[num];
}
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
static void KeyExpansion(void)
{
uint32_t i;
uint8_t k, tempa[4]; // Used for the column/row operations
// The first round key is the key itself.
for (i = 0; i < Nk; ++i)
{
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
}
// All other round keys are found from the previous round keys.
//i == Nk
for (; i < Nb * (Nr + 1); ++i)
{
{
tempa[0]=RoundKey[(i-1) * 4 + 0];
tempa[1]=RoundKey[(i-1) * 4 + 1];
tempa[2]=RoundKey[(i-1) * 4 + 2];
tempa[3]=RoundKey[(i-1) * 4 + 3];
}
if (i % Nk == 0)
{
// This function shifts the 4 bytes in a word to the left once.
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
// Function RotWord()
{
k = tempa[0];
tempa[0] = tempa[1];
tempa[1] = tempa[2];
tempa[2] = tempa[3];
tempa[3] = k;
}
// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an output word.
// Function Subword()
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
tempa[0] = tempa[0] ^ Rcon[i/Nk];
}
#if defined(AES256) && (AES256 == 1)
if (i % Nk == 4)
{
// Function Subword()
{
tempa[0] = getSBoxValue(tempa[0]);
tempa[1] = getSBoxValue(tempa[1]);
tempa[2] = getSBoxValue(tempa[2]);
tempa[3] = getSBoxValue(tempa[3]);
}
}
#endif
RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0];
RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1];
RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2];
RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3];
}
}
// This function adds the round key to state.
// The round key is added to the state by an XOR function.
static void AddRoundKey(uint8_t round)
{
uint8_t i,j;
for (i=0;i<4;++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[i][j] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}
}
// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
static void SubBytes(void)
{
uint8_t i, j;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[j][i] = getSBoxValue((*state)[j][i]);
}
}
}
// The ShiftRows() function shifts the rows in the state to the left.
// Each row is shifted with different offset.
// Offset = Row number. So the first row is not shifted.
static void ShiftRows(void)
{
uint8_t temp;
// Rotate first row 1 columns to left
temp = (*state)[0][1];
(*state)[0][1] = (*state)[1][1];
(*state)[1][1] = (*state)[2][1];
(*state)[2][1] = (*state)[3][1];
(*state)[3][1] = temp;
// Rotate second row 2 columns to left
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
// Rotate third row 3 columns to left
temp = (*state)[0][3];
(*state)[0][3] = (*state)[3][3];
(*state)[3][3] = (*state)[2][3];
(*state)[2][3] = (*state)[1][3];
(*state)[1][3] = temp;
}
static uint8_t xtime(uint8_t x)
{
return (uint8_t)((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
// MixColumns function mixes the columns of the state matrix
static void MixColumns(void)
{
uint8_t i;
uint8_t Tmp,Tm,t;
for (i = 0; i < 4; ++i)
{
t = (*state)[i][0];
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ;
Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ;
Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ;
Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ;
}
}
// Multiply is used to multiply numbers in the field GF(2^8)
#if MULTIPLY_AS_A_FUNCTION
static uint8_t Multiply(uint8_t x, uint8_t y)
{
return (((y & 1) * x) ^
((y>>1 & 1) * xtime(x)) ^
((y>>2 & 1) * xtime(xtime(x))) ^
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^
((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
#else
#define Multiply(x, y) (uint8_t) \
( ((y & 1) * x) ^ \
((y>>1 & 1) * xtime(x)) ^ \
((y>>2 & 1) * xtime(xtime(x))) ^ \
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
#endif
// MixColumns function mixes the columns of the state matrix.
// The method used to multiply may be difficult to understand for the inexperienced.
// Please use the references to gain more information.
static void InvMixColumns(void)
{
int i;
uint8_t a, b, c, d;
for (i = 0; i < 4; ++i)
{
a = (*state)[i][0];
b = (*state)[i][1];
c = (*state)[i][2];
d = (*state)[i][3];
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
}
}
// The SubBytes Function Substitutes the values in the
// state matrix with values in an S-box.
static void InvSubBytes(void)
{
uint8_t i,j;
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 4; ++j)
{
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
}
}
}
static void InvShiftRows(void)
{
uint8_t temp;
// Rotate first row 1 columns to right
temp = (*state)[3][1];
(*state)[3][1] = (*state)[2][1];
(*state)[2][1] = (*state)[1][1];
(*state)[1][1] = (*state)[0][1];
(*state)[0][1] = temp;
// Rotate second row 2 columns to right
temp = (*state)[0][2];
(*state)[0][2] = (*state)[2][2];
(*state)[2][2] = temp;
temp = (*state)[1][2];
(*state)[1][2] = (*state)[3][2];
(*state)[3][2] = temp;
// Rotate third row 3 columns to right
temp = (*state)[0][3];
(*state)[0][3] = (*state)[1][3];
(*state)[1][3] = (*state)[2][3];
(*state)[2][3] = (*state)[3][3];
(*state)[3][3] = temp;
}
// Cipher is the main function that encrypts the PlainText.
static void Cipher(void)
{
uint8_t round = 0;
// Add the First round key to the state before starting the rounds.
AddRoundKey(0);
// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr-1 rounds are executed in the loop below.
for (round = 1; round < Nr; ++round)
{
SubBytes();
ShiftRows();
MixColumns();
AddRoundKey(round);
}
// The last round is given below.
// The MixColumns function is not here in the last round.
SubBytes();
ShiftRows();
AddRoundKey(Nr);
}
static void InvCipher(void)
{
uint8_t round=0;
// Add the First round key to the state before starting the rounds.
AddRoundKey(Nr);
// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr-1 rounds are executed in the loop below.
for (round = (Nr - 1); round > 0; --round)
{
InvShiftRows();
InvSubBytes();
AddRoundKey(round);
InvMixColumns();
}
// The last round is given below.
// The MixColumns function is not here in the last round.
InvShiftRows();
InvSubBytes();
AddRoundKey(0);
}
/*****************************************************************************/
/* Public functions: */
/*****************************************************************************/
#if defined(AES_ECB) && (AES_ECB == 1)
void AES_ECB_encrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
{
// Copy input to output, and work in-memory on output
memcpy(output, input, length);
state = (state_t*)output;
Key = key;
KeyExpansion();
// The next function call encrypts the PlainText with the Key using AES algorithm.
Cipher();
mpw_zero( RoundKey, keyExpSize );
}
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
{
// Copy input to output, and work in-memory on output
memcpy(output, input, length);
state = (state_t*)output;
// The KeyExpansion routine must be called before encryption.
Key = key;
KeyExpansion();
InvCipher();
mpw_zero( RoundKey, keyExpSize );
}
#endif // #if defined(AES_ECB) && (AES_ECB == 1)
#if defined(AES_CBC) && (AES_CBC == 1)
static void XorWithIv(uint8_t* buf)
{
uint8_t i;
for (i = 0; i < AES_BLOCKLEN; ++i) //WAS for(i = 0; i < KEYLEN; ++i) but the block in AES is always 128bit so 16 bytes!
{
buf[i] ^= Iv[i];
}
}
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
uintptr_t i;
uint8_t extra = (uint8_t)(length % AES_BLOCKLEN); /* Remaining bytes in the last non-full block */
// Skip the key expansion if key is passed as 0
if (0 != key)
{
Key = key;
KeyExpansion();
}
if (iv != 0)
{
Iv = (uint8_t*)iv;
}
for (i = 0; i < length; i += AES_BLOCKLEN)
{
XorWithIv(input);
memcpy(output, input, AES_BLOCKLEN);
state = (state_t*)output;
Cipher();
Iv = output;
input += AES_BLOCKLEN;
output += AES_BLOCKLEN;
//printf("Step %d - %d", i/16, i);
}
if (extra)
{
memcpy(output, input, extra);
state = (state_t*)output;
Cipher();
}
mpw_zero( RoundKey, keyExpSize );
}
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
{
uintptr_t i;
uint8_t extra = (uint8_t)(length % AES_BLOCKLEN); /* Remaining bytes in the last non-full block */
// Skip the key expansion if key is passed as 0
if (0 != key)
{
Key = key;
KeyExpansion();
}
// If iv is passed as 0, we continue to encrypt without re-setting the Iv
if (iv != 0)
{
Iv = (uint8_t*)iv;
}
for (i = 0; i < length; i += AES_BLOCKLEN)
{
memcpy(output, input, AES_BLOCKLEN);
state = (state_t*)output;
InvCipher();
XorWithIv(output);
Iv = input;
input += AES_BLOCKLEN;
output += AES_BLOCKLEN;
}
if (extra)
{
memcpy(output, input, extra);
state = (state_t*)output;
InvCipher();
}
mpw_zero( RoundKey, keyExpSize );
}
#endif // #if defined(AES_CBC) && (AES_CBC == 1)

50
core/c/aes.h Normal file
View File

@@ -0,0 +1,50 @@
/*
Source: https://github.com/kokke/tiny-AES-c
This is an implementation of the AES algorithm, specifically ECB and CBC mode.
*/
#ifndef _AES_H_
#define _AES_H_
#include <stdint.h>
// #define the macros below to 1/0 to enable/disable the mode of operation.
//
// AES_CBC enables AES encryption in CBC-mode of operation.
// AES_ECB enables the basic ECB 16-byte block algorithm. Both can be enabled simultaneously.
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
#ifndef AES_CBC
#define AES_CBC 1
#endif
#ifndef AES_ECB
#define AES_ECB 1
#endif
#define AES_128 1
//#define AES_192 1
//#define AES_256 1
#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only
#if defined(AES_ECB) && (AES_ECB == 1)
void AES_ECB_encrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key);
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key);
#endif // #if defined(AES_ECB) && (AES_ECB == !)
#if defined(AES_CBC) && (AES_CBC == 1)
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, const uint32_t length, const uint8_t* key, const uint8_t* iv);
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, const uint32_t length, const uint8_t* key, const uint8_t* iv);
#endif // #if defined(AES_CBC) && (AES_CBC == 1)
#endif //_AES_H_

View File

@@ -29,9 +29,9 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
if (masterPassword && !strlen( masterPassword )) if (masterPassword && !strlen( masterPassword ))
masterPassword = NULL; masterPassword = NULL;
trc( "-- mpw_masterKey (algorithm: %u)\n", algorithmVersion ); trc( "-- mpw_masterKey (algorithm: %u)", algorithmVersion );
trc( "fullName: %s\n", fullName ); trc( "fullName: %s", fullName );
trc( "masterPassword.id: %s\n", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL ); trc( "masterPassword.id: %s", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
if (!fullName || !masterPassword) if (!fullName || !masterPassword)
return NULL; return NULL;
@@ -45,7 +45,7 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_masterKey_v3( fullName, masterPassword ); return mpw_masterKey_v3( fullName, masterPassword );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
@@ -54,16 +54,14 @@ MPSiteKey mpw_siteKey(
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter, MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) { const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext )) if (keyContext && !strlen( keyContext ))
keyContext = NULL; keyContext = NULL;
trc( "-- mpw_siteKey (algorithm: %u)\n", algorithmVersion ); trc( "-- mpw_siteKey (algorithm: %u)", algorithmVersion );
trc( "siteName: %s\n", siteName ); trc( "siteName: %s", siteName );
trc( "siteCounter: %d\n", siteCounter ); trc( "siteCounter: %d", siteCounter );
trc( "keyPurpose: %d (%s)\n", keyPurpose, mpw_nameForPurpose( keyPurpose ) ); trc( "keyPurpose: %d (%s)", keyPurpose, mpw_nameForPurpose( keyPurpose ) );
trc( "keyContext: %s\n", keyContext ); trc( "keyContext: %s", keyContext );
if (!masterKey || !siteName) if (!masterKey || !siteName)
return NULL; return NULL;
@@ -77,7 +75,7 @@ MPSiteKey mpw_siteKey(
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext ); return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
@@ -88,8 +86,6 @@ const char *mpw_siteResult(
const MPResultType resultType, const char *resultParam, const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion) { const MPAlgorithmVersion algorithmVersion) {
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext )) if (keyContext && !strlen( keyContext ))
keyContext = NULL; keyContext = NULL;
if (resultParam && !strlen( resultParam )) if (resultParam && !strlen( resultParam ))
@@ -99,9 +95,9 @@ const char *mpw_siteResult(
if (!siteKey) if (!siteKey)
return NULL; return NULL;
trc( "-- mpw_siteResult (algorithm: %u)\n", algorithmVersion ); trc( "-- mpw_siteResult (algorithm: %u)", algorithmVersion );
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) ); trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
trc( "resultParam: %s\n", resultParam ); trc( "resultParam: %s", resultParam );
char *sitePassword = NULL; char *sitePassword = NULL;
if (resultType & MPResultTypeClassTemplate) { if (resultType & MPResultTypeClassTemplate) {
@@ -115,7 +111,7 @@ const char *mpw_siteResult(
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_sitePasswordFromTemplate_v3( masterKey, siteKey, resultType, resultParam ); return mpw_sitePasswordFromTemplate_v3( masterKey, siteKey, resultType, resultParam );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
@@ -130,7 +126,7 @@ const char *mpw_siteResult(
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_sitePasswordFromCrypt_v3( masterKey, siteKey, resultType, resultParam ); return mpw_sitePasswordFromCrypt_v3( masterKey, siteKey, resultType, resultParam );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
@@ -145,12 +141,12 @@ const char *mpw_siteResult(
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_sitePasswordFromDerive_v3( masterKey, siteKey, resultType, resultParam ); return mpw_sitePasswordFromDerive_v3( masterKey, siteKey, resultType, resultParam );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
else { else {
err( "Unsupported password type: %d\n", resultType ); err( "Unsupported password type: %d", resultType );
} }
return sitePassword; return sitePassword;
@@ -162,20 +158,18 @@ const char *mpw_siteState(
const MPResultType resultType, const char *resultParam, const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion) { const MPAlgorithmVersion algorithmVersion) {
if (siteName && !strlen( siteName ))
siteName = NULL;
if (keyContext && !strlen( keyContext )) if (keyContext && !strlen( keyContext ))
keyContext = NULL; keyContext = NULL;
if (resultParam && !strlen( resultParam )) if (resultParam && !strlen( resultParam ))
resultParam = NULL; resultParam = NULL;
MPSiteKey siteKey = mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext ); MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
if (!siteKey) if (!siteKey)
return NULL; return NULL;
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion ); trc( "-- mpw_siteState (algorithm: %u)", algorithmVersion );
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) ); trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
trc( "resultParam: %s\n", resultParam ); trc( "resultParam: %zu bytes = %s", sizeof( resultParam ), resultParam );
if (!masterKey || !resultParam) if (!masterKey || !resultParam)
return NULL; return NULL;
@@ -189,7 +183,44 @@ const char *mpw_siteState(
case MPAlgorithmVersion3: case MPAlgorithmVersion3:
return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam ); return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam );
default: default:
err( "Unsupported version: %d\n", algorithmVersion ); err( "Unsupported version: %d", algorithmVersion );
return NULL; return NULL;
} }
} }
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) {
const char *leftArm[] = { "", "", "", "" };
const char *rightArm[] = { "", "", "", "" };
const char *body[] = { "", "", "", "", "", "" };
const char *accessory[] = {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};
const uint8_t *identiconSeed = NULL;
if (fullName && strlen( fullName ) && masterPassword && strlen( masterPassword ))
identiconSeed = mpw_hash_hmac_sha256(
(const uint8_t *)masterPassword, strlen( masterPassword ),
(const uint8_t *)fullName, strlen( fullName ) );
if (!identiconSeed)
return (MPIdenticon){
.leftArm = "",
.body = "",
.rightArm = "",
.accessory = "",
.color=0,
};
MPIdenticon identicon = {
.leftArm = leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
.body = body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
.rightArm = rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
.accessory = accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
.color = (uint8_t)(identiconSeed[4] % (MPIdenticonColorLast - MPIdenticonColorFirst + 1) + MPIdenticonColorFirst),
};
mpw_free( &identiconSeed, 32 );
return identicon;
}

View File

@@ -66,4 +66,7 @@ const char *mpw_siteState(
const MPResultType resultType, const char *resultParam, const MPResultType resultType, const char *resultParam,
const MPAlgorithmVersion algorithmVersion); const MPAlgorithmVersion algorithmVersion);
/** @return A fingerprint for a user. */
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword);
#endif // _MPW_ALGORITHM_H #endif // _MPW_ALGORITHM_H

View File

@@ -52,10 +52,10 @@ static MPMasterKey mpw_masterKey_v0(
const char *fullName, const char *masterPassword) { const char *fullName, const char *masterPassword) {
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication ); const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
trc( "keyScope: %s\n", keyScope ); trc( "keyScope: %s", keyScope );
// Calculate the master key salt. // Calculate the master key salt.
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n", trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( fullName ) ), fullName ); keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( fullName ) ), fullName );
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
@@ -63,20 +63,20 @@ static MPMasterKey mpw_masterKey_v0(
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)mpw_utf8_strlen( fullName ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)mpw_utf8_strlen( fullName ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
err( "Could not allocate master key salt: %s\n", strerror( errno ) ); err( "Could not allocate master key salt: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => masterKeySalt.id: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) ); trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p ); trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, 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) { if (!masterKey) {
err( "Could not derive master key: %s\n", strerror( errno ) ); err( "Could not derive master key: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) ); trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey; return masterKey;
} }
@@ -86,14 +86,14 @@ static MPSiteKey mpw_siteKey_v0(
MPKeyPurpose keyPurpose, const char *keyContext) { MPKeyPurpose keyPurpose, const char *keyContext) {
const char *keyScope = mpw_scopeForPurpose( keyPurpose ); const char *keyScope = mpw_scopeForPurpose( keyPurpose );
trc( "keyScope: %s\n", keyScope ); trc( "keyScope: %s", keyScope );
// OTP counter value. // OTP counter value.
if (siteCounter == MPCounterValueTOTP) if (siteCounter == MPCounterValueTOTP)
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window; siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
// Calculate the site seed. // Calculate the site seed.
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n", trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
keyScope, mpw_hex_l( (uint32_t)mpw_utf8_strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ), 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 ); keyContext? mpw_hex_l( (uint32_t)mpw_utf8_strlen( keyContext ) ): NULL, keyContext );
size_t siteSaltSize = 0; size_t siteSaltSize = 0;
@@ -107,20 +107,20 @@ static MPSiteKey mpw_siteKey_v0(
mpw_push_string( &siteSalt, &siteSaltSize, keyContext ); mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
} }
if (!siteSalt) { if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) ); err( "Could not allocate site salt: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) ); trc( " => siteSalt.id: %s", mpw_id_buf( siteSalt, siteSaltSize ) );
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n", trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )",
mpw_id_buf( masterKey, MPMasterKeySize ) ); mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize ); MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize ); mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) { if (!siteKey) {
err( "Could not derive site key: %s\n", strerror( errno ) ); err( "Could not derive site key: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) ); trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
return siteKey; return siteKey;
} }
@@ -134,11 +134,11 @@ static const char *mpw_sitePasswordFromTemplate_v0(
uint16_t seedByte; uint16_t seedByte;
mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte ); mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte );
const char *template = mpw_templateForType_v0( resultType, seedByte ); const char *template = mpw_templateForType_v0( resultType, seedByte );
trc( "template: %u => %s\n", seedByte, template ); trc( "template: %u => %s", seedByte, template );
if (!template) if (!template)
return NULL; return NULL;
if (strlen( template ) > MPSiteKeySize) { if (strlen( template ) > MPSiteKeySize) {
err( "Template too long for password seed: %zu\n", strlen( template ) ); err( "Template too long for password seed: %zu", strlen( template ) );
return NULL; return NULL;
} }
@@ -147,10 +147,10 @@ static const char *mpw_sitePasswordFromTemplate_v0(
for (size_t c = 0; c < strlen( template ); ++c) { for (size_t c = 0; c < strlen( template ); ++c) {
mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte ); mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte );
sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte ); sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte );
trc( " - class: %c, index: %5u (0x%02hX) => character: %c\n", trc( " - class: %c, index: %5u (0x%02hX) => character: %c",
template[c], seedByte, seedByte, sitePassword[c] ); template[c], seedByte, seedByte, sitePassword[c] );
} }
trc( " => password: %s\n", sitePassword ); trc( " => password: %s", sitePassword );
return sitePassword; return sitePassword;
} }
@@ -159,28 +159,28 @@ static const char *mpw_sitePasswordFromCrypt_v0(
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) { MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) {
if (!cipherText) { if (!cipherText) {
err( "Missing encrypted state.\n" ); err( "Missing encrypted state." );
return NULL; return NULL;
} }
// Base64-decode // Base64-decode
uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) ); uint8_t *cipherBuf = calloc( 1, mpw_base64_decode_max( cipherText ) );
size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText ); size_t bufSize = (size_t)mpw_base64_decode( cipherBuf, cipherText ), cipherBufSize = bufSize;
if ((int)bufSize < 0) { if ((int)bufSize < 0) {
err( "Base64 decoding error." ); err( "Base64 decoding error." );
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) ); mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
return NULL; return NULL;
} }
trc( "b64 decoded: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) ); trc( "b64 decoded: %zu bytes = %s", bufSize, mpw_hex( cipherBuf, bufSize ) );
// Decrypt // Decrypt
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize ); const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, &bufSize );
mpw_free( &cipherBuf, bufSize ); mpw_free( &cipherBuf, cipherBufSize );
const char *plainText = strndup( (char *)plainBytes, bufSize ); const char *plainText = mpw_strndup( (char *)plainBytes, bufSize );
mpw_free( &plainBytes, bufSize ); mpw_free( &plainBytes, bufSize );
if (!plainText) if (!plainText)
err( "AES decryption error: %s\n", strerror( errno ) ); err( "AES decryption error: %s", strerror( errno ) );
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) ); trc( "decrypted -> plainText: %zu bytes = %s = %s", strlen( plainText ), plainText, mpw_hex( plainText, strlen( plainText ) ) );
return plainText; return plainText;
} }
@@ -191,21 +191,23 @@ static const char *mpw_sitePasswordFromDerive_v0(
switch (resultType) { switch (resultType) {
case MPResultTypeDeriveKey: { case MPResultTypeDeriveKey: {
if (!resultParam) { if (!resultParam) {
err( "Missing key size parameter.\n" ); err( "Missing key size parameter." );
return NULL; return NULL;
} }
int resultParamInt = atoi( resultParam ); int resultParamInt = atoi( resultParam );
if (!resultParamInt)
resultParamInt = 512;
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) { if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
err( "Parameter is not a valid key size (should be 128 - 512): %s\n", resultParam ); err( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
return NULL; return NULL;
} }
uint16_t keySize = (uint16_t)(resultParamInt / 8); uint16_t keySize = (uint16_t)(resultParamInt / 8);
trc( "keySize: %u\n", keySize ); trc( "keySize: %u", keySize );
// Derive key // Derive key
const uint8_t *resultKey = mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL ); const uint8_t *resultKey = mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
if (!resultKey) { if (!resultKey) {
err( "Could not derive result key: %s\n", strerror( errno ) ); err( "Could not derive result key: %s", strerror( errno ) );
return NULL; return NULL;
} }
@@ -217,13 +219,13 @@ static const char *mpw_sitePasswordFromDerive_v0(
mpw_free_string( &b64Key ); mpw_free_string( &b64Key );
} }
else else
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) ); trc( "b64 encoded -> key: %s", b64Key );
mpw_free( &resultKey, keySize ); mpw_free( &resultKey, keySize );
return b64Key; return b64Key;
} }
default: default:
err( "Unsupported derived password type: %d\n", resultType ); err( "Unsupported derived password type: %d", resultType );
return NULL; return NULL;
} }
} }
@@ -233,12 +235,12 @@ static const char *mpw_siteState_v0(
// Encrypt // Encrypt
size_t bufSize = strlen( plainText ); size_t bufSize = strlen( plainText );
const uint8_t *cipherBuf = mpw_aes_encrypt( masterKey, MPMasterKeySize, (const uint8_t *)plainText, bufSize ); const uint8_t *cipherBuf = mpw_aes_encrypt( masterKey, MPMasterKeySize, (const uint8_t *)plainText, &bufSize );
if (!cipherBuf) { if (!cipherBuf) {
err( "AES encryption error: %s\n", strerror( errno ) ); err( "AES encryption error: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( "cipherBuf: %zu bytes = %s\n", bufSize, mpw_hex( cipherBuf, bufSize ) ); trc( "cipherBuf: %zu bytes = %s", bufSize, mpw_hex( cipherBuf, bufSize ) );
// Base64-encode // Base64-encode
size_t b64Max = mpw_base64_encode_max( bufSize ); size_t b64Max = mpw_base64_encode_max( bufSize );
@@ -248,7 +250,7 @@ static const char *mpw_siteState_v0(
mpw_free_string( &cipherText ); mpw_free_string( &cipherText );
} }
else else
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) ); trc( "b64 encoded -> cipherText: %s", cipherText );
mpw_free( &cipherBuf, bufSize ); mpw_free( &cipherBuf, bufSize );
return cipherText; return cipherText;

View File

@@ -58,11 +58,11 @@ static const char *mpw_sitePasswordFromTemplate_v1(
// Determine the template. // Determine the template.
uint8_t seedByte = siteKey[0]; uint8_t seedByte = siteKey[0];
const char *template = mpw_templateForType( resultType, seedByte ); const char *template = mpw_templateForType( resultType, seedByte );
trc( "template: %u => %s\n", seedByte, template ); trc( "template: %u => %s", seedByte, template );
if (!template) if (!template)
return NULL; return NULL;
if (strlen( template ) > MPSiteKeySize) { if (strlen( template ) > MPSiteKeySize) {
err( "Template too long for password seed: %zu\n", strlen( template ) ); err( "Template too long for password seed: %zu", strlen( template ) );
return NULL; return NULL;
} }
@@ -71,10 +71,10 @@ static const char *mpw_sitePasswordFromTemplate_v1(
for (size_t c = 0; c < strlen( template ); ++c) { for (size_t c = 0; c < strlen( template ); ++c) {
seedByte = siteKey[c + 1]; seedByte = siteKey[c + 1];
sitePassword[c] = mpw_characterFromClass( template[c], seedByte ); sitePassword[c] = mpw_characterFromClass( template[c], seedByte );
trc( " - class: %c, index: %3u (0x%02hhX) => character: %c\n", trc( " - class: %c, index: %3u (0x%02hhX) => character: %c",
template[c], seedByte, seedByte, sitePassword[c] ); template[c], seedByte, seedByte, sitePassword[c] );
} }
trc( " => password: %s\n", sitePassword ); trc( " => password: %s", sitePassword );
return sitePassword; return sitePassword;
} }

View File

@@ -51,14 +51,14 @@ static MPSiteKey mpw_siteKey_v2(
MPKeyPurpose keyPurpose, const char *keyContext) { MPKeyPurpose keyPurpose, const char *keyContext) {
const char *keyScope = mpw_scopeForPurpose( keyPurpose ); const char *keyScope = mpw_scopeForPurpose( keyPurpose );
trc( "keyScope: %s\n", keyScope ); trc( "keyScope: %s", keyScope );
// OTP counter value. // OTP counter value.
if (siteCounter == MPCounterValueTOTP) if (siteCounter == MPCounterValueTOTP)
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window; siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
// Calculate the site seed. // Calculate the site seed.
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n", trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ), keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ),
keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext ); keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext );
size_t siteSaltSize = 0; size_t siteSaltSize = 0;
@@ -72,20 +72,20 @@ static MPSiteKey mpw_siteKey_v2(
mpw_push_string( &siteSalt, &siteSaltSize, keyContext ); mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
} }
if (!siteSalt) { if (!siteSalt) {
err( "Could not allocate site salt: %s\n", strerror( errno ) ); err( "Could not allocate site salt: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => siteSalt.id: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) ); trc( " => siteSalt.id: %s", mpw_id_buf( siteSalt, siteSaltSize ) );
trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )\n", trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )",
mpw_id_buf( masterKey, MPMasterKeySize ) ); mpw_id_buf( masterKey, MPMasterKeySize ) );
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize ); MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
mpw_free( &siteSalt, siteSaltSize ); mpw_free( &siteSalt, siteSaltSize );
if (!siteKey) { if (!siteKey) {
err( "Could not derive site key: %s\n", strerror( errno ) ); err( "Could not derive site key: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) ); trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
return siteKey; return siteKey;
} }

View File

@@ -44,10 +44,10 @@ static MPMasterKey mpw_masterKey_v3(
const char *fullName, const char *masterPassword) { const char *fullName, const char *masterPassword) {
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication ); const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
trc( "keyScope: %s\n", keyScope ); trc( "keyScope: %s", keyScope );
// Calculate the master key salt. // Calculate the master key salt.
trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s\n", trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName ); keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName );
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
@@ -55,20 +55,20 @@ static MPMasterKey mpw_masterKey_v3(
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
err( "Could not allocate master key salt: %s\n", strerror( errno ) ); err( "Could not allocate master key salt: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => masterKeySalt.id: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) ); trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )\n", MP_N, MP_r, MP_p ); trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )", MP_N, MP_r, MP_p );
MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, masterPassword, masterKeySalt, masterKeySaltSize, 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) { if (!masterKey) {
err( "Could not derive master key: %s\n", strerror( errno ) ); err( "Could not derive master key: %s", strerror( errno ) );
return NULL; return NULL;
} }
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) ); trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
return masterKey; return masterKey;
} }

View File

@@ -18,7 +18,7 @@
#include <string.h> #include <string.h>
#include "mpw-marshall-util.h" #include "mpw-marshal-util.h"
#include "mpw-util.h" #include "mpw-util.h"
char *mpw_get_token(const char **in, const char *eol, char *delim) { char *mpw_get_token(const char **in, const char *eol, char *delim) {
@@ -28,7 +28,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
// Find characters up to the first delim. // Find characters up to the first delim.
size_t len = strcspn( *in, delim ); size_t len = strcspn( *in, delim );
char *token = len && len <= (size_t)(eol - *in)? strndup( *in, len ): NULL; char *token = len && len <= (size_t)(eol - *in)? mpw_strndup( *in, len ): NULL;
// Advance past the delimitor. // Advance past the delimitor.
*in = min( eol, *in + len + 1 ); *in = min( eol, *in + len + 1 );
@@ -38,7 +38,7 @@ char *mpw_get_token(const char **in, const char *eol, char *delim) {
time_t mpw_mktime( time_t mpw_mktime(
const char *time) { const char *time) {
struct tm tm = { .tm_isdst = -1, .tm_gmtoff = 0 }; struct tm tm = { .tm_isdst = -1 };
if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ", if (time && sscanf( time, "%4d-%2d-%2dT%2d:%2d:%2dZ",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) { &tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
@@ -55,10 +55,10 @@ json_object *mpw_get_json_section(
json_object *obj, const char *section) { json_object *obj, const char *section) {
json_object *json_value = obj; json_object *json_value = obj;
char *sectionTokenizer = strdup( section ), *sectionToken = sectionTokenizer; char *sectionTokenizer = mpw_strdup( section ), *sectionToken = sectionTokenizer;
for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." )) for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." ))
if (!json_object_object_get_ex( json_value, sectionToken, &json_value ) || !json_value) { if (!json_object_object_get_ex( json_value, sectionToken, &json_value ) || !json_value) {
trc( "While resolving: %s: Missing value for: %s\n", section, sectionToken ); trc( "While resolving: %s: Missing value for: %s", section, sectionToken );
json_value = NULL; json_value = NULL;
break; break;
} }
@@ -106,7 +106,7 @@ bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyA
*masterKeyAlgorithm = targetKeyAlgorithm; *masterKeyAlgorithm = targetKeyAlgorithm;
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm ); *masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
if (!*masterKey) { if (!*masterKey) {
err( "Couldn't derive master key for user %s, algorithm %d.\n", fullName, *masterKeyAlgorithm ); err( "Couldn't derive master key for user %s, algorithm %d.", fullName, *masterKeyAlgorithm );
return false; return false;
} }
} }

View File

@@ -16,11 +16,13 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
#ifndef _MPW_MARSHALL_UTIL_H #ifndef _MPW_MARSHAL_UTIL_H
#define _MPW_MARSHALL_UTIL_H #define _MPW_MARSHAL_UTIL_H
#include <time.h> #include <time.h>
#if MPW_JSON
#include "json-c/json.h" #include "json-c/json.h"
#endif
#include "mpw-algorithm.h" #include "mpw-algorithm.h"
@@ -37,6 +39,7 @@ time_t mpw_mktime(
/// JSON parsing. /// JSON parsing.
#if MPW_JSON
/** Search for a JSON child object in a JSON object tree. /** Search for a JSON child object in a JSON object tree.
* @param section A dot-delimited list of JSON object keys to walk toward the child object. * @param section A dot-delimited list of JSON object keys to walk toward the child object.
* @return A new JSON object or NULL if one of the section's object keys was not found in the source object's tree. */ * @return A new JSON object or NULL if one of the section's object keys was not found in the source object's tree. */
@@ -57,6 +60,7 @@ int64_t mpw_get_json_int(
* @return The boolean value or defaultValue if one of the section's object keys was not found in the source object's tree. */ * @return The boolean value or defaultValue if one of the section's object keys was not found in the source object's tree. */
bool mpw_get_json_boolean( bool mpw_get_json_boolean(
json_object *obj, const char *section, bool defaultValue); json_object *obj, const char *section, bool defaultValue);
#endif
/// mpw. /// mpw.
@@ -66,4 +70,4 @@ bool mpw_update_masterKey(
MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm, MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm,
const char *fullName, const char *masterPassword); const char *fullName, const char *masterPassword);
#endif // _MPW_MARSHALL_UTIL_H #endif // _MPW_MARSHAL_UTIL_H

View File

@@ -21,11 +21,11 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "mpw-marshall.h" #include "mpw-marshal.h"
#include "mpw-util.h" #include "mpw-util.h"
#include "mpw-marshall-util.h" #include "mpw-marshal-util.h"
MPMarshalledUser *mpw_marshall_user( MPMarshalledUser *mpw_marshal_user(
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
MPMarshalledUser *user; MPMarshalledUser *user;
@@ -33,8 +33,8 @@ MPMarshalledUser *mpw_marshall_user(
return NULL; return NULL;
*user = (MPMarshalledUser){ *user = (MPMarshalledUser){
.fullName = strdup( fullName ), .fullName = mpw_strdup( fullName ),
.masterPassword = strdup( masterPassword ), .masterPassword = mpw_strdup( masterPassword ),
.algorithm = algorithmVersion, .algorithm = algorithmVersion,
.redacted = true, .redacted = true,
@@ -46,9 +46,9 @@ MPMarshalledUser *mpw_marshall_user(
.sites = NULL, .sites = NULL,
}; };
return user; return user;
}; }
MPMarshalledSite *mpw_marshall_site( MPMarshalledSite *mpw_marshal_site(
MPMarshalledUser *user, const char *siteName, const MPResultType resultType, MPMarshalledUser *user, const char *siteName, const MPResultType resultType,
const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion) { const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion) {
@@ -57,7 +57,7 @@ MPMarshalledSite *mpw_marshall_site(
MPMarshalledSite *site = &user->sites[user->sites_count - 1]; MPMarshalledSite *site = &user->sites[user->sites_count - 1];
*site = (MPMarshalledSite){ *site = (MPMarshalledSite){
.name = strdup( siteName ), .name = mpw_strdup( siteName ),
.content = NULL, .content = NULL,
.type = resultType, .type = resultType,
.counter = siteCounter, .counter = siteCounter,
@@ -74,7 +74,7 @@ MPMarshalledSite *mpw_marshall_site(
.questions = NULL, .questions = NULL,
}; };
return site; return site;
}; }
MPMarshalledQuestion *mpw_marshal_question( MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledSite *site, const char *keyword) { MPMarshalledSite *site, const char *keyword) {
@@ -86,7 +86,7 @@ MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1]; MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
*question = (MPMarshalledQuestion){ *question = (MPMarshalledQuestion){
.keyword = strdup( keyword ), .keyword = mpw_strdup( keyword ),
.content = NULL, .content = NULL,
.type = MPResultTypeTemplatePhrase, .type = MPResultTypeTemplatePhrase,
}; };
@@ -94,14 +94,14 @@ MPMarshalledQuestion *mpw_marshal_question(
} }
bool mpw_marshal_info_free( bool mpw_marshal_info_free(
MPMarshallInfo **info) { MPMarshalInfo **info) {
if (!info || !*info) if (!info || !*info)
return true; return true;
bool success = true; bool success = true;
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL ); success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
success &= mpw_free( info, sizeof( MPMarshallInfo ) ); success &= mpw_free( info, sizeof( MPMarshalInfo ) );
return success; return success;
} }
@@ -132,22 +132,22 @@ bool mpw_marshal_free(
return success; return success;
} }
static bool mpw_marshall_write_flat( static bool mpw_marshal_write_flat(
char **out, const MPMarshalledUser *user, MPMarshallError *error) { char **out, const MPMarshalledUser *user, MPMarshalError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
if (!user->fullName || !strlen( user->fullName )) { if (!user->fullName || !strlen( user->fullName )) {
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." }; *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
return false; return false;
} }
if (!user->masterPassword || !strlen( user->masterPassword )) { if (!user->masterPassword || !strlen( user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." }; *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
return false; return false;
} }
MPMasterKey masterKey = NULL; MPMasterKey masterKey = NULL;
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return false; return false;
} }
@@ -186,7 +186,7 @@ static bool mpw_marshall_write_flat(
if (!user->redacted) { if (!user->redacted) {
// Clear Text // Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return false; return false;
} }
@@ -198,9 +198,9 @@ static bool mpw_marshall_write_flat(
else { else {
// Redacted // Redacted
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content )) if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
content = strdup( site->content ); content = mpw_strdup( site->content );
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent )) if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
loginContent = strdup( site->loginContent ); loginContent = mpw_strdup( site->loginContent );
} }
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) )) if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
@@ -211,27 +211,27 @@ static bool mpw_marshall_write_flat(
} }
mpw_free( &masterKey, MPMasterKeySize ); mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return true; return true;
} }
#if MPW_JSON #if MPW_JSON
static bool mpw_marshall_write_json( static bool mpw_marshal_write_json(
char **out, const MPMarshalledUser *user, MPMarshallError *error) { char **out, const MPMarshalledUser *user, MPMarshalError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
if (!user->fullName || !strlen( user->fullName )) { if (!user->fullName || !strlen( user->fullName )) {
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." }; *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
return false; return false;
} }
if (!user->masterPassword || !strlen( user->masterPassword )) { if (!user->masterPassword || !strlen( user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." }; *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
return false; return false;
} }
MPMasterKey masterKey = NULL; MPMasterKey masterKey = NULL;
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1; MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, user->algorithm, user->fullName, user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return false; return false;
} }
@@ -272,7 +272,7 @@ static bool mpw_marshall_write_json(
if (!user->redacted) { if (!user->redacted) {
// Clear Text // Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, user->fullName, user->masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return false; return false;
} }
@@ -284,9 +284,9 @@ static bool mpw_marshall_write_json(
else { else {
// Redacted // Redacted
if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content )) if (site->type & MPSiteFeatureExportContent && site->content && strlen( site->content ))
content = strdup( site->content ); content = mpw_strdup( site->content );
if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent )) if (site->loginType & MPSiteFeatureExportContent && site->loginContent && strlen( site->loginContent ))
loginContent = strdup( site->loginContent ); loginContent = mpw_strdup( site->loginContent );
} }
json_object *json_site = json_object_new_object(); json_object *json_site = json_object_new_object();
@@ -340,32 +340,32 @@ static bool mpw_marshall_write_json(
mpw_free( &masterKey, MPMasterKeySize ); mpw_free( &masterKey, MPMasterKeySize );
json_object_put( json_file ); json_object_put( json_file );
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return true; return true;
} }
#endif #endif
bool mpw_marshall_write( bool mpw_marshal_write(
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error) { char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error) {
switch (outFormat) { switch (outFormat) {
case MPMarshallFormatNone: case MPMarshalFormatNone:
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return false; return false;
case MPMarshallFormatFlat: case MPMarshalFormatFlat:
return mpw_marshall_write_flat( out, user, error ); return mpw_marshal_write_flat( out, user, error );
#if MPW_JSON #if MPW_JSON
case MPMarshallFormatJSON: case MPMarshalFormatJSON:
return mpw_marshall_write_json( out, user, error ); return mpw_marshal_write_json( out, user, error );
#endif #endif
default: default:
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) }; *error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
return false; return false;
} }
} }
static void mpw_marshall_read_flat_info( static void mpw_marshal_read_flat_info(
const char *in, MPMarshallInfo *info) { const char *in, MPMarshalInfo *info) {
info->algorithm = MPAlgorithmVersionCurrent; info->algorithm = MPAlgorithmVersionCurrent;
@@ -397,9 +397,9 @@ static void mpw_marshall_read_flat_info(
if (strcmp( headerName, "Algorithm" ) == 0) if (strcmp( headerName, "Algorithm" ) == 0)
info->algorithm = (MPAlgorithmVersion)atoi( headerValue ); info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0) if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
info->fullName = strdup( headerValue ); info->fullName = mpw_strdup( headerValue );
if (strcmp( headerName, "Key ID" ) == 0) if (strcmp( headerName, "Key ID" ) == 0)
info->keyID = strdup( headerValue ); info->keyID = mpw_strdup( headerValue );
if (strcmp( headerName, "Passwords" ) == 0) if (strcmp( headerName, "Passwords" ) == 0)
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0; info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
if (strcmp( headerName, "Date" ) == 0) if (strcmp( headerName, "Date" ) == 0)
@@ -411,12 +411,12 @@ static void mpw_marshall_read_flat_info(
} }
} }
static MPMarshalledUser *mpw_marshall_read_flat( static MPMarshalledUser *mpw_marshal_read_flat(
const char *in, const char *masterPassword, MPMarshallError *error) { const char *in, const char *masterPassword, MPMarshalError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
if (!in || !strlen( in )) { if (!in || !strlen( in )) {
error->type = MPMarshallErrorStructure; error->type = MPMarshalErrorStructure;
error->description = mpw_str( "No input data." ); error->description = mpw_str( "No input data." );
return NULL; return NULL;
} }
@@ -455,23 +455,23 @@ static MPMarshalledUser *mpw_marshall_read_flat(
char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" ); char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" ); char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
if (!headerName || !headerValue) { if (!headerName || !headerValue) {
error->type = MPMarshallErrorStructure; error->type = MPMarshalErrorStructure;
error->description = mpw_str( "Invalid header: %s", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) ); error->description = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
return NULL; return NULL;
} }
if (strcmp( headerName, "Format" ) == 0) if (strcmp( headerName, "Format" ) == 0)
format = (unsigned int)atoi( headerValue ); format = (unsigned int)atoi( headerValue );
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0) if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
fullName = strdup( headerValue ); fullName = mpw_strdup( headerValue );
if (strcmp( headerName, "Avatar" ) == 0) if (strcmp( headerName, "Avatar" ) == 0)
avatar = (unsigned int)atoi( headerValue ); avatar = (unsigned int)atoi( headerValue );
if (strcmp( headerName, "Key ID" ) == 0) if (strcmp( headerName, "Key ID" ) == 0)
keyID = strdup( headerValue ); keyID = mpw_strdup( headerValue );
if (strcmp( headerName, "Algorithm" ) == 0) { if (strcmp( headerName, "Algorithm" ) == 0) {
int value = atoi( headerValue ); int value = atoi( headerValue );
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %s", headerValue ) };
return NULL; return NULL;
} }
algorithm = (MPAlgorithmVersion)value; algorithm = (MPAlgorithmVersion)value;
@@ -479,7 +479,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (strcmp( headerName, "Default Type" ) == 0) { if (strcmp( headerName, "Default Type" ) == 0) {
int value = atoi( headerValue ); int value = atoi( headerValue );
if (!mpw_nameForType( (MPResultType)value )) { if (!mpw_nameForType( (MPResultType)value )) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) };
return NULL; return NULL;
} }
defaultType = (MPResultType)value; defaultType = (MPResultType)value;
@@ -493,7 +493,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (!headerEnded) if (!headerEnded)
continue; continue;
if (!fullName) { if (!fullName) {
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing header: Full Name" }; *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing header: Full Name" };
return NULL; return NULL;
} }
if (positionInLine >= endOfLine) if (positionInLine >= endOfLine)
@@ -501,15 +501,15 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (!user) { if (!user) {
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return NULL; return NULL;
} }
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) { if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Master password doesn't match key ID." }; *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
return NULL; return NULL;
} }
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) { if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
return NULL; return NULL;
} }
@@ -527,11 +527,11 @@ static MPMarshalledUser *mpw_marshall_read_flat(
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" ); str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" ); char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
if (typeAndVersion) { if (typeAndVersion) {
str_type = strdup( strtok( typeAndVersion, ":" ) ); str_type = mpw_strdup( strtok( typeAndVersion, ":" ) );
str_algorithm = strdup( strtok( NULL, "" ) ); str_algorithm = mpw_strdup( strtok( NULL, "" ) );
mpw_free_string( &typeAndVersion ); mpw_free_string( &typeAndVersion );
} }
str_counter = strdup( "1" ); str_counter = mpw_strdup( "1" );
siteLoginName = NULL; siteLoginName = NULL;
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); siteName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
siteContent = mpw_get_token( &positionInLine, endOfLine, "\n" ); siteContent = mpw_get_token( &positionInLine, endOfLine, "\n" );
@@ -542,9 +542,9 @@ static MPMarshalledUser *mpw_marshall_read_flat(
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" ); str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" ); char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
if (typeAndVersionAndCounter) { if (typeAndVersionAndCounter) {
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) ); str_type = mpw_strdup( strtok( typeAndVersionAndCounter, ":" ) );
str_algorithm = strdup( strtok( NULL, ":" ) ); str_algorithm = mpw_strdup( strtok( NULL, ":" ) );
str_counter = strdup( strtok( NULL, "" ) ); str_counter = mpw_strdup( strtok( NULL, "" ) );
mpw_free_string( &typeAndVersionAndCounter ); mpw_free_string( &typeAndVersionAndCounter );
} }
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" ); siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
@@ -553,7 +553,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
break; break;
} }
default: { default: {
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unexpected import format: %u", format ) }; *error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
return NULL; return NULL;
} }
} }
@@ -561,31 +561,31 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) { if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
MPResultType siteType = (MPResultType)atoi( str_type ); MPResultType siteType = (MPResultType)atoi( str_type );
if (!mpw_nameForType( siteType )) { if (!mpw_nameForType( siteType )) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) };
return NULL; return NULL;
} }
long long int value = atoll( str_counter ); long long int value = atoll( str_counter );
if (value < MPCounterValueFirst || value > MPCounterValueLast) { if (value < MPCounterValueFirst || value > MPCounterValueLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %s", siteName, str_counter ) };
return NULL; return NULL;
} }
MPCounterValue siteCounter = (MPCounterValue)value; MPCounterValue siteCounter = (MPCounterValue)value;
value = atoll( str_algorithm ); value = atoll( str_algorithm );
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm: %s: %s", siteName, str_algorithm ) };
return NULL; return NULL;
} }
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value; MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
time_t siteLastUsed = mpw_mktime( str_lastUsed ); time_t siteLastUsed = mpw_mktime( str_lastUsed );
if (!siteLastUsed) { if (!siteLastUsed) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
return NULL; return NULL;
} }
MPMarshalledSite *site = mpw_marshall_site( MPMarshalledSite *site = mpw_marshal_site(
user, siteName, siteType, siteCounter, siteAlgorithm ); user, siteName, siteType, siteCounter, siteAlgorithm );
if (!site) { if (!site) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
return NULL; return NULL;
} }
@@ -594,7 +594,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
if (!user->redacted) { if (!user->redacted) {
// Clear Text // Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return NULL; return NULL;
} }
@@ -608,13 +608,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
else { else {
// Redacted // Redacted
if (siteContent && strlen( siteContent )) if (siteContent && strlen( siteContent ))
site->content = strdup( siteContent ); site->content = mpw_strdup( siteContent );
if (siteLoginName && strlen( siteLoginName )) if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName ); site->loginContent = mpw_strdup( siteLoginName );
} }
} }
else { else {
error->type = MPMarshallErrorMissing; error->type = MPMarshalErrorMissing;
error->description = mpw_str( error->description = mpw_str(
"Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s", "Missing one of: lastUsed=%s, uses=%s, type=%s, version=%s, counter=%s, loginName=%s, siteName=%s",
str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginName, siteName ); str_lastUsed, str_uses, str_type, str_algorithm, str_counter, siteLoginName, siteName );
@@ -627,13 +627,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
mpw_free_strings( &fullName, &keyID, NULL ); mpw_free_strings( &fullName, &keyID, NULL );
mpw_free( &masterKey, MPMasterKeySize ); mpw_free( &masterKey, MPMasterKeySize );
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return user; return user;
} }
#if MPW_JSON #if MPW_JSON
static void mpw_marshall_read_json_info( static void mpw_marshal_read_json_info(
const char *in, MPMarshallInfo *info) { const char *in, MPMarshalInfo *info) {
// Parse JSON. // Parse JSON.
enum json_tokener_error json_error = json_tokener_success; enum json_tokener_error json_error = json_tokener_success;
@@ -650,18 +650,18 @@ static void mpw_marshall_read_json_info(
// Section: "user" // Section: "user"
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent ); 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->fullName = mpw_strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
info->keyID = strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) ); info->keyID = mpw_strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
json_object_put( json_file ); json_object_put( json_file );
} }
static MPMarshalledUser *mpw_marshall_read_json( static MPMarshalledUser *mpw_marshal_read_json(
const char *in, const char *masterPassword, MPMarshallError *error) { const char *in, const char *masterPassword, MPMarshalError *error) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
if (!in || !strlen( in )) { if (!in || !strlen( in )) {
error->type = MPMarshallErrorStructure; error->type = MPMarshalErrorStructure;
error->description = mpw_str( "No input data." ); error->description = mpw_str( "No input data." );
return NULL; return NULL;
} }
@@ -670,7 +670,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
enum json_tokener_error json_error = json_tokener_success; enum json_tokener_error json_error = json_tokener_success;
json_object *json_file = json_tokener_parse_verbose( in, &json_error ); json_object *json_file = json_tokener_parse_verbose( in, &json_error );
if (!json_file || json_error != json_tokener_success) { if (!json_file || json_error != json_tokener_success) {
*error = (MPMarshallError){ MPMarshallErrorStructure, mpw_str( "JSON error: %s", json_tokener_error_desc( json_error ) ) }; *error = (MPMarshalError){ MPMarshalErrorStructure, mpw_str( "JSON error: %s", json_tokener_error_desc( json_error ) ) };
return NULL; return NULL;
} }
@@ -682,7 +682,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
// Section: "export" // Section: "export"
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 ); int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
if (fileFormat < 1) { if (fileFormat < 1) {
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) }; *error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
return NULL; return NULL;
} }
bool fileRedacted = mpw_get_json_boolean( json_file, "export.redacted", true ); bool fileRedacted = mpw_get_json_boolean( json_file, "export.redacted", true );
@@ -694,34 +694,34 @@ static MPMarshalledUser *mpw_marshall_read_json(
const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL ); const char *keyID = mpw_get_json_string( json_file, "user.key_id", NULL );
int64_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) { if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
return NULL; return NULL;
} }
MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value; MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value;
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault ); MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
if (!mpw_nameForType( defaultType )) { if (!mpw_nameForType( defaultType )) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
return NULL; return NULL;
} }
time_t lastUsed = mpw_mktime( str_lastUsed ); time_t lastUsed = mpw_mktime( str_lastUsed );
if (!lastUsed) { if (!lastUsed) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user last used: %s", str_lastUsed ) };
return NULL; return NULL;
} }
if (!fullName || !strlen( fullName )) { if (!fullName || !strlen( fullName )) {
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing value for full name." }; *error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." };
return NULL; return NULL;
} }
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return NULL; return NULL;
} }
if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) { if (keyID && !mpw_id_buf_equals( keyID, mpw_id_buf( masterKey, MPMasterKeySize ) )) {
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Master password doesn't match key ID." }; *error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Master password doesn't match key ID." };
return NULL; return NULL;
} }
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) { if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
return NULL; return NULL;
} }
user->redacted = fileRedacted; user->redacted = fileRedacted;
@@ -736,18 +736,18 @@ static MPMarshalledUser *mpw_marshall_read_json(
const char *siteName = json_site.key; const char *siteName = json_site.key;
value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm ); value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm );
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) { if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
return NULL; return NULL;
} }
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value; MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType ); MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
if (!mpw_nameForType( siteType )) { if (!mpw_nameForType( siteType )) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
return NULL; return NULL;
} }
value = mpw_get_json_int( json_site.val, "counter", 1 ); value = mpw_get_json_int( json_site.val, "counter", 1 );
if (value < MPCounterValueFirst || value > MPCounterValueLast) { if (value < MPCounterValueFirst || value > MPCounterValueLast) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site counter: %s: %d", siteName, value ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site counter: %s: %d", siteName, value ) };
return NULL; return NULL;
} }
MPCounterValue siteCounter = (MPCounterValue)value; MPCounterValue siteCounter = (MPCounterValue)value;
@@ -758,27 +758,27 @@ static MPMarshalledUser *mpw_marshall_read_json(
str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL ); str_lastUsed = mpw_get_json_string( json_site.val, "last_used", NULL );
time_t siteLastUsed = mpw_mktime( str_lastUsed ); time_t siteLastUsed = mpw_mktime( str_lastUsed );
if (!siteLastUsed) { if (!siteLastUsed) {
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) }; *error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site last used: %s: %s", siteName, str_lastUsed ) };
return NULL; return NULL;
} }
json_object *json_site_mpw = mpw_get_json_section( json_site.val, "_ext_mpw" ); json_object *json_site_mpw = mpw_get_json_section( json_site.val, "_ext_mpw" );
const char *siteURL = mpw_get_json_string( json_site_mpw, "url", NULL ); const char *siteURL = mpw_get_json_string( json_site_mpw, "url", NULL );
MPMarshalledSite *site = mpw_marshall_site( user, siteName, siteType, siteCounter, siteAlgorithm ); MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, siteAlgorithm );
if (!site) { if (!site) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
return NULL; return NULL;
} }
site->loginType = siteLoginType; site->loginType = siteLoginType;
site->url = siteURL? strdup( siteURL ): NULL; site->url = siteURL? mpw_strdup( siteURL ): NULL;
site->uses = siteUses; site->uses = siteUses;
site->lastUsed = siteLastUsed; site->lastUsed = siteLastUsed;
if (!user->redacted) { if (!user->redacted) {
// Clear Text // Clear Text
if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) { if (!mpw_update_masterKey( &masterKey, &masterKeyAlgorithm, site->algorithm, fullName, masterPassword )) {
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't derive master key." }; *error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't derive master key." };
return NULL; return NULL;
} }
@@ -792,9 +792,9 @@ static MPMarshalledUser *mpw_marshall_read_json(
else { else {
// Redacted // Redacted
if (siteContent && strlen( siteContent )) if (siteContent && strlen( siteContent ))
site->content = strdup( siteContent ); site->content = mpw_strdup( siteContent );
if (siteLoginName && strlen( siteLoginName )) if (siteLoginName && strlen( siteLoginName ))
site->loginContent = strdup( siteLoginName ); site->loginContent = mpw_strdup( siteLoginName );
} }
json_object_iter json_site_question; json_object_iter json_site_question;
@@ -813,32 +813,32 @@ static MPMarshalledUser *mpw_marshall_read_json(
else { else {
// Redacted // Redacted
if (answerContent && strlen( answerContent )) if (answerContent && strlen( answerContent ))
question->content = strdup( answerContent ); question->content = mpw_strdup( answerContent );
} }
} }
} }
json_object_put( json_file ); json_object_put( json_file );
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return user; return user;
} }
#endif #endif
MPMarshallInfo *mpw_marshall_read_info( MPMarshalInfo *mpw_marshal_read_info(
const char *in) { const char *in) {
MPMarshallInfo *info = malloc( sizeof( MPMarshallInfo ) ); MPMarshalInfo *info = malloc( sizeof( MPMarshalInfo ) );
*info = (MPMarshallInfo){ .format = MPMarshallFormatNone }; *info = (MPMarshalInfo){ .format = MPMarshalFormatNone };
if (in && strlen( in )) { if (in && strlen( in )) {
if (in[0] == '#') { if (in[0] == '#') {
*info = (MPMarshallInfo){ .format = MPMarshallFormatFlat }; *info = (MPMarshalInfo){ .format = MPMarshalFormatFlat };
mpw_marshall_read_flat_info( in, info ); mpw_marshal_read_flat_info( in, info );
} }
else if (in[0] == '{') { else if (in[0] == '{') {
*info = (MPMarshallInfo){ .format = MPMarshallFormatJSON }; *info = (MPMarshalInfo){ .format = MPMarshalFormatJSON };
#if MPW_JSON #if MPW_JSON
mpw_marshall_read_json_info( in, info ); mpw_marshal_read_json_info( in, info );
#endif #endif
} }
} }
@@ -846,30 +846,30 @@ MPMarshallInfo *mpw_marshall_read_info(
return info; return info;
} }
MPMarshalledUser *mpw_marshall_read( MPMarshalledUser *mpw_marshal_read(
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error) { const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error) {
switch (inFormat) { switch (inFormat) {
case MPMarshallFormatNone: case MPMarshalFormatNone:
*error = (MPMarshallError){ .type = MPMarshallSuccess }; *error = (MPMarshalError){ .type = MPMarshalSuccess };
return false; return false;
case MPMarshallFormatFlat: case MPMarshalFormatFlat:
return mpw_marshall_read_flat( in, masterPassword, error ); return mpw_marshal_read_flat( in, masterPassword, error );
#if MPW_JSON #if MPW_JSON
case MPMarshallFormatJSON: case MPMarshalFormatJSON:
return mpw_marshall_read_json( in, masterPassword, error ); return mpw_marshal_read_json( in, masterPassword, error );
#endif #endif
default: default:
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) }; *error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
return NULL; return NULL;
} }
} }
const MPMarshallFormat mpw_formatWithName( const MPMarshalFormat mpw_formatWithName(
const char *formatName) { const char *formatName) {
if (!formatName || !strlen( formatName )) if (!formatName || !strlen( formatName ))
return MPMarshallFormatNone; return MPMarshalFormatNone;
// Lower-case to standardize it. // Lower-case to standardize it.
size_t stdFormatNameSize = strlen( formatName ); size_t stdFormatNameSize = strlen( formatName );
@@ -878,46 +878,46 @@ const MPMarshallFormat mpw_formatWithName(
stdFormatName[c] = (char)tolower( formatName[c] ); stdFormatName[c] = (char)tolower( formatName[c] );
stdFormatName[stdFormatNameSize] = '\0'; stdFormatName[stdFormatNameSize] = '\0';
if (strncmp( mpw_nameForFormat( MPMarshallFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0) if (strncmp( mpw_nameForFormat( MPMarshalFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
return MPMarshallFormatNone; return MPMarshalFormatNone;
if (strncmp( mpw_nameForFormat( MPMarshallFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0) if (strncmp( mpw_nameForFormat( MPMarshalFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
return MPMarshallFormatFlat; return MPMarshalFormatFlat;
if (strncmp( mpw_nameForFormat( MPMarshallFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0) if (strncmp( mpw_nameForFormat( MPMarshalFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
return MPMarshallFormatJSON; return MPMarshalFormatJSON;
dbg( "Not a format name: %s\n", stdFormatName ); dbg( "Not a format name: %s", stdFormatName );
return (MPMarshallFormat)ERR; return (MPMarshalFormat)ERR;
} }
const char *mpw_nameForFormat( const char *mpw_nameForFormat(
const MPMarshallFormat format) { const MPMarshalFormat format) {
switch (format) { switch (format) {
case MPMarshallFormatNone: case MPMarshalFormatNone:
return "none"; return "none";
case MPMarshallFormatFlat: case MPMarshalFormatFlat:
return "flat"; return "flat";
case MPMarshallFormatJSON: case MPMarshalFormatJSON:
return "json"; return "json";
default: { default: {
dbg( "Unknown format: %d\n", format ); dbg( "Unknown format: %d", format );
return NULL; return NULL;
} }
} }
} }
const char *mpw_marshall_format_extension( const char *mpw_marshal_format_extension(
const MPMarshallFormat format) { const MPMarshalFormat format) {
switch (format) { switch (format) {
case MPMarshallFormatNone: case MPMarshalFormatNone:
return NULL; return NULL;
case MPMarshallFormatFlat: case MPMarshalFormatFlat:
return "mpsites"; return "mpsites";
case MPMarshallFormatJSON: case MPMarshalFormatJSON:
return "mpsites.json"; return "mpsites.json";
default: { default: {
dbg( "Unknown format: %d\n", format ); dbg( "Unknown format: %d", format );
return NULL; return NULL;
} }
} }

View File

@@ -16,8 +16,8 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
#ifndef _MPW_MARSHALL_H #ifndef _MPW_MARSHAL_H
#define _MPW_MARSHALL_H #define _MPW_MARSHAL_H
#include <time.h> #include <time.h>
@@ -25,37 +25,41 @@
//// Types. //// Types.
typedef mpw_enum( unsigned int, MPMarshallFormat ) { typedef mpw_enum( unsigned int, MPMarshalFormat ) {
/** Generate a key for authentication. */ /** Do not marshal. */
MPMarshallFormatNone, MPMarshalFormatNone,
/** Generate a key for authentication. */ /** Marshal using the line-based plain-text format. */
MPMarshallFormatFlat, MPMarshalFormatFlat,
/** Generate a name for identification. */ /** Marshal using the JSON structured format. */
MPMarshallFormatJSON, MPMarshalFormatJSON,
MPMarshallFormatDefault = MPMarshallFormatJSON, #if MPW_JSON
MPMarshalFormatDefault = MPMarshalFormatJSON,
#else
MPMarshalFormatDefault = MPMarshalFormatFlat,
#endif
}; };
typedef mpw_enum( unsigned int, MPMarshallErrorType ) { typedef mpw_enum( unsigned int, MPMarshalErrorType ) {
/** The marshalling operation completed successfully. */ /** The marshalling operation completed successfully. */
MPMarshallSuccess, MPMarshalSuccess,
/** An error in the structure of the marshall file interrupted marshalling. */ /** An error in the structure of the marshall file interrupted marshalling. */
MPMarshallErrorStructure, MPMarshalErrorStructure,
/** The marshall file uses an unsupported format version. */ /** The marshall file uses an unsupported format version. */
MPMarshallErrorFormat, MPMarshalErrorFormat,
/** A required value is missing or not specified. */ /** A required value is missing or not specified. */
MPMarshallErrorMissing, MPMarshalErrorMissing,
/** The given master password is not valid. */ /** The given master password is not valid. */
MPMarshallErrorMasterPassword, MPMarshalErrorMasterPassword,
/** An illegal value was specified. */ /** An illegal value was specified. */
MPMarshallErrorIllegal, MPMarshalErrorIllegal,
/** An internal system error interrupted marshalling. */ /** An internal system error interrupted marshalling. */
MPMarshallErrorInternal, MPMarshalErrorInternal,
}; };
typedef struct MPMarshallError { typedef struct MPMarshalError {
MPMarshallErrorType type; MPMarshalErrorType type;
const char *description; const char *description;
} MPMarshallError; } MPMarshalError;
typedef struct MPMarshalledQuestion { typedef struct MPMarshalledQuestion {
const char *keyword; const char *keyword;
@@ -95,34 +99,34 @@ typedef struct MPMarshalledUser {
MPMarshalledSite *sites; MPMarshalledSite *sites;
} MPMarshalledUser; } MPMarshalledUser;
typedef struct MPMarshallInfo { typedef struct MPMarshalInfo {
MPMarshallFormat format; MPMarshalFormat format;
MPAlgorithmVersion algorithm; MPAlgorithmVersion algorithm;
const char *fullName; const char *fullName;
const char *keyID; const char *keyID;
bool redacted; bool redacted;
time_t date; time_t date;
} MPMarshallInfo; } MPMarshalInfo;
//// Marshalling. //// Marshalling.
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */ /** Write the user and all associated data out to the given output buffer using the given marshalling format. */
bool mpw_marshall_write( bool mpw_marshal_write(
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error); char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error);
/** Try to read metadata on the sites in the input buffer. */ /** Try to read metadata on the sites in the input buffer. */
MPMarshallInfo *mpw_marshall_read_info( MPMarshalInfo *mpw_marshal_read_info(
const char *in); const char *in);
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */ /** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */
MPMarshalledUser *mpw_marshall_read( MPMarshalledUser *mpw_marshal_read(
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error); const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error);
//// Utilities. //// Utilities.
/** Create a new user object ready for marshalling. */ /** Create a new user object ready for marshalling. */
MPMarshalledUser *mpw_marshall_user( MPMarshalledUser *mpw_marshal_user(
const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion); const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
/** Create a new site attached to the given user object, ready for marshalling. */ /** Create a new site attached to the given user object, ready for marshalling. */
MPMarshalledSite *mpw_marshall_site( MPMarshalledSite *mpw_marshal_site(
MPMarshalledUser *user, MPMarshalledUser *user,
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion); 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. */ /** Create a new question attached to the given site object, ready for marshalling. */
@@ -130,7 +134,7 @@ MPMarshalledQuestion *mpw_marshal_question(
MPMarshalledSite *site, const char *keyword); MPMarshalledSite *site, const char *keyword);
/** Free the given user object and all associated data. */ /** Free the given user object and all associated data. */
bool mpw_marshal_info_free( bool mpw_marshal_info_free(
MPMarshallInfo **info); MPMarshalInfo **info);
bool mpw_marshal_free( bool mpw_marshal_free(
MPMarshalledUser **user); MPMarshalledUser **user);
@@ -139,17 +143,17 @@ bool mpw_marshal_free(
/** /**
* @return The purpose represented by the given name. * @return The purpose represented by the given name.
*/ */
const MPMarshallFormat mpw_formatWithName( const MPMarshalFormat mpw_formatWithName(
const char *formatName); const char *formatName);
/** /**
* @return The standard name for the given purpose. * @return The standard name for the given purpose.
*/ */
const char *mpw_nameForFormat( const char *mpw_nameForFormat(
const MPMarshallFormat format); const MPMarshalFormat format);
/** /**
* @return The file extension that's recommended for files that use the given marshalling format. * @return The file extension that's recommended for files that use the given marshalling format.
*/ */
const char *mpw_marshall_format_extension( const char *mpw_marshal_format_extension(
const MPMarshallFormat format); const MPMarshalFormat format);
#endif // _MPW_MARSHALL_H #endif // _MPW_MARSHAL_H

View File

@@ -22,6 +22,9 @@
#include "mpw-types.h" #include "mpw-types.h"
#include "mpw-util.h" #include "mpw-util.h"
const size_t MPMasterKeySize = 64;
const size_t MPSiteKeySize = 256 / 8; // Size of HMAC-SHA-256
const MPResultType mpw_typeWithName(const char *typeName) { const MPResultType mpw_typeWithName(const char *typeName) {
// Find what password type is represented by the type letter. // Find what password type is represented by the type letter.
@@ -40,22 +43,21 @@ const MPResultType mpw_typeWithName(const char *typeName) {
return MPResultTypeTemplatePIN; return MPResultTypeTemplatePIN;
if ('n' == typeName[0]) if ('n' == typeName[0])
return MPResultTypeTemplateName; return MPResultTypeTemplateName;
if ('p' == typeName[0])
return MPResultTypeTemplatePhrase;
if ('P' == typeName[0]) if ('P' == typeName[0])
return MPResultTypeStatefulPersonal; return MPResultTypeStatefulPersonal;
if ('D' == typeName[0]) if ('D' == typeName[0])
return MPResultTypeStatefulDevice; return MPResultTypeStatefulDevice;
if ('k' == typeName[0]) if ('K' == typeName[0])
return MPResultTypeDeriveKey; return MPResultTypeDeriveKey;
} }
// Lower-case and trim optionally leading "Generated" string from typeName to standardize it. // Lower-case typeName to standardize it.
size_t stdTypeNameOffset = 0;
size_t stdTypeNameSize = strlen( typeName ); size_t stdTypeNameSize = strlen( typeName );
if (strstr( typeName, "Generated" ) == typeName)
stdTypeNameSize -= (stdTypeNameOffset = strlen( "Generated" ));
char stdTypeName[stdTypeNameSize + 1]; char stdTypeName[stdTypeNameSize + 1];
for (size_t c = 0; c < stdTypeNameSize; ++c) for (size_t c = 0; c < stdTypeNameSize; ++c)
stdTypeName[c] = (char)tolower( typeName[c + stdTypeNameOffset] ); stdTypeName[c] = (char)tolower( typeName[c] );
stdTypeName[stdTypeNameSize] = '\0'; stdTypeName[stdTypeNameSize] = '\0';
// Find what password type is represented by the type name. // Find what password type is represented by the type name.
@@ -82,7 +84,7 @@ const MPResultType mpw_typeWithName(const char *typeName) {
if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0) if (strncmp( mpw_nameForType( MPResultTypeDeriveKey ), stdTypeName, strlen( stdTypeName ) ) == 0)
return MPResultTypeDeriveKey; return MPResultTypeDeriveKey;
dbg( "Not a generated type name: %s\n", stdTypeName ); dbg( "Not a generated type name: %s", stdTypeName );
return (MPResultType)ERR; return (MPResultType)ERR;
} }
@@ -112,7 +114,7 @@ const char *mpw_nameForType(MPResultType resultType) {
case MPResultTypeDeriveKey: case MPResultTypeDeriveKey:
return "key"; return "key";
default: { default: {
dbg( "Unknown password type: %d\n", resultType ); dbg( "Unknown password type: %d", resultType );
return NULL; return NULL;
} }
} }
@@ -121,7 +123,7 @@ const char *mpw_nameForType(MPResultType resultType) {
const char **mpw_templatesForType(MPResultType type, size_t *count) { const char **mpw_templatesForType(MPResultType type, size_t *count) {
if (!(type & MPResultTypeClassTemplate)) { if (!(type & MPResultTypeClassTemplate)) {
dbg( "Not a generated type: %d\n", type ); dbg( "Not a generated type: %d", type );
return NULL; return NULL;
} }
@@ -157,7 +159,7 @@ const char **mpw_templatesForType(MPResultType type, size_t *count) {
return mpw_alloc_array( count, const char *, return mpw_alloc_array( count, const char *,
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" ); "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
default: { default: {
dbg( "Unknown generated type: %d\n", type ); dbg( "Unknown generated type: %d", type );
return NULL; return NULL;
} }
} }
@@ -189,7 +191,7 @@ const MPKeyPurpose mpw_purposeWithName(const char *purposeName) {
if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0) if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
return MPKeyPurposeRecovery; return MPKeyPurposeRecovery;
dbg( "Not a purpose name: %s\n", stdPurposeName ); dbg( "Not a purpose name: %s", stdPurposeName );
return (MPKeyPurpose)ERR; return (MPKeyPurpose)ERR;
} }
@@ -203,7 +205,7 @@ const char *mpw_nameForPurpose(MPKeyPurpose purpose) {
case MPKeyPurposeRecovery: case MPKeyPurposeRecovery:
return "recovery"; return "recovery";
default: { default: {
dbg( "Unknown purpose: %d\n", purpose ); dbg( "Unknown purpose: %d", purpose );
return NULL; return NULL;
} }
} }
@@ -219,7 +221,7 @@ const char *mpw_scopeForPurpose(MPKeyPurpose purpose) {
case MPKeyPurposeRecovery: case MPKeyPurposeRecovery:
return "com.lyndir.masterpassword.answer"; return "com.lyndir.masterpassword.answer";
default: { default: {
dbg( "Unknown purpose: %d\n", purpose ); dbg( "Unknown purpose: %d", purpose );
return NULL; return NULL;
} }
} }
@@ -249,7 +251,7 @@ const char *mpw_charactersInClass(char characterClass) {
case ' ': case ' ':
return " "; return " ";
default: { default: {
dbg( "Unknown character class: %c\n", characterClass ); dbg( "Unknown character class: %c", characterClass );
return NULL; return NULL;
} }
} }

View File

@@ -35,10 +35,8 @@
//// Types. //// Types.
#define MPMasterKeySize 64 /* bytes */ extern const size_t MPMasterKeySize, MPSiteKeySize; /* bytes */
typedef const uint8_t *MPMasterKey; typedef const uint8_t *MPMasterKey, *MPSiteKey;
#define MPSiteKeySize (256 / 8) /* bytes */ // Size of HMAC-SHA-256
typedef const uint8_t *MPSiteKey;
typedef const char *MPKeyID; typedef const char *MPKeyID;
typedef mpw_enum( uint8_t, MPKeyPurpose ) { typedef mpw_enum( uint8_t, MPKeyPurpose ) {
@@ -72,30 +70,30 @@ typedef mpw_enum( uint16_t, MPSiteFeature ) {
// bit 0-3 | MPResultTypeClass | MPSiteFeature // bit 0-3 | MPResultTypeClass | MPSiteFeature
typedef mpw_enum( uint32_t, MPResultType ) { typedef mpw_enum( uint32_t, MPResultType ) {
/** pg^VMAUBk5x3p%HP%i4= */ /** 16: pg^VMAUBk5x3p%HP%i4= */
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
/** BiroYena8:Kixa */ /** 17: BiroYena8:Kixa */
MPResultTypeTemplateLong = 0x1 | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplateLong = 0x1 | MPResultTypeClassTemplate | 0x0,
/** BirSuj0- */ /** 18: BirSuj0- */
MPResultTypeTemplateMedium = 0x2 | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplateMedium = 0x2 | MPResultTypeClassTemplate | 0x0,
/** pO98MoD0 */ /** 19: Bir8 */
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
/** Bir8 */
MPResultTypeTemplateShort = 0x3 | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplateShort = 0x3 | MPResultTypeClassTemplate | 0x0,
/** 2798 */ /** 20: pO98MoD0 */
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
/** 21: 2798 */
MPResultTypeTemplatePIN = 0x5 | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplatePIN = 0x5 | MPResultTypeClassTemplate | 0x0,
/** birsujano */ /** 30: birsujano */
MPResultTypeTemplateName = 0xE | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplateName = 0xE | MPResultTypeClassTemplate | 0x0,
/** bir yennoquce fefi */ /** 31: bir yennoquce fefi */
MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0, MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0,
/** Custom saved password. */ /** 1056: Custom saved password. */
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent, MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
/** Custom saved password that should not be exported from the device. */ /** 2081: Custom saved password that should not be exported from the device. */
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate, MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
/** Derive a unique binary key. */ /** 4160: Derive a unique binary key. */
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative, MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
MPResultTypeDefault = MPResultTypeTemplateLong, MPResultTypeDefault = MPResultTypeTemplateLong,
}; };
@@ -111,6 +109,28 @@ typedef mpw_enum ( uint32_t, MPCounterValue ) {
MPCounterValueLast = UINT32_MAX, MPCounterValueLast = UINT32_MAX,
}; };
/** These colours are compatible with the original ANSI SGR. */
typedef mpw_enum( uint8_t, MPIdenticonColor ) {
MPIdenticonColorRed = 1,
MPIdenticonColorGreen,
MPIdenticonColorYellow,
MPIdenticonColorBlue,
MPIdenticonColorMagenta,
MPIdenticonColorCyan,
MPIdenticonColorWhite,
MPIdenticonColorFirst = MPIdenticonColorRed,
MPIdenticonColorLast = MPIdenticonColorWhite,
};
typedef struct {
const char *leftArm;
const char *body;
const char *rightArm;
const char *accessory;
MPIdenticonColor color;
} MPIdenticon;
//// Type utilities. //// Type utilities.
/** /**

View File

@@ -20,18 +20,15 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#if MPW_COLOR
#include <unistd.h>
#include <curses.h>
#include <term.h>
#endif
#if MPW_CPERCIVA #if MPW_CPERCIVA
#include <scrypt/crypto_scrypt.h> #include <scrypt/crypto_scrypt.h>
#include <scrypt/sha256.h> #include <scrypt/sha256.h>
#elif MPW_SODIUM #elif MPW_SODIUM
#include "sodium.h" #include "sodium.h"
#endif #endif
#define AES_ECB 0
#define AES_CBC 1
#include "aes.h"
#include "mpw-util.h" #include "mpw-util.h"
@@ -134,31 +131,38 @@ bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSi
return true; return true;
} }
bool __mpw_free(const void **buffer, const size_t bufferSize) { void mpw_zero(void *buffer, size_t bufferSize) {
uint8_t *b = buffer;
for (; bufferSize > 0; --bufferSize)
*b++ = 0;
}
bool __mpw_free(void **buffer, const size_t bufferSize) {
if (!buffer || !*buffer) if (!buffer || !*buffer)
return false; return false;
memset( (void *)*buffer, 0, bufferSize ); mpw_zero( *buffer, bufferSize );
free( (void *)*buffer ); free( *buffer );
*buffer = NULL; *buffer = NULL;
return true; return true;
} }
bool __mpw_free_string(const char **string) { bool __mpw_free_string(char **string) {
return *string && __mpw_free( (const void **)string, strlen( *string ) ); return *string && __mpw_free( (void **)string, strlen( *string ) );
} }
bool __mpw_free_strings(const char **strings, ...) { bool __mpw_free_strings(char **strings, ...) {
bool success = true; bool success = true;
va_list args; va_list args;
va_start( args, strings ); va_start( args, strings );
success &= mpw_free_string( strings ); success &= mpw_free_string( strings );
for (const char **string; (string = va_arg( args, const char ** ));) for (char **string; (string = va_arg( args, char ** ));)
success &= mpw_free_string( string ); success &= mpw_free_string( string );
va_end( args ); va_end( args );
@@ -207,7 +211,6 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
#if MPW_SODIUM #if MPW_SODIUM
if (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX || 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 || subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
contextSize < crypto_generichash_blake2b_BYTES_MIN || contextSize > crypto_generichash_blake2b_BYTES_MAX ||
(personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) { (personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) {
errno = EINVAL; errno = EINVAL;
free( subkey ); free( subkey );
@@ -215,12 +218,12 @@ uint8_t const *mpw_kdf_blake2b(const size_t subkeySize, const uint8_t *key, cons
} }
uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES]; uint8_t saltBuf[crypto_generichash_blake2b_SALTBYTES];
bzero( saltBuf, sizeof saltBuf ); mpw_zero( saltBuf, sizeof saltBuf );
if (id) if (id)
mpw_uint64( id, saltBuf ); mpw_uint64( id, saltBuf );
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES]; uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
bzero( personalBuf, sizeof saltBuf ); mpw_zero( personalBuf, sizeof personalBuf );
if (personal && strlen( personal )) if (personal && strlen( personal ))
memcpy( personalBuf, personal, strlen( personal ) ); memcpy( personalBuf, personal, strlen( personal ) );
@@ -265,50 +268,47 @@ uint8_t const *mpw_hash_hmac_sha256(const uint8_t *key, const size_t keySize, co
return mac; return mac;
} }
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, const size_t bufSize) { // We do our best to not fail on odd buf's, eg. non-padded cipher texts.
static uint8_t const *mpw_aes(bool encrypt, const uint8_t *key, const size_t keySize, const uint8_t *buf, size_t *bufSize) {
#if MPW_SODIUM if (!key || keySize < 16 || !*bufSize)
if (!key || keySize < crypto_stream_KEYBYTES)
return NULL; return NULL;
uint8_t nonce[crypto_stream_NONCEBYTES]; // IV = zero
bzero( (void *)nonce, sizeof( nonce ) ); uint8_t iv[16];
mpw_zero( iv, sizeof iv );
#pragma GCC diagnostic push // Add PKCS#7 padding
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
#pragma clang diagnostic push if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
#pragma clang diagnostic ignored "-Wdeprecated-declarations" encrypt += 16;
if (encrypt) { uint8_t aesBuf[aesSize];
uint8_t *const cipherBuf = malloc( bufSize ); memcpy( aesBuf, buf, *bufSize );
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) { memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
mpw_free( &cipherBuf, bufSize ); uint8_t *resultBuf = malloc( aesSize );
return NULL;
} if (encrypt)
return cipherBuf; AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
} else
else { AES_CBC_decrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
uint8_t *const plainBuf = malloc( bufSize ); mpw_zero( aesBuf, aesSize );
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) { mpw_zero( iv, 16 );
mpw_free( &plainBuf, bufSize );
return NULL; // Truncate PKCS#7 padding
} if (encrypt)
for (size_t c = 0; c < bufSize; ++c) *bufSize = aesSize;
plainBuf[c] = buf[c] ^ plainBuf[c]; else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
return plainBuf; *bufSize -= resultBuf[aesSize - 1];
}
#pragma clang diagnostic pop return resultBuf;
#pragma GCC diagnostic pop
#else
#error No crypto support for mpw_aes.
#endif
} }
uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, const size_t bufSize) { uint8_t const *mpw_aes_encrypt(const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize) {
return mpw_aes( true, key, keySize, plainBuf, bufSize ); return mpw_aes( true, key, keySize, plainBuf, bufSize );
} }
uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize) { uint8_t const *mpw_aes_decrypt(const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize) {
return mpw_aes( false, key, keySize, cipherBuf, bufSize ); return mpw_aes( false, key, keySize, cipherBuf, bufSize );
} }
@@ -338,7 +338,7 @@ const char *mpw_hotp(const uint8_t *key, size_t keySize, uint64_t movingFactor,
// Render the OTP as `digits` decimal digits. // Render the OTP as `digits` decimal digits.
otp %= (int)pow(10, digits); otp %= (int)pow(10, digits);
return strdup( mpw_str( "%0*d", digits, otp ) ); return mpw_strdup( mpw_str( "%0*d", digits, otp ) );
} }
#endif #endif
@@ -438,99 +438,6 @@ const char *mpw_hex_l(uint32_t number) {
return mpw_hex( &buf, sizeof( buf ) ); return mpw_hex( &buf, sizeof( buf ) );
} }
#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 errret;
if (!(termsetup = (setupterm( NULL, STDERR_FILENO, &errret ) == OK))) {
wrn( "Terminal doesn't support color (setupterm errret %d).\n", errret );
return false;
}
}
return true;
}
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) {
const char *leftArm[] = { "", "", "", "" };
const char *rightArm[] = { "", "", "", "" };
const char *body[] = { "", "", "", "", "", "" };
const char *accessory[] = {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};
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 MPW_COLOR
if (mpw_setupterm()) {
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
colorString = mpw_tputs( tparm( tgetstr( "AF", NULL ), colorIdentifier ), 1 );
resetString = mpw_tputs( tgetstr( "me", NULL ), 1 );
}
else
#endif
{
colorString = calloc( 1, sizeof( char ) );
resetString = calloc( 1, sizeof( char ) );
}
char *identicon = (char *)calloc( 256, sizeof( char ) );
snprintf( identicon, 256, "%s%s%s%s%s%s",
colorString,
leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))],
body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))],
rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))],
accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))],
resetString );
mpw_free( &identiconSeed, 32 );
mpw_free_strings( &colorString, &resetString, NULL );
return identicon;
}
/** /**
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte. * @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
*/ */
@@ -561,3 +468,31 @@ const size_t mpw_utf8_strlen(const char *utf8String) {
return charlen; return charlen;
} }
char *mpw_strdup(const char *src) {
if (!src)
return NULL;
size_t len = strlen( src );
char *dst = malloc( len + 1 );
memcpy( dst, src, len );
dst[len] = '\0';
return dst;
}
char *mpw_strndup(const char *src, size_t max) {
if (!src)
return NULL;
size_t len = 0;
for (; len < max && src[len] != '\0'; ++len);
char *dst = malloc( len + 1 );
memcpy( dst, src, len );
dst[len] = '\0';
return dst;
}

View File

@@ -25,49 +25,44 @@
#include "mpw-types.h" #include "mpw-types.h"
//// Logging. //// Logging.
extern int mpw_verbosity;
#ifndef mpw_log_do
#define mpw_log_do(level, format, ...) \
fprintf( stderr, format "\n", ##__VA_ARGS__ )
#endif
#ifndef mpw_log
#define mpw_log(level, ...) ({ \
if (mpw_verbosity >= level) { \
mpw_log_do( level, ##__VA_ARGS__ ); \
}; })
#endif
#ifndef trc #ifndef trc
extern int mpw_verbosity;
#define trc_level 3
/** Logging internal state. */ /** Logging internal state. */
#define trc(...) ({ \ #define trc_level 3
if (mpw_verbosity >= trc_level) \ #define trc(...) mpw_log( trc_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef dbg
#define dbg_level 2
/** Logging state and events interesting when investigating issues. */ /** Logging state and events interesting when investigating issues. */
#define dbg(...) ({ \ #define dbg_level 2
if (mpw_verbosity >= dbg_level) \ #define dbg(...) mpw_log( dbg_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef inf
#define inf_level 1
/** User messages. */ /** User messages. */
#define inf(...) ({ \ #define inf_level 1
if (mpw_verbosity >= inf_level) \ #define inf(...) mpw_log( inf_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef wrn
#define wrn_level 0
/** Recoverable issues and user suggestions. */ /** Recoverable issues and user suggestions. */
#define wrn(...) ({ \ #define wrn_level 0
if (mpw_verbosity >= wrn_level) \ #define wrn(...) mpw_log( wrn_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef err
#define err_level -1
/** Unrecoverable issues. */ /** Unrecoverable issues. */
#define err(...) ({ \ #define err_level -1
if (mpw_verbosity >= err_level) \ #define err(...) mpw_log( err_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif
#ifndef ftl
#define ftl_level -2
/** Issues that lead to abortion. */ /** Issues that lead to abortion. */
#define ftl(...) ({ \ #define ftl_level -2
if (mpw_verbosity >= ftl_level) \ #define ftl(...) mpw_log( ftl_level, ##__VA_ARGS__ )
fprintf( stderr, __VA_ARGS__ ); })
#endif #endif
#ifndef min #ifndef min
@@ -136,23 +131,25 @@ bool mpw_push_int(
* @return true if successful, false if reallocation failed. * @return true if successful, false if reallocation failed.
*/ */
#define mpw_realloc(buffer, bufferSize, deltaSize) \ #define mpw_realloc(buffer, bufferSize, deltaSize) \
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_realloc( (const void **)_b, bufferSize, deltaSize ); }) ({ __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); bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSize);
void mpw_zero(
void *buffer, size_t bufferSize);
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */ /** Free a buffer after zero'ing its contents, then set the reference to NULL. */
#define mpw_free(buffer, bufferSize) \ #define mpw_free(buffer, bufferSize) \
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (const void **)_b, bufferSize ); }) ({ __typeof__(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (void **)_b, bufferSize ); })
bool __mpw_free( bool __mpw_free(
const void **buffer, const size_t bufferSize); void **buffer, size_t bufferSize);
/** Free a string after zero'ing its contents, then set the reference to NULL. */ /** Free a string after zero'ing its contents, then set the reference to NULL. */
#define mpw_free_string(string) \ #define mpw_free_string(string) \
({ typeof(string) _s = string; const char *__s = *_s; (void)__s; __mpw_free_string( (const char **)_s ); }) ({ __typeof__(string) _s = string; const char *__s = *_s; (void)__s; __mpw_free_string( (char **)_s ); })
bool __mpw_free_string( bool __mpw_free_string(
const char **string); char **string);
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */ /** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
#define mpw_free_strings(strings, ...) \ #define mpw_free_strings(strings, ...) \
({ typeof(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (const char **)_s, __VA_ARGS__ ); }) ({ __typeof__(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (char **)_s, __VA_ARGS__ ); })
bool __mpw_free_strings( bool __mpw_free_strings(
const char **strings, ...); char **strings, ...);
//// Cryptographic functions. //// Cryptographic functions.
@@ -173,11 +170,11 @@ uint8_t const *mpw_hash_hmac_sha256(
/** Encrypt a plainBuf with the given key using AES-128-CBC. /** Encrypt a plainBuf with the given key using AES-128-CBC.
* @return A new bufSize allocated buffer containing the cipherBuf. */ * @return A new bufSize allocated buffer containing the cipherBuf. */
uint8_t const *mpw_aes_encrypt( uint8_t const *mpw_aes_encrypt(
const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, const size_t bufSize); const uint8_t *key, const size_t keySize, const uint8_t *plainBuf, size_t *bufSize);
/** Decrypt a cipherBuf with the given key using AES-128-CBC. /** Decrypt a cipherBuf with the given key using AES-128-CBC.
* @return A new bufSize allocated buffer containing the plainBuf. */ * @return A new bufSize allocated buffer containing the plainBuf. */
uint8_t const *mpw_aes_decrypt( uint8_t const *mpw_aes_decrypt(
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize); const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize);
/** Calculate an OTP using RFC-4226. /** Calculate an OTP using RFC-4226.
* @return A newly allocated string containing exactly `digits` decimal OTP digits. */ * @return A newly allocated string containing exactly `digits` decimal OTP digits. */
#if UNUSED #if UNUSED
@@ -201,13 +198,14 @@ MPKeyID mpw_id_buf(const void *buf, size_t length);
/** Compare two fingerprints for equality. /** Compare two fingerprints for equality.
* @return true if the buffers represent identical fingerprints. */ * @return true if the buffers represent identical fingerprints. */
bool mpw_id_buf_equals(const char *id1, const char *id2); bool mpw_id_buf_equals(const char *id1, const char *id2);
/** Encode a visual fingerprint for a user.
* @return A newly allocated string. */
const char *mpw_identicon(const char *fullName, const char *masterPassword);
//// String utilities. //// String utilities.
/** @return The amount of display characters in the given UTF-8 string. */ /** @return The amount of display characters in the given UTF-8 string. */
const size_t mpw_utf8_strlen(const char *utf8String); const size_t mpw_utf8_strlen(const char *utf8String);
/** Drop-in for POSIX strdup(3). */
char *mpw_strdup(const char *src);
/** Drop-in for POSIX strndup(3). */
char *mpw_strndup(const char *src, size_t max);
#endif // _MPW_UTIL_H #endif // _MPW_UTIL_H

View File

@@ -5,9 +5,10 @@ plugins {
description = 'Master Password Algorithm Implementation' description = 'Master Password Algorithm Implementation'
dependencies { dependencies {
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p10') { compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p11') {
exclude( module: 'joda-time' ) exclude( module: 'joda-time' )
} }
compile group: 'com.lyndir.lhunath.opal', name: 'opal-crypto', version: '1.6-p11'
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0' compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
compile group: 'org.jetbrains', name: 'annotations', version: '13.0' compile group: 'org.jetbrains', name: 'annotations', version: '13.0'

View File

@@ -23,7 +23,7 @@
<dependency> <dependency>
<groupId>com.lyndir.lhunath.opal</groupId> <groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-system</artifactId> <artifactId>opal-system</artifactId>
<version>1.6-p9</version> <version>1.6-p11</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>joda-time</groupId> <groupId>joda-time</groupId>
@@ -31,6 +31,11 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-crypto</artifactId>
<version>1.6-p11</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES --> <!-- EXTERNAL DEPENDENCIES -->
<dependency> <dependency>

View File

@@ -0,0 +1,99 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.MessageDigests;
import java.io.Serializable;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import javax.annotation.Nullable;
/**
* @see MPMasterKey.Version
*/
public interface MPAlgorithm {
/**
* mpw: validity for the time-based rolling counter.
*/
int mpw_otp_window = 5 * 60 /* s */;
/**
* mpw: Key ID hash.
*/
MessageDigests mpw_hash = MessageDigests.SHA256;
/**
* mpw: Site digest.
*/
MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
/**
* mpw: Platform-agnostic byte order.
*/
ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
/**
* mpw: Input character encoding.
*/
Charset mpw_charset = Charsets.UTF_8;
/**
* mpw: Master key size (byte).
*/
int mpw_dkLen = 64;
/**
* scrypt: Parallelization parameter.
*/
int scrypt_p = 2;
/**
* scrypt: Memory cost parameter.
*/
int scrypt_r = 8;
/**
* scrypt: CPU cost parameter.
*/
int scrypt_N = 32768;
MPMasterKey.Version getAlgorithmVersion();
byte[] masterKey(String fullName, char[] masterPassword);
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
@Nullable String keyContext);
String siteResult(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
String siteState(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
@Nullable String keyContext, MPResultType resultType, String resultParam);
}

View File

@@ -0,0 +1,248 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.base.*;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.crypto.CryptUtils;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.nio.*;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.annotation.Nullable;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
/**
* @author lhunath, 2014-08-30
* @see MPMasterKey.Version#V0
*/
public class MPAlgorithmV0 implements MPAlgorithm {
protected final Logger logger = Logger.get( getClass() );
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return MPMasterKey.Version.V0;
}
@Override
public byte[] masterKey(final String fullName, final char[] masterPassword) {
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
String keyScope = MPKeyPurpose.Authentication.getScope();
logger.trc( "keyScope: %s", keyScope );
// Calculate the master key salt.
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
// Calculate the master key.
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
scrypt_N, scrypt_r, scrypt_p );
byte[] masterPasswordBytes = bytesForChars( masterPassword );
byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
Arrays.fill( masterKeySalt, (byte) 0 );
Arrays.fill( masterPasswordBytes, (byte) 0 );
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
return masterKey;
}
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try {
//if (isAllowNative())
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
//else
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
}
catch (final GeneralSecurityException e) {
throw logger.bug( e );
}
}
@Override
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext) {
String keyScope = keyPurpose.getScope();
logger.trc( "keyScope: %s", keyScope );
// OTP counter value.
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
// Calculate the site seed.
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (keyContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
return sitePasswordSeedBytes;
}
@Override
public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
switch (resultType.getTypeClass()) {
case Template:
return sitePasswordFromTemplate( masterKey, siteKey, resultType, resultParam );
case Stateful:
return sitePasswordFromCrypt( masterKey, siteKey, resultType, resultParam );
case Derive:
return sitePasswordFromDerive( masterKey, siteKey, resultType, resultParam );
}
throw logger.bug( "Unsupported result type class: %s", resultType.getTypeClass() );
}
@Override
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
@Nullable final String resultParam) {
int[] _siteKey = new int[siteKey.length];
for (int i = 0; i < siteKey.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder );
Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
buf.position( 2 );
buf.put( siteKey[i] ).rewind();
_siteKey[i] = buf.getInt() & 0xFFFF;
}
// Determine the template.
Preconditions.checkState( _siteKey.length > 0 );
int templateIndex = _siteKey[0];
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
// Encode the password from the seed using the template.
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = _siteKey[i + 1];
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( " - class: %c, index: %5d (0x%2H) => character: %c",
characterClass.getIdentifier(), characterIndex, _siteKey[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
logger.trc( " => password: %s", password );
return password.toString();
}
@Override
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
@Nullable final String resultParam) {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
try {
// Base64-decode
byte[] cipherBuf = CryptUtils.decodeBase64( resultParam );
logger.trc( "b64 decoded: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
// Decrypt
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
return plainText;
}
catch (final BadPaddingException e) {
throw Throwables.propagate( e );
}
}
@Override
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
@Nullable final String resultParam) {
if (resultType == MPResultType.DeriveKey) {
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
if (resultParamInt == 0)
resultParamInt = 512;
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
int keySize = resultParamInt / 8;
logger.trc( "keySize: %d", keySize );
// Derive key
byte[] resultKey = null; // TODO: mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
if (resultKey == null)
throw logger.bug( "Could not derive result key." );
// Base64-encode
String b64Key = Verify.verifyNotNull( CryptUtils.encodeBase64( resultKey ) );
logger.trc( "b64 encoded -> key: %s", b64Key );
return b64Key;
} else
throw logger.bug( "Unsupported derived password type: %s", resultType );
}
@Override
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
try {
// Encrypt
byte[] cipherBuf = CryptUtils.encrypt( resultParam.getBytes( mpw_charset ), masterKey, true );
logger.trc( "cipherBuf: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
// Base64-encode
String cipherText = Verify.verifyNotNull( CryptUtils.encodeBase64( cipherBuf ) );
logger.trc( "b64 encoded -> cipherText: %s", cipherText );
return cipherText;
}
catch (final IllegalBlockSizeException e) {
throw logger.bug( e );
}
}
}

View File

@@ -0,0 +1,62 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
/**
* @see MPMasterKey.Version#V1
*
* @author lhunath, 2014-08-30
*/
public class MPAlgorithmV1 extends MPAlgorithmV0 {
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return MPMasterKey.Version.V1;
}
@Override
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
// Determine the template.
Preconditions.checkState( siteKey.length > 0 );
int templateIndex = siteKey[0] & 0xFF; // Convert to unsigned int.
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
// Encode the password from the seed using the template.
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = siteKey[i + 1] & 0xFF; // Convert to unsigned int.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( " - class: %c, index: %3d (0x%2H) => character: %c",
characterClass.getIdentifier(), characterIndex, siteKey[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
logger.trc( " => password: %s", password );
return password.toString();
}
}

View File

@@ -0,0 +1,74 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import javax.annotation.Nullable;
/**
* @see MPMasterKey.Version#V2
*
* @author lhunath, 2014-08-30
*/
public class MPAlgorithmV2 extends MPAlgorithmV1 {
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return MPMasterKey.Version.V2;
}
@Override
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext) {
String keyScope = keyPurpose.getScope();
logger.trc( "keyScope: %s", keyScope );
// OTP counter value.
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithm.mpw_otp_window * 1000)) * MPAlgorithm.mpw_otp_window );
// Calculate the site seed.
byte[] siteNameBytes = siteName.getBytes( MPAlgorithm.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithm.mpw_charset );
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (keyContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
byte[] sitePasswordSeedBytes = MPAlgorithm.mpw_digest.of( masterKey, sitePasswordInfo );
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
return sitePasswordSeedBytes;
}
}

View File

@@ -0,0 +1,67 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.primitives.Bytes;
import com.lyndir.lhunath.opal.system.CodeUtils;
import java.util.Arrays;
/**
* @see MPMasterKey.Version#V3
*
* @author lhunath, 2014-08-30
*/
public class MPAlgorithmV3 extends MPAlgorithmV2 {
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return MPMasterKey.Version.V3;
}
@Override
public byte[] masterKey(final String fullName, final char[] masterPassword) {
byte[] fullNameBytes = fullName.getBytes( MPAlgorithm.mpw_charset );
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
String keyScope = MPKeyPurpose.Authentication.getScope();
logger.trc( "keyScope: %s", keyScope );
// Calculate the master key salt.
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
// Calculate the master key.
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
MPAlgorithm.scrypt_N, MPAlgorithm.scrypt_r, MPAlgorithm.scrypt_p );
byte[] mpBytes = bytesForChars( masterPassword );
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
Arrays.fill( masterKeySalt, (byte) 0 );
Arrays.fill( mpBytes, (byte) 0 );
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
return masterKey;
}
}

View File

@@ -18,11 +18,8 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import com.google.common.base.Charsets; import org.joda.time.format.DateTimeFormatter;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import org.joda.time.format.ISODateTimeFormat;
import com.lyndir.lhunath.opal.system.MessageDigests;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
/** /**
@@ -32,68 +29,18 @@ public final class MPConstant {
/* Environment */ /* Environment */
/**
* mpw: default user name if one is not provided.
*/
public static final String env_userName = "MP_USERNAME";
/**
* mpw: default site type if one is not provided.
*
* @see MPSiteType#forOption(String)
*/
public static final String env_siteType = "MP_SITETYPE";
/**
* mpw: default site counter value if one is not provided.
*/
public static final String env_siteCounter = "MP_SITECOUNTER";
/** /**
* mpw: default path to look for run configuration files if the platform default is not desired. * mpw: default path to look for run configuration files if the platform default is not desired.
*/ */
public static final String env_rcDir = "MP_RCDIR"; public static final String env_rcDir = "MPW_RCDIR";
/** /**
* mpw: permit automatic update checks. * mpw: permit automatic update checks.
*/ */
public static final String env_checkUpdates = "MP_CHECKUPDATES"; public static final String env_checkUpdates = "MPW_CHECKUPDATES";
/* Algorithm */ /* Algorithm */
/**
* scrypt: CPU cost parameter.
*/
public static final int scrypt_N = 32768;
/**
* scrypt: Memory cost parameter.
*/
public static final int scrypt_r = 8;
/**
* scrypt: Parallelization parameter.
*/
public static final int scrypt_p = 2;
/**
* mpw: Master key size (byte).
*/
public static final int mpw_dkLen = 64;
/**
* mpw: Input character encoding.
*/
public static final Charset mpw_charset = Charsets.UTF_8;
/**
* mpw: Platform-agnostic byte order.
*/
public static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
/**
* mpw: Site digest.
*/
public static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
/**
* mpw: Key ID hash.
*/
public static final MessageDigests mpw_hash = MessageDigests.SHA256;
/**
* mpw: validity for the time-based rolling counter.
*/
public static final int mpw_counter_timeout = 5 * 60 /* s */;
public static final int MS_PER_S = 1000; public static final int MS_PER_S = 1000;
public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
} }

View File

@@ -16,13 +16,10 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
/**
*
* @author lhunath, 15-02-04
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import javax.annotation.ParametersAreNonnullByDefault; /**
* @author lhunath, 2017-09-21
*/
public class MPInvalidatedException extends Exception {
}

View File

@@ -0,0 +1,97 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Locale;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/**
* @author lhunath, 14-12-02
*/
public enum MPKeyPurpose {
/**
* Generate a key for authentication.
*/
Authentication( "authentication", "Generate a key for authentication.", "com.lyndir.masterpassword" ),
/**
* Generate a name for identification.
*/
Identification( "identification", "Generate a name for identification.", "com.lyndir.masterpassword.login" ),
/**
* Generate a recovery token.
*/
Recovery( "recovery", "Generate a recovery token.", "com.lyndir.masterpassword.answer" );
static final Logger logger = Logger.get( MPResultType.class );
private final String shortName;
private final String description;
private final String scope;
MPKeyPurpose(final String shortName, final String description, @NonNls final String scope) {
this.shortName = shortName;
this.description = description;
this.scope = scope;
}
public String getShortName() {
return shortName;
}
public String getDescription() {
return description;
}
public String getScope() {
return scope;
}
/**
* @param shortNamePrefix The name for the purpose to look up. It is a case insensitive prefix of the purpose's short name.
*
* @return The purpose registered with the given name.
*/
@Nullable
@Contract("!null -> !null")
public static MPKeyPurpose forName(@Nullable final String shortNamePrefix) {
if (shortNamePrefix == null)
return null;
for (final MPKeyPurpose type : values())
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
return type;
throw logger.bug( "No purpose for name: %s", shortNamePrefix );
}
public static MPKeyPurpose forInt(final int keyPurpose) {
return values()[keyPurpose];
}
public int toInt() {
return ordinal();
}
}

View File

@@ -0,0 +1,246 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Arrays;
import java.util.EnumMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-08-30
*/
public class MPMasterKey {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPMasterKey.class );
private final EnumMap<Version, byte[]> keyByVersion = new EnumMap<>( Version.class );
private final String fullName;
private final char[] masterPassword;
private boolean invalidated;
/**
* @param masterPassword The characters of the user's master password. Note: this array is held by reference and its contents
* invalidated on {@link #invalidate()}.
*/
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
public MPMasterKey(final String fullName, final char[] masterPassword) {
this.fullName = fullName;
this.masterPassword = masterPassword;
}
/**
* Derive the master key for a user based on their name and master password.
*
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
*/
private byte[] masterKey(final Version algorithmVersion)
throws MPInvalidatedException {
Preconditions.checkArgument( masterPassword.length > 0 );
if (invalidated)
throw new MPInvalidatedException();
byte[] key = keyByVersion.get( algorithmVersion );
if (key == null) {
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
logger.trc( "fullName: %s", fullName );
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex( idForBytes( bytesForChars( masterPassword ) ) ) );
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
}
return key;
}
/**
* Derive the master key for a user based on their name and master password.
*
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
*/
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final Version algorithmVersion)
throws MPInvalidatedException {
Preconditions.checkArgument( !siteName.isEmpty() );
byte[] masterKey = masterKey( algorithmVersion );
logger.trc( "-- mpw_siteKey (algorithm: %d)", algorithmVersion.toInt() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %s", siteCounter );
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
logger.trc( "keyContext: %s", keyContext );
return algorithmVersion.getAlgorithm().siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
}
/**
* Generate a site result token.
*
* @param siteName A site identifier.
* @param siteCounter The result identifier.
* @param keyPurpose The intended purpose for this site result.
* @param keyContext A site-scoped result modifier.
* @param resultType The type of result to generate.
* @param resultParam A parameter for the resultType. For stateful result types, the output of
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
*
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
*/
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
final Version algorithmVersion)
throws MPInvalidatedException {
byte[] masterKey = masterKey( algorithmVersion );
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
logger.trc( "-- mpw_siteResult (algorithm: %d)", algorithmVersion.toInt() );
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
logger.trc( "resultParam: %s", resultParam );
return algorithmVersion.getAlgorithm().siteResult(
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
}
/**
* Encrypt a stateful site token for persistence.
*
* @param siteName A site identifier.
* @param siteCounter The result identifier.
* @param keyPurpose The intended purpose for the site token.
* @param keyContext A site-scoped key modifier.
* @param resultType The type of result token to encrypt.
* @param resultParam The result token desired from
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
*
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
*/
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
final Version algorithmVersion)
throws MPInvalidatedException {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
byte[] masterKey = masterKey( algorithmVersion );
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( MPAlgorithm.mpw_charset ).length, resultParam );
return algorithmVersion.getAlgorithm().siteState(
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
}
@Nonnull
public String getFullName() {
return fullName;
}
/**
* Calculate an identifier for the master key.
*
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
*/
public byte[] getKeyID(final Version algorithmVersion)
throws MPInvalidatedException {
return idForBytes( masterKey( algorithmVersion ) );
}
/**
* Wipe this key's secrets from memory, making the object permanently unusable.
*/
public void invalidate() {
invalidated = true;
for (final byte[] key : keyByVersion.values())
Arrays.fill( key, (byte) 0 );
Arrays.fill( masterPassword, (char) 0 );
}
/**
* The algorithm iterations.
*/
public enum Version {
/**
* bugs:
* - does math with chars whose signedness was platform-dependent.
* - miscounted the byte-length for multi-byte site names.
* - miscounted the byte-length for multi-byte user names.
*/
V0( new MPAlgorithmV0() ),
/**
* bugs:
* - miscounted the byte-length for multi-byte site names.
* - miscounted the byte-length for multi-byte user names.
*/
V1( new MPAlgorithmV1() ),
/**
* bugs:
* - miscounted the byte-length for multi-byte user names.
*/
V2( new MPAlgorithmV2() ),
/**
* bugs:
* - no known issues.
*/
V3( new MPAlgorithmV3() );
public static final Version CURRENT = V3;
private final MPAlgorithm algorithm;
Version(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
public MPAlgorithm getAlgorithm() {
return algorithm;
}
public static Version fromInt(final int algorithmVersion) {
return values()[algorithmVersion];
}
public int toInt() {
return ordinal();
}
}
}

View File

@@ -24,7 +24,6 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.*; import java.util.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/** /**
@@ -32,15 +31,21 @@ import org.jetbrains.annotations.NonNls;
* *
* @author lhunath * @author lhunath
*/ */
public enum MPSiteType { public enum MPResultType {
// bit 0-3 | MPResultTypeClass | MPSiteFeature
GeneratedMaximum( "Max", "20 characters, contains symbols.", // /**
ImmutableList.of( "x", "max", "maximum" ), // NON-NLS * pg^VMAUBk5x3p%HP%i4=
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), // */
MPSiteTypeClass.Generated, 0x0 ), GeneratedMaximum( "maximum", "20 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ),
new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPResultTypeClass.Template, 0x0 ),
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", // /**
ImmutableList.of( "l", "long" ), // NON-NLS * BiroYena8:Kixa
*/
GeneratedLong( "long", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ), ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ), new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
@@ -52,65 +57,92 @@ public enum MPSiteType {
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ), new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ), new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
new MPTemplate( "CvccCvcvCvccno" ) ), // new MPTemplate( "CvccCvcvCvccno" ) ), //
MPSiteTypeClass.Generated, 0x1 ), MPResultTypeClass.Template, 0x1 ),
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", // /**
ImmutableList.of( "m", "med", "medium" ), // NON-NLS * BirSuj0-
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), // */
MPSiteTypeClass.Generated, 0x2 ), GeneratedMedium( "medium", "Copy-friendly, 8 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcnoCvc" ),
new MPTemplate( "CvcCvcno" ) ), //
MPResultTypeClass.Template, 0x2 ),
GeneratedBasic( "Basic", "8 characters, no symbols.", // /**
ImmutableList.of( "b", "basic" ), // NON-NLS * pO98MoD0
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), // */
MPSiteTypeClass.Generated, 0x3 ), GeneratedBasic( "basic", "8 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "aaanaaan" ),
new MPTemplate( "aannaaan" ),
new MPTemplate( "aaannaaa" ) ), //
MPResultTypeClass.Template, 0x3 ),
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", // /**
ImmutableList.of( "s", "short" ), // NON-NLS * Bir8
*/
GeneratedShort( "short", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "Cvcn" ) ), // ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPSiteTypeClass.Generated, 0x4 ), MPResultTypeClass.Template, 0x4 ),
GeneratedPIN( "PIN", "4 numbers.", // /**
ImmutableList.of( "i", "pin" ), // NON-NLS * 2798
*/
GeneratedPIN( "pin", "4 numbers.", //
ImmutableList.of( new MPTemplate( "nnnn" ) ), // ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPSiteTypeClass.Generated, 0x5 ), MPResultTypeClass.Template, 0x5 ),
GeneratedName( "Name", "9 letter name.", // /**
ImmutableList.of( "n", "name" ), // NON-NLS * birsujano
*/
GeneratedName( "name", "9 letter name.", //
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), // ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPSiteTypeClass.Generated, 0xE ), MPResultTypeClass.Template, 0xE ),
GeneratedPhrase( "Phrase", "20 character sentence.", // /**
ImmutableList.of( "p", "phrase" ), // NON-NLS * bir yennoquce fefi
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ), */
GeneratedPhrase( "phrase", "20 character sentence.", //
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), // new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
MPSiteTypeClass.Generated, 0xF ), MPResultTypeClass.Template, 0xF ),
StoredPersonal( "Personal", "AES-encrypted, exportable.", // /**
ImmutableList.of( "personal" ), // NON-NLS * Custom saved password.
*/
StoredPersonal( "personal", "AES-encrypted, exportable.", //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ), MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ),
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", // /**
ImmutableList.of( "device" ), // NON-NLS * Custom saved password that should not be exported from the device.
*/
StoredDevicePrivate( "device", "AES-encrypted, not exported.", //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate ); MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ),
static final Logger logger = Logger.get( MPSiteType.class ); /**
* Derive a unique binary key.
*/
DeriveKey( "key", "Encryption key.", //
ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
public static final MPResultType DEFAULT = GeneratedLong;
static final Logger logger = Logger.get( MPResultType.class );
private final String shortName; private final String shortName;
private final String description; private final String description;
private final List<String> options;
private final List<MPTemplate> templates; private final List<MPTemplate> templates;
private final MPSiteTypeClass typeClass; private final MPResultTypeClass typeClass;
private final int typeIndex; private final int typeIndex;
private final Set<MPSiteFeature> typeFeatures; private final Set<MPSiteFeature> typeFeatures;
MPSiteType(final String shortName, final String description, final List<String> options, final List<MPTemplate> templates, MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) { final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
this.shortName = shortName; this.shortName = shortName;
this.description = description; this.description = description;
this.options = options;
this.templates = templates; this.templates = templates;
this.typeClass = typeClass; this.typeClass = typeClass;
this.typeIndex = typeIndex; this.typeIndex = typeIndex;
@@ -131,11 +163,7 @@ public enum MPSiteType {
return description; return description;
} }
public List<String> getOptions() { public MPResultTypeClass getTypeClass() {
return options;
}
public MPSiteTypeClass getTypeClass() {
return typeClass; return typeClass;
} }
@@ -154,35 +182,22 @@ public enum MPSiteType {
} }
/** /**
* @param option The option to select a type with. It is matched case insensitively. * @param shortNamePrefix The name for the type to look up. It is a case insensitive prefix of the type's short name.
*
* @return The type registered for the given option.
*/
public static MPSiteType forOption(final String option) {
for (final MPSiteType type : values())
if (type.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
return type;
throw logger.bug( "No type for option: %s", option );
}
/**
* @param name The name fromInt the type to look up. It is matched case insensitively.
* *
* @return The type registered with the given name. * @return The type registered with the given name.
*/ */
@Nullable
@Contract("!null -> !null") @Contract("!null -> !null")
public static MPSiteType forName(@Nullable final String name) { public static MPResultType forName(@Nullable final String shortNamePrefix) {
if (name == null) if (shortNamePrefix == null)
return null; return null;
for (final MPSiteType type : values()) for (final MPResultType type : values())
if (type.name().equalsIgnoreCase( name )) if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
return type; return type;
throw logger.bug( "No type for name: %s", name ); throw logger.bug( "No type for name: %s", shortNamePrefix );
} }
/** /**
@@ -190,10 +205,10 @@ public enum MPSiteType {
* *
* @return All types that support the given class. * @return All types that support the given class.
*/ */
public static ImmutableList<MPSiteType> forClass(final MPSiteTypeClass typeClass) { public static ImmutableList<MPResultType> forClass(final MPResultTypeClass typeClass) {
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder(); ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
for (final MPSiteType type : values()) for (final MPResultType type : values())
if (type.getTypeClass() == typeClass) if (type.getTypeClass() == typeClass)
types.add( type ); types.add( type );
@@ -205,27 +220,28 @@ public enum MPSiteType {
* *
* @return The type registered with the given type. * @return The type registered with the given type.
*/ */
public static MPSiteType forType(final int type) { public static MPResultType forType(final int type) {
for (final MPSiteType siteType : values()) for (final MPResultType resultType : values())
if (siteType.getType() == type) if (resultType.getType() == type)
return siteType; return resultType;
throw logger.bug( "No type: %s", type ); throw logger.bug( "No type: %s", type );
} }
/** /**
* @param mask The mask for which we look up types. * @param mask The type mask for which we look up types.
* *
* @return All types that support the given mask. * @return All types that support the given mask's class & features.
*/ */
public static ImmutableList<MPSiteType> forMask(final int mask) { public static ImmutableList<MPResultType> forMask(final int mask) {
int typeMask = mask & ~0xF; int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
for (final MPSiteType siteType : values()) ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
if (((siteType.getType() & ~0xF) & typeMask) != 0) for (final MPResultType resultType : values())
types.add( siteType ); if (((resultType.getType() & ~0xF) & typeMask) != 0)
types.add( resultType );
return types.build(); return types.build();
} }

View File

@@ -0,0 +1,51 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPResultTypeClass {
// bit 4 - 9
/**
* Use the site key to generate a password from a template.
*/
Template( 1 << 4 ),
/**
* Use the site key to encrypt and decrypt a stateful entity.
*/
Stateful( 1 << 5 ),
/**
* Use the site key to derive a site-specific object.
*/
Derive( 1 << 6 );
private final int mask;
MPResultTypeClass(final int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
}

View File

@@ -24,6 +24,7 @@ package com.lyndir.masterpassword;
* @author lhunath * @author lhunath
*/ */
public enum MPSiteFeature { public enum MPSiteFeature {
// bit 10 - 15
/** /**
* Export the key-protected content data. * Export the key-protected content data.
@@ -33,7 +34,12 @@ public enum MPSiteFeature {
/** /**
* Never export content. * Never export content.
*/ */
DevicePrivate( 1 << 11 ); DevicePrivate( 1 << 11 ),
/**
* Don't use this as the primary authentication result type.
*/
Alternative( 1 << 12 );
MPSiteFeature(final int mask) { MPSiteFeature(final int mask) {
this.mask = mask; this.mask = mask;

View File

@@ -1,103 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/**
* @author lhunath, 14-12-02
*/
public enum MPSiteVariant {
Password( "Generate a key for authentication.", "Doesn't currently use a context.", //
ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), // NON-NLS
Login( "Generate a name for identification.", "Doesn't currently use a context.", //
ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), // NON-NLS
Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", //
ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); // NON-NLS
static final Logger logger = Logger.get( MPSiteType.class );
private final String description;
private final String contextDescription;
private final List<String> options;
private final String scope;
MPSiteVariant(final String description, final String contextDescription, final List<String> options, @NonNls final String scope) {
this.contextDescription = contextDescription;
this.options = options;
this.description = description;
this.scope = scope;
}
public String getDescription() {
return description;
}
public String getContextDescription() {
return contextDescription;
}
public List<String> getOptions() {
return options;
}
public String getScope() {
return scope;
}
/**
* @param option The option to select a variant with. It is matched case insensitively.
*
* @return The variant registered for the given option.
*/
public static MPSiteVariant forOption(final String option) {
for (final MPSiteVariant variant : values())
if (variant.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
return variant;
throw logger.bug( "No variant for option: %s", option );
}
/**
* @param name The name fromInt the variant to look up. It is matched case insensitively.
*
* @return The variant registered with the given name.
*/
@Contract("!null -> !null")
public static MPSiteVariant forName(@Nullable final String name) {
if (name == null)
return null;
for (final MPSiteVariant type : values())
if (type.name().equalsIgnoreCase( name ))
return type;
throw logger.bug( "No variant for name: %s", name );
}
}

View File

@@ -0,0 +1,53 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.primitives.UnsignedInteger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Arrays;
/**
* @author lhunath, 2017-09-20
*/
public final class MPUtils {
public static byte[] bytesForInt(final int number) {
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number ).array();
}
public static byte[] bytesForInt(final UnsignedInteger number) {
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number.intValue() ).array();
}
public static byte[] bytesForChars(final char[] characters) {
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get( bytes );
Arrays.fill( byteBuffer.array(), (byte) 0 );
return bytes;
}
public static byte[] idForBytes(final byte[] bytes) {
return MPAlgorithm.mpw_hash.of( bytes );
}
}

View File

@@ -1,219 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Arrays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-08-30
*/
public abstract class MasterKey {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKey.class );
private static boolean allowNativeByDefault = true;
@Nonnull
private final String fullName;
private boolean allowNative = allowNativeByDefault;
@Nullable
private byte[] masterKey;
@SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final String fullName, final char[] masterPassword) {
return create( Version.CURRENT, fullName, masterPassword );
}
@Nonnull
@SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final Version version, final String fullName, final char[] masterPassword) {
switch (version) {
case V0:
return new MasterKeyV0( fullName ).revalidate( masterPassword );
case V1:
return new MasterKeyV1( fullName ).revalidate( masterPassword );
case V2:
return new MasterKeyV2( fullName ).revalidate( masterPassword );
case V3:
return new MasterKeyV3( fullName ).revalidate( masterPassword );
}
throw new UnsupportedOperationException( strf( "Unsupported version: %s", version ) );
}
public static boolean isAllowNativeByDefault() {
return allowNativeByDefault;
}
/**
* Native libraries are useful for speeding up the performance of cryptographical functions.
* Sometimes, however, we may prefer to use Java-only code.
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
* <p/>
* This setter affects the default setting for any newly created {@link MasterKey}s.
*
* @param allowNative false to disallow the use of native libraries.
*/
public static void setAllowNativeByDefault(final boolean allowNative) {
allowNativeByDefault = allowNative;
}
protected MasterKey(@Nonnull final String fullName) {
this.fullName = fullName;
logger.trc( "fullName: %s", fullName );
}
@Nullable
@SuppressWarnings("MethodCanBeVariableArityMethod")
protected abstract byte[] deriveKey(char[] masterPassword);
public abstract Version getAlgorithmVersion();
@Nonnull
public String getFullName() {
return fullName;
}
public boolean isAllowNative() {
return allowNative;
}
public MasterKey setAllowNative(final boolean allowNative) {
this.allowNative = allowNative;
return this;
}
@Nonnull
protected byte[] getKey() {
Preconditions.checkState( isValid() );
return Preconditions.checkNotNull( masterKey );
}
public byte[] getKeyID() {
return idForBytes( getKey() );
}
public abstract String encode(@Nonnull String siteName, MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
MPSiteVariant siteVariant, @Nullable String siteContext);
public boolean isValid() {
return masterKey != null;
}
public void invalidate() {
if (masterKey != null) {
Arrays.fill( masterKey, (byte) 0 );
masterKey = null;
}
}
@SuppressWarnings("MethodCanBeVariableArityMethod")
public MasterKey revalidate(final char[] masterPassword) {
invalidate();
logger.trc( "masterPassword: %s", new String( masterPassword ) );
long start = System.currentTimeMillis();
masterKey = deriveKey( masterPassword );
if (masterKey == null)
logger.dbg( "masterKey calculation failed after %.2fs.", (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
else
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
(double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
return this;
}
protected abstract byte[] bytesForInt(int number);
protected abstract byte[] bytesForInt(@Nonnull UnsignedInteger number);
protected abstract byte[] idForBytes(byte[] bytes);
public enum Version {
/**
* bugs:
* - does math with chars whose signedness was platform-dependent.
* - miscounted the byte-length fromInt multi-byte site names.
* - miscounted the byte-length fromInt multi-byte full names.
*/
V0,
/**
* bugs:
* - miscounted the byte-length fromInt multi-byte site names.
* - miscounted the byte-length fromInt multi-byte full names.
*/
V1,
/**
* bugs:
* - miscounted the byte-length fromInt multi-byte full names.
*/
V2,
/**
* bugs:
* - no known issues.
*/
V3;
public static final Version CURRENT = V3;
public static Version fromInt(final int algorithmVersion) {
return values()[algorithmVersion];
}
public int toInt() {
return ordinal();
}
public String toBundleVersion() {
switch (this) {
case V0:
return "1.0";
case V1:
return "2.0";
case V2:
return "2.1";
case V3:
return "2.2";
}
throw new UnsupportedOperationException( strf( "Unsupported version: %s", this ) );
}
}
}

View File

@@ -1,170 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
* - V1: miscounted the byte-length fromInt multi-byte site names.
* - V0: does math with chars whose signedness was platform-dependent.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV0 extends MasterKey {
private static final int MP_intLen = 32;
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV0.class );
public MasterKeyV0(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V0;
}
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
String fullName = getFullName();
byte[] fullNameBytes = fullName.getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
return scrypt( masterKeySalt, mpBytes );
}
@Nullable
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try {
if (isAllowNative())
return SCrypt.scrypt( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
else
return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
}
catch (final GeneralSecurityException e) {
logger.bug( e );
return null;
}
finally {
Arrays.fill( mpBytes, (byte) 0 );
}
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeedBytes = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
Arrays.fill( buf.array(), (byte) ((sitePasswordSeedBytes[i] > 0)? 0x00: 0xFF) );
buf.position( 2 );
buf.put( sitePasswordSeedBytes[i] ).rewind();
sitePasswordSeed[i] = buf.getInt() & 0xFFFF;
}
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0];
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1];
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
@Override
protected byte[] bytesForInt(final int number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number ).array();
}
@Override
protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number.intValue() ).array();
}
@Override
protected byte[] idForBytes(final byte[] bytes) {
return MPConstant.mpw_hash.of( bytes );
}
}

View File

@@ -1,103 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
* - V1: miscounted the byte-length fromInt multi-byte site names.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV1 extends MasterKeyV0 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV1.class );
public MasterKeyV1(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V1;
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
}

View File

@@ -1,102 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV2 extends MasterKeyV1 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV2.class );
public MasterKeyV2(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V2;
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
}

View File

@@ -1,69 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.primitives.Bytes;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Arrays;
import javax.annotation.Nullable;
/**
* bugs:
* - no known issues.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV3 extends MasterKeyV2 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV3.class );
public MasterKeyV3(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V3;
}
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
byte[] fullNameBytes = getFullName().getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
return scrypt( masterKeySalt, mpBytes );
}
}

View File

@@ -1,19 +0,0 @@
package com.lyndir.masterpassword.model;
/**
* @author lhunath, 14-12-17
*/
public class IncorrectMasterPasswordException extends Exception {
private final MPUser user;
public IncorrectMasterPasswordException(final MPUser user) {
super( "Incorrect master password for user: " + user.getFullName() );
this.user = user;
}
public MPUser getUser() {
return user;
}
}

View File

@@ -0,0 +1,205 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*;
import javax.annotation.Nullable;
import org.joda.time.Instant;
/**
* @author lhunath, 14-12-05
*/
public class MPFileSite extends MPSite {
private final MPFileUser user;
private String siteName;
@Nullable
private String siteContent;
private UnsignedInteger siteCounter;
private MPResultType resultType;
private MPMasterKey.Version algorithmVersion;
@Nullable
private String loginContent;
@Nullable
private MPResultType loginType;
@Nullable
private String url;
private int uses;
private Instant lastUsed;
public MPFileSite(final MPFileUser user, final String siteName) {
this( user, siteName, DEFAULT_COUNTER, MPResultType.DEFAULT, MPMasterKey.Version.CURRENT );
}
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
final MPMasterKey.Version algorithmVersion) {
this.user = user;
this.siteName = siteName;
this.siteCounter = siteCounter;
this.resultType = resultType;
this.algorithmVersion = algorithmVersion;
this.lastUsed = new Instant();
}
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
final UnsignedInteger siteCounter,
final MPResultType resultType, final MPMasterKey.Version algorithmVersion,
@Nullable final String loginContent, @Nullable final MPResultType loginType,
@Nullable final String url, final int uses, final Instant lastUsed) {
this.user = user;
this.siteName = siteName;
this.siteContent = siteContent;
this.siteCounter = siteCounter;
this.resultType = resultType;
this.algorithmVersion = algorithmVersion;
this.loginContent = loginContent;
this.loginType = loginType;
this.url = url;
this.uses = uses;
this.lastUsed = lastUsed;
}
public String resultFor(final MPMasterKey masterKey)
throws MPInvalidatedException {
return resultFor( masterKey, MPKeyPurpose.Authentication, null );
}
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
throws MPInvalidatedException {
return resultFor( masterKey, keyPurpose, keyContext, getSiteContent() );
}
public String loginFor(final MPMasterKey masterKey)
throws MPInvalidatedException {
if (loginType == null)
loginType = MPResultType.GeneratedName;
return loginFor( masterKey, loginType, loginContent );
}
public MPFileUser getUser() {
return user;
}
@Override
public String getSiteName() {
return siteName;
}
@Override
public void setSiteName(final String siteName) {
this.siteName = siteName;
}
@Nullable
public String getSiteContent() {
return siteContent;
}
public void setSitePassword(final MPMasterKey masterKey, @Nullable final MPResultType resultType, @Nullable final String result)
throws MPInvalidatedException {
this.resultType = resultType;
if (result == null)
this.siteContent = null;
else
this.siteContent = masterKey.siteState(
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, getAlgorithmVersion() );
}
@Override
public UnsignedInteger getSiteCounter() {
return siteCounter;
}
@Override
public void setSiteCounter(final UnsignedInteger siteCounter) {
this.siteCounter = siteCounter;
}
@Override
public MPResultType getResultType() {
return resultType;
}
@Override
public void setResultType(final MPResultType resultType) {
this.resultType = resultType;
}
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return algorithmVersion;
}
@Override
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
this.algorithmVersion = algorithmVersion;
}
@Nullable
public MPResultType getLoginType() {
return loginType;
}
@Nullable
public String getLoginContent() {
return loginContent;
}
public void setLoginName(final MPMasterKey masterKey, @Nullable final MPResultType loginType, @Nullable final String result)
throws MPInvalidatedException {
this.loginType = loginType;
if (this.loginType != null)
if (result == null)
this.loginContent = null;
else
this.loginContent = masterKey.siteState(
siteName, DEFAULT_COUNTER, MPKeyPurpose.Identification, null, this.loginType, result, algorithmVersion );
}
@Nullable
public String getUrl() {
return url;
}
public void setUrl(@Nullable final String url) {
this.url = url;
}
public int getUses() {
return uses;
}
public Instant getLastUsed() {
return lastUsed;
}
public void use() {
uses++;
lastUsed = new Instant();
user.use();
}
}

View File

@@ -0,0 +1,172 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import com.google.common.collect.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.*;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.*;
/**
* @author lhunath, 14-12-07
*/
public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileUser> {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUser.class );
private final String fullName;
private final Collection<MPFileSite> sites = Sets.newHashSet();
@Nullable
private byte[] keyID;
private MPMasterKey.Version algorithmVersion;
private int avatar;
private MPResultType defaultType;
private ReadableInstant lastUsed;
public MPFileUser(final String fullName) {
this( fullName, null, MPMasterKey.Version.CURRENT );
}
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
this( fullName, keyID, algorithmVersion, 0, MPResultType.DEFAULT, new Instant() );
}
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion, final int avatar,
final MPResultType defaultType, final ReadableInstant lastUsed) {
this.fullName = fullName;
this.keyID = (keyID == null)? null: keyID.clone();
this.algorithmVersion = algorithmVersion;
this.avatar = avatar;
this.defaultType = defaultType;
this.lastUsed = lastUsed;
}
@Override
public String getFullName() {
return fullName;
}
@Override
public MPMasterKey.Version getAlgorithmVersion() {
return algorithmVersion;
}
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
this.algorithmVersion = algorithmVersion;
}
@Override
public int getAvatar() {
return avatar;
}
public void setAvatar(final int avatar) {
this.avatar = avatar;
}
public MPResultType getDefaultType() {
return defaultType;
}
public void setDefaultType(final MPResultType defaultType) {
this.defaultType = defaultType;
}
public ReadableInstant getLastUsed() {
return lastUsed;
}
public void use() {
lastUsed = new Instant();
}
public Iterable<MPFileSite> getSites() {
return sites;
}
@Override
public void addSite(final MPFileSite site) {
sites.add( site );
}
@Override
public void deleteSite(final MPFileSite site) {
sites.remove( site );
}
@Override
public Collection<MPFileSite> findSites(final String query) {
ImmutableList.Builder<MPFileSite> results = ImmutableList.builder();
for (final MPFileSite site : getSites())
if (site.getSiteName().startsWith( query ))
results.add( site );
return results.build();
}
/**
* Performs an authentication attempt against the keyID for this user.
*
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
*
* @param masterPassword The password to authenticate with.
*
* @return The master key for the user if authentication was successful.
*
* @throws MPIncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/
@Nonnull
@Override
public MPMasterKey authenticate(final char[] masterPassword)
throws MPIncorrectMasterPasswordException {
try {
key = new MPMasterKey( getFullName(), masterPassword );
if ((keyID == null) || (keyID.length == 0))
keyID = key.getKeyID( algorithmVersion );
else if (!Arrays.equals( key.getKeyID( algorithmVersion ), keyID ))
throw new MPIncorrectMasterPasswordException( this );
return key;
}
catch (final MPInvalidatedException e) {
throw logger.bug( e );
}
}
void save()
throws MPInvalidatedException {
MPFileUserManager.get().save( this, getMasterKey() );
}
@Override
public int compareTo(final MPFileUser o) {
int comparison = getLastUsed().compareTo( o.getLastUsed() );
if (comparison == 0)
comparison = getFullName().compareTo( o.getFullName() );
return comparison;
}
}

View File

@@ -0,0 +1,139 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.io.CharSink;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.*;
import java.io.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Manages user data stored in user-specific {@code .mpsites} files under {@code .mpw.d}.
*
* @author lhunath, 14-12-07
*/
public class MPFileUserManager extends MPUserManager {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPFileUserManager.class );
private static final MPFileUserManager instance;
static {
String rcDir = System.getenv( MPConstant.env_rcDir );
if (rcDir != null)
instance = create( new File( rcDir ) );
else
instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
}
private final File userFilesDirectory;
public static MPFileUserManager get() {
MPUserManager.instance = instance;
return instance;
}
public static MPFileUserManager create(final File userFilesDirectory) {
return new MPFileUserManager( userFilesDirectory );
}
protected MPFileUserManager(final File userFilesDirectory) {
super( unmarshallUsers( userFilesDirectory ) );
this.userFilesDirectory = userFilesDirectory;
}
private static Iterable<MPFileUser> unmarshallUsers(final File userFilesDirectory) {
if (!userFilesDirectory.mkdirs() && !userFilesDirectory.isDirectory()) {
logger.err( "Couldn't create directory for user files: %s", userFilesDirectory );
return ImmutableList.of();
}
return FluentIterable.from( listUserFiles( userFilesDirectory ) ).transform( new Function<File, MPFileUser>() {
@Nullable
@Override
public MPFileUser apply(@Nullable final File file) {
try {
return new MPFlatUnmarshaller().unmarshall( Preconditions.checkNotNull( file ) );
}
catch (final IOException e) {
logger.err( e, "Couldn't read user from: %s", file );
return null;
}
}
} ).filter( Predicates.notNull() );
}
private static ImmutableList<File> listUserFiles(final File userFilesDirectory) {
return ImmutableList.copyOf( ifNotNullElse( userFilesDirectory.listFiles( new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith( ".mpsites" );
}
} ), new File[0] ) );
}
@Override
public void deleteUser(final MPFileUser user) {
super.deleteUser( user );
// Remove deleted users.
File userFile = getUserFile( user );
if (userFile.exists() && !userFile.delete())
logger.err( "Couldn't delete file: %s", userFile );
}
/**
* Write the current user state to disk.
*/
public void save(final MPFileUser user, final MPMasterKey masterKey)
throws MPInvalidatedException {
try {
new CharSink() {
@Override
public Writer openStream()
throws IOException {
return new OutputStreamWriter( new FileOutputStream( getUserFile( user ) ), Charsets.UTF_8 );
}
}.write( new MPFlatMarshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
}
catch (final IOException e) {
logger.err( e, "Unable to save sites for user: %s", user );
}
}
@Nonnull
private File getUserFile(final MPFileUser user) {
return new File( userFilesDirectory, user.getFullName() + ".mpsites" );
}
/**
* @return The location on the file system where the user models are stored.
*/
public File getPath() {
return userFilesDirectory;
}
}

View File

@@ -0,0 +1,80 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.lyndir.masterpassword.*;
import org.joda.time.Instant;
/**
* @author lhunath, 2017-09-20
*/
public class MPFlatMarshaller implements MPMarshaller {
private static final int FORMAT = 1;
@Override
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode)
throws MPInvalidatedException {
StringBuilder content = new StringBuilder();
content.append( "# Master Password site export\n" );
content.append( "# " ).append( contentMode.description() ).append( '\n' );
content.append( "# \n" );
content.append( "##\n" );
content.append( "# Format: " ).append( FORMAT ).append( '\n' );
content.append( "# Date: " ).append( MPConstant.dateTimeFormatter.print( new Instant() ) ).append( '\n' );
content.append( "# User Name: " ).append( user.getFullName() ).append( '\n' );
content.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
content.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
content.append( "# Algorithm: " ).append( MPMasterKey.Version.CURRENT.toInt() ).append( '\n' );
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
content.append( "##\n" );
content.append( "#\n" );
content.append( "# Last Times Password Login\t Site\tSite\n" );
content.append( "# used used type name\t name\tpassword\n" );
for (final MPFileSite site : user.getSites()) {
String loginName = site.getLoginContent();
String password = site.getSiteContent();
if (!contentMode.isRedacted()) {
loginName = site.loginFor( masterKey );
password = site.resultFor( masterKey );
}
content.append( strf( "%s %8d %8s %25s\t%25s\t%s\n", //
MPConstant.dateTimeFormatter.print( site.getLastUsed() ), // lastUsed
site.getUses(), // uses
strf( "%d:%d:%d", //
site.getResultType().getType(), // type
site.getAlgorithmVersion().toInt(), // algorithm
site.getSiteCounter().intValue() ), // counter
ifNotNullElse( loginName, "" ), // loginName
site.getSiteName(), // siteName
ifNotNullElse( password, "" ) // password
) );
}
return content.toString();
}
}

View File

@@ -0,0 +1,139 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import com.google.common.base.*;
import com.google.common.io.CharStreams;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.masterpassword.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.joda.time.DateTime;
/**
* @author lhunath, 14-12-07
*/
public class MPFlatUnmarshaller implements MPUnmarshaller {
private static final Pattern[] unmarshallFormats = {
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ),
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) };
private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" );
private static final Pattern colon = Pattern.compile( ":" );
@Nonnull
@Override
public MPFileUser unmarshall(@Nonnull final File file)
throws IOException {
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
return unmarshall( CharStreams.toString( reader ) );
}
}
@Nonnull
@Override
public MPFileUser unmarshall(@Nonnull final String content) {
MPFileUser user = null;
byte[] keyID = null;
String fullName = null;
int mpVersion = 0, importFormat = 0, avatar = 0;
boolean clearContent = false, headerStarted = false;
MPResultType defaultType = MPResultType.DEFAULT;
//noinspection HardcodedLineSeparator
for (final String line : Splitter.on( CharMatcher.anyOf( "\r\n" ) ).omitEmptyStrings().split( content ))
// Header delimitor.
if (line.startsWith( "##" ))
if (!headerStarted)
// Starts the header.
headerStarted = true;
else
// Ends the header.
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ), avatar, defaultType, new DateTime( 0 ) );
// Comment.
else if (line.startsWith( "#" )) {
if (headerStarted && (user == null)) {
// In header.
Matcher headerMatcher = headerFormat.matcher( line );
if (headerMatcher.matches()) {
String name = headerMatcher.group( 1 ), value = headerMatcher.group( 2 );
if ("Full Name".equalsIgnoreCase( name ) || "User Name".equalsIgnoreCase( name ))
fullName = value;
else if ("Key ID".equalsIgnoreCase( name ))
keyID = CodeUtils.decodeHex( value );
else if ("Algorithm".equalsIgnoreCase( name ))
mpVersion = ConversionUtils.toIntegerNN( value );
else if ("Format".equalsIgnoreCase( name ))
importFormat = ConversionUtils.toIntegerNN( value );
else if ("Avatar".equalsIgnoreCase( name ))
avatar = ConversionUtils.toIntegerNN( value );
else if ("Passwords".equalsIgnoreCase( name ))
clearContent = "visible".equalsIgnoreCase( value );
else if ("Default Type".equalsIgnoreCase( name ))
defaultType = MPResultType.forType( ConversionUtils.toIntegerNN( value ) );
}
}
}
// No comment.
else if (user != null) {
Matcher siteMatcher = unmarshallFormats[importFormat].matcher( line );
if (!siteMatcher.matches())
return null;
MPFileSite site;
switch (importFormat) {
case 0:
site = new MPFileSite( user, //
siteMatcher.group( 5 ), siteMatcher.group( 6 ), MPFileSite.DEFAULT_COUNTER,
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
break;
case 1:
site = new MPFileSite( user, //
siteMatcher.group( 7 ), siteMatcher.group( 8 ),
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
break;
default:
throw new UnsupportedOperationException( "Unexpected format: " + importFormat );
}
user.addSite( site );
}
return Preconditions.checkNotNull( user, "No full header found in import file." );
}
}

View File

@@ -0,0 +1,37 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
/**
* @author lhunath, 14-12-17
*/
public class MPIncorrectMasterPasswordException extends Exception {
private final MPFileUser user;
public MPIncorrectMasterPasswordException(final MPFileUser user) {
super( "Incorrect master password for user: " + user.getFullName() );
this.user = user;
}
public MPFileUser getUser() {
return user;
}
}

View File

@@ -0,0 +1,34 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import com.lyndir.masterpassword.MPMasterKey;
/**
* @author lhunath, 2017-09-20
*/
public class MPJSONMarshaller implements MPMarshaller {
@Override
public String marshall(final MPFileUser user, final MPMasterKey masterKey, final ContentMode contentMode) {
// TODO
return null;
}
}

View File

@@ -0,0 +1,45 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import java.io.File;
import java.io.IOException;
import javax.annotation.Nonnull;
/**
* @author lhunath, 2017-09-20
*/
public class MPJSONUnmarshaller implements MPUnmarshaller {
@Nonnull
@Override
public MPFileUser unmarshall(@Nonnull final File file)
throws IOException {
// TODO
return null;
}
@Nonnull
@Override
public MPFileUser unmarshall(@Nonnull final String content) {
// TODO
return null;
}
}

View File

@@ -0,0 +1,60 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
/**
* @author lhunath, 2017-09-20
*/
public enum MPMarshalFormat {
/**
* Marshal using the line-based plain-text format.
*/
Flat {
@Override
public MPMarshaller marshaller() {
return new MPFlatMarshaller();
}
@Override
public MPUnmarshaller unmarshaller() {
return new MPFlatUnmarshaller();
}
},
/**
* Marshal using the JSON structured format.
*/
JSON {
@Override
public MPMarshaller marshaller() {
return new MPJSONMarshaller();
}
@Override
public MPUnmarshaller unmarshaller() {
return new MPJSONUnmarshaller();
}
};
public static final MPMarshalFormat DEFAULT = JSON;
public abstract MPMarshaller marshaller();
public abstract MPUnmarshaller unmarshaller();
}

View File

@@ -0,0 +1,52 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model;
import com.lyndir.masterpassword.MPInvalidatedException;
import com.lyndir.masterpassword.MPMasterKey;
/**
* @author lhunath, 14-12-07
*/
public interface MPMarshaller {
String marshall(MPFileUser user, MPMasterKey masterKey, ContentMode contentMode)
throws MPInvalidatedException;
enum ContentMode {
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ),
VISIBLE( "Export of site names and passwords in clear-text." );
private final String description;
private boolean redacted;
ContentMode(final String description) {
this.description = description;
}
public String description() {
return description;
}
public boolean isRedacted() {
return redacted;
}
}
}

View File

@@ -1,3 +1,21 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
@@ -6,138 +24,58 @@ import com.google.common.primitives.UnsignedInteger;
import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.*;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.Instant;
/** /**
* @author lhunath, 14-12-05 * @author lhunath, 14-12-16
*/ */
public class MPSite { public abstract class MPSite {
public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong; public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.ONE;
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.valueOf( 1 );
private final MPUser user; public abstract String getSiteName();
private MasterKey.Version algorithmVersion;
private Instant lastUsed;
private String siteName;
private MPSiteType siteType;
private UnsignedInteger siteCounter;
private int uses;
private String loginName;
public MPSite(final MPUser user, final String siteName) { public abstract void setSiteName(String siteName);
this( user, siteName, DEFAULT_TYPE, DEFAULT_COUNTER );
public abstract UnsignedInteger getSiteCounter();
public abstract void setSiteCounter(UnsignedInteger siteCounter);
public abstract MPResultType getResultType();
public abstract void setResultType(MPResultType resultType);
public abstract MPMasterKey.Version getAlgorithmVersion();
public abstract void setAlgorithmVersion(MPMasterKey.Version algorithmVersion);
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
@Nullable final String siteContent)
throws MPInvalidatedException {
return masterKey.siteResult(
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithmVersion() );
} }
public MPSite(final MPUser user, final String siteName, final MPSiteType siteType, final UnsignedInteger siteCounter) { public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
this.user = user; throws MPInvalidatedException {
this.algorithmVersion = MasterKey.Version.CURRENT;
this.lastUsed = new Instant();
this.siteName = siteName;
this.siteType = siteType;
this.siteCounter = siteCounter;
}
protected MPSite(final MPUser user, final MasterKey.Version algorithmVersion, final Instant lastUsed, final String siteName, return masterKey.siteResult(
final MPSiteType siteType, final UnsignedInteger siteCounter, final int uses, @Nullable final String loginName, getSiteName(), DEFAULT_COUNTER, MPKeyPurpose.Identification, null, loginType, loginContent, getAlgorithmVersion() );
@Nullable final String importContent) {
this.user = user;
this.algorithmVersion = algorithmVersion;
this.lastUsed = lastUsed;
this.siteName = siteName;
this.siteType = siteType;
this.siteCounter = siteCounter;
this.uses = uses;
this.loginName = loginName;
}
public String resultFor(final MasterKey masterKey) {
return resultFor( masterKey, MPSiteVariant.Password, null );
}
public String resultFor(final MasterKey masterKey, final MPSiteVariant variant, @Nullable final String context) {
return masterKey.encode( siteName, siteType, siteCounter, variant, context );
}
public MPUser getUser() {
return user;
}
@Nullable
protected String exportContent() {
return null;
}
public MasterKey.Version getAlgorithmVersion() {
return algorithmVersion;
}
public void setAlgorithmVersion(final MasterKey.Version mpVersion) {
this.algorithmVersion = mpVersion;
}
public Instant getLastUsed() {
return lastUsed;
}
public void updateLastUsed() {
lastUsed = new Instant();
user.updateLastUsed();
}
public String getSiteName() {
return siteName;
}
public void setSiteName(final String siteName) {
this.siteName = siteName;
}
public MPSiteType getSiteType() {
return siteType;
}
public void setSiteType(final MPSiteType siteType) {
this.siteType = siteType;
}
public UnsignedInteger getSiteCounter() {
return siteCounter;
}
public void setSiteCounter(final UnsignedInteger siteCounter) {
this.siteCounter = siteCounter;
}
public int getUses() {
return uses;
}
public void setUses(final int uses) {
this.uses = uses;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(final String loginName) {
this.loginName = loginName;
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( siteName, ((MPSite) obj).siteName )); return (this == obj) || ((obj instanceof MPSite) && Objects.equals( getSiteName(), ((MPSite) obj).getSiteName() ));
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode( siteName ); return Objects.hashCode( getSiteName() );
} }
@Override @Override
public String toString() { public String toString() {
return strf( "{MPSite: %s}", siteName ); return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() );
} }
} }

View File

@@ -1,131 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.base.Preconditions;
import com.lyndir.masterpassword.MasterKey;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.Instant;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
/**
* @author lhunath, 14-12-07
*/
public class MPSiteMarshaller {
private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis();
private final StringBuilder export = new StringBuilder();
private ContentMode contentMode = ContentMode.PROTECTED;
private MasterKey masterKey;
public static MPSiteMarshaller marshallSafe(final MPUser user) {
MPSiteMarshaller marshaller = new MPSiteMarshaller();
marshaller.marshallHeaderForSafeContent( user );
for (final MPSite site : user.getSites())
marshaller.marshallSite( site );
return marshaller;
}
public static MPSiteMarshaller marshallVisible(final MPUser user, final MasterKey masterKey) {
MPSiteMarshaller marshaller = new MPSiteMarshaller();
marshaller.marshallHeaderForVisibleContentWithKey( user, masterKey );
for (final MPSite site : user.getSites())
marshaller.marshallSite( site );
return marshaller;
}
private String marshallHeaderForSafeContent(final MPUser user) {
return marshallHeader( ContentMode.PROTECTED, user, null );
}
private String marshallHeaderForVisibleContentWithKey(final MPUser user, final MasterKey masterKey) {
return marshallHeader( ContentMode.VISIBLE, user, masterKey );
}
private String marshallHeader(final ContentMode contentMode, final MPUser user, @Nullable final MasterKey masterKey) {
this.contentMode = contentMode;
this.masterKey = masterKey;
StringBuilder header = new StringBuilder();
header.append( "# Master Password site export\n" );
header.append( "# " ).append( this.contentMode.description() ).append( '\n' );
header.append( "# \n" );
header.append( "##\n" );
header.append( "# Format: 1\n" );
header.append( "# Date: " ).append( rfc3339.print( new Instant() ) ).append( '\n' );
header.append( "# User Name: " ).append( user.getFullName() ).append( '\n' );
header.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
header.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
header.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
header.append( "# Version: " ).append( MasterKey.Version.CURRENT.toBundleVersion() ).append( '\n' );
header.append( "# Algorithm: " ).append( MasterKey.Version.CURRENT.toInt() ).append( '\n' );
header.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
header.append( "# Passwords: " ).append( this.contentMode.name() ).append( '\n' );
header.append( "##\n" );
header.append( "#\n" );
header.append( "# Last Times Password Login\t Site\tSite\n" );
header.append( "# used used type name\t name\tpassword\n" );
export.append( header );
return header.toString();
}
public String marshallSite(final MPSite site) {
String exportLine = strf( "%s %8d %8s %25s\t%25s\t%s", //
rfc3339.print( site.getLastUsed() ), // lastUsed
site.getUses(), // uses
strf( "%d:%d:%d", //
site.getSiteType().getType(), // type
site.getAlgorithmVersion().toInt(), // algorithm
site.getSiteCounter().intValue() ), // counter
ifNotNullElse( site.getLoginName(), "" ), // loginName
site.getSiteName(), // siteName
ifNotNullElse( contentMode.contentForSite( site, masterKey ), "" ) // password
);
export.append( exportLine ).append( '\n' );
return exportLine;
}
public String getExport() {
return export.toString();
}
public ContentMode getContentMode() {
return contentMode;
}
public enum ContentMode {
PROTECTED( "Export of site names and stored passwords (unless device-private) encrypted with the master key." ) {
@Override
public String contentForSite(final MPSite site, @Nullable final MasterKey masterKey) {
return site.exportContent();
}
},
VISIBLE( "Export of site names and passwords in clear-text." ) {
@Override
public String contentForSite(final MPSite site, @Nonnull final MasterKey masterKey) {
return site.resultFor( Preconditions.checkNotNull( masterKey, "Master key is required when content mode is VISIBLE." ) );
}
};
private final String description;
ContentMode(final String description) {
this.description = description;
}
public String description() {
return description;
}
public abstract String contentForSite(MPSite site, MasterKey masterKey);
}
}

View File

@@ -1,3 +1,21 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
@@ -10,13 +28,13 @@ import java.util.Objects;
*/ */
public class MPSiteResult { public class MPSiteResult {
private final MPSite site; private final MPFileSite site;
public MPSiteResult(final MPSite site) { public MPSiteResult(final MPFileSite site) {
this.site = site; this.site = site;
} }
public MPSite getSite() { public MPFileSite getSite() {
return site; return site;
} }

View File

@@ -1,163 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharStreams;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.lhunath.opal.system.util.NNOperation;
import com.lyndir.masterpassword.MPSiteType;
import com.lyndir.masterpassword.MasterKey;
import java.io.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
/**
* @author lhunath, 14-12-07
*/
public class MPSiteUnmarshaller {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPSite.class );
private static final DateTimeFormatter rfc3339 = ISODateTimeFormat.dateTimeNoMillis();
private static final Pattern[] unmarshallFormats = {
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)? +([^\t]+)\t(.*)" ),
Pattern.compile( "^([^ ]+) +(\\d+) +(\\d+)(:\\d+)?(:\\d+)? +([^\t]*)\t *([^\t]+)\t(.*)" ) };
private static final Pattern headerFormat = Pattern.compile( "^#\\s*([^:]+): (.*)" );
private final int importFormat;
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
private final int mpVersion;
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
private final boolean clearContent;
private final MPUser user;
@Nonnull
public static MPSiteUnmarshaller unmarshall(@Nonnull final File file)
throws IOException {
try (Reader reader = new InputStreamReader( new FileInputStream( file ), Charsets.UTF_8 )) {
return unmarshall( CharStreams.readLines( reader ) );
}
}
@Nonnull
public static MPSiteUnmarshaller unmarshall(@Nonnull final List<String> lines) {
byte[] keyID = null;
String fullName = null;
int mpVersion = 0, importFormat = 0, avatar = 0;
boolean clearContent = false, headerStarted = false;
MPSiteType defaultType = MPSiteType.GeneratedLong;
MPSiteUnmarshaller marshaller = null;
final ImmutableList.Builder<MPSite> sites = ImmutableList.builder();
for (final String line : lines)
// Header delimitor.
if (line.startsWith( "##" ))
if (!headerStarted)
// Starts the header.
headerStarted = true;
else
// Ends the header.
marshaller = new MPSiteUnmarshaller( importFormat, mpVersion, fullName, keyID, avatar, defaultType, clearContent );
// Comment.
else if (line.startsWith( "#" )) {
if (headerStarted && (marshaller == null)) {
// In header.
Matcher headerMatcher = headerFormat.matcher( line );
if (headerMatcher.matches()) {
String name = headerMatcher.group( 1 ), value = headerMatcher.group( 2 );
if ("Full Name".equalsIgnoreCase( name ) || "User Name".equalsIgnoreCase( name ))
fullName = value;
else if ("Key ID".equalsIgnoreCase( name ))
keyID = CodeUtils.decodeHex( value );
else if ("Algorithm".equalsIgnoreCase( name ))
mpVersion = ConversionUtils.toIntegerNN( value );
else if ("Format".equalsIgnoreCase( name ))
importFormat = ConversionUtils.toIntegerNN( value );
else if ("Avatar".equalsIgnoreCase( name ))
avatar = ConversionUtils.toIntegerNN( value );
else if ("Passwords".equalsIgnoreCase( name ))
clearContent = "visible".equalsIgnoreCase( value );
else if ("Default Type".equalsIgnoreCase( name ))
defaultType = MPSiteType.forType( ConversionUtils.toIntegerNN( value ) );
}
}
}
// No comment.
else if (marshaller != null)
ifNotNull( marshaller.unmarshallSite( line ), new NNOperation<MPSite>() {
@Override
public void apply(@Nonnull final MPSite site) {
sites.add( site );
}
} );
return Preconditions.checkNotNull( marshaller, "No full header found in import file." );
}
protected MPSiteUnmarshaller(final int importFormat, final int mpVersion, final String fullName, final byte[] keyID, final int avatar,
final MPSiteType defaultType, final boolean clearContent) {
this.importFormat = importFormat;
this.mpVersion = mpVersion;
this.clearContent = clearContent;
user = new MPUser( fullName, keyID, MasterKey.Version.fromInt( mpVersion ), avatar, defaultType, new DateTime( 0 ) );
}
@Nullable
public MPSite unmarshallSite(@Nonnull final String siteLine) {
Matcher siteMatcher = unmarshallFormats[importFormat].matcher( siteLine );
if (!siteMatcher.matches())
return null;
MPSite site;
switch (importFormat) {
case 0:
site = new MPSite( user, //
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
siteMatcher.group( 5 ), //
MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPSite.DEFAULT_COUNTER, //
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
null, //
siteMatcher.group( 6 ) );
break;
case 1:
site = new MPSite( user, //
MasterKey.Version.fromInt( ConversionUtils.toIntegerNN( siteMatcher.group( 4 ).replace( ":", "" ) ) ), //
rfc3339.parseDateTime( siteMatcher.group( 1 ) ).toInstant(), //
siteMatcher.group( 7 ), //
MPSiteType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
UnsignedInteger.valueOf( siteMatcher.group( 5 ).replace( ":", "" ) ), //
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ), //
siteMatcher.group( 6 ), //
siteMatcher.group( 8 ) );
break;
default:
throw logger.bug( "Unexpected format: %d", importFormat );
}
user.addSite( site );
return site;
}
public MPUser getUser() {
return user;
}
}

View File

@@ -16,24 +16,21 @@
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>. // LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//============================================================================== //==============================================================================
package com.lyndir.masterpassword; package com.lyndir.masterpassword.model;
import java.io.*;
import javax.annotation.Nonnull;
/** /**
* <i>07 04, 2012</i> * @author lhunath, 14-12-07
*
* @author lhunath
*/ */
public enum MPSiteTypeClass { public interface MPUnmarshaller {
Generated( 1 << 4 ),
Stored( 1 << 5 );
private final int mask; @Nonnull
MPFileUser unmarshall(@Nonnull File file)
throws IOException;
MPSiteTypeClass(final int mask) { @Nonnull
this.mask = mask; MPFileUser unmarshall(@Nonnull String content);
}
public int getMask() {
return mask;
}
} }

View File

@@ -1,153 +1,86 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.collect.ImmutableList; import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.MPSiteType; import com.lyndir.masterpassword.MPInvalidatedException;
import com.lyndir.masterpassword.MasterKey; import com.lyndir.masterpassword.MPMasterKey;
import java.util.*; import java.util.*;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.joda.time.*;
/** /**
* @author lhunath, 14-12-07 * @author lhunath, 2014-06-08
*/ */
public class MPUser implements Comparable<MPUser> { public abstract class MPUser<S extends MPSite> {
private final String fullName;
private final Collection<MPSite> sites = Sets.newHashSet();
@Nullable @Nullable
private byte[] keyID; protected MPMasterKey key;
private final MasterKey.Version algorithmVersion;
private int avatar;
private MPSiteType defaultType;
private ReadableInstant lastUsed;
public MPUser(final String fullName) { public abstract String getFullName();
this( fullName, null );
public boolean isMasterKeyAvailable() {
return key != null;
} }
public MPUser(final String fullName, @Nullable final byte[] keyID) {
this( fullName, keyID, MasterKey.Version.CURRENT, 0, MPSiteType.GeneratedLong, new DateTime() );
}
public MPUser(final String fullName, @Nullable final byte[] keyID, final MasterKey.Version algorithmVersion, final int avatar,
final MPSiteType defaultType, final ReadableInstant lastUsed) {
this.fullName = fullName;
this.keyID = (keyID == null)? null: keyID.clone();
this.algorithmVersion = algorithmVersion;
this.avatar = avatar;
this.defaultType = defaultType;
this.lastUsed = lastUsed;
}
public Collection<MPSiteResult> findSitesByName(final String query) {
ImmutableList.Builder<MPSiteResult> results = ImmutableList.builder();
for (final MPSite site : getSites())
if (site.getSiteName().startsWith( query ))
results.add( new MPSiteResult( site ) );
return results.build();
}
public void addSite(final MPSite site) {
sites.add( site );
}
public void deleteSite(final MPSite site) {
sites.remove( site );
}
public String getFullName() {
return fullName;
}
public boolean hasKeyID() {
return keyID != null;
}
public String exportKeyID() {
return CodeUtils.encodeHex( keyID );
}
/**
* Performs an authentication attempt against the keyID for this user.
*
* Note: If this user doesn't have a keyID set yet, authentication will always succeed and the key ID will be set as a result.
*
* @param masterPassword The password to authenticate with.
*
* @return The master key for the user if authentication was successful.
*
* @throws IncorrectMasterPasswordException If authentication fails due to the given master password not matching the user's keyID.
*/
@Nonnull @Nonnull
@SuppressWarnings("MethodCanBeVariableArityMethod") public MPMasterKey getMasterKey() {
public MasterKey authenticate(final char[] masterPassword) return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() );
throws IncorrectMasterPasswordException {
MasterKey masterKey = MasterKey.create( algorithmVersion, getFullName(), masterPassword );
if ((keyID == null) || (keyID.length == 0))
keyID = masterKey.getKeyID();
else if (!Arrays.equals( masterKey.getKeyID(), keyID ))
throw new IncorrectMasterPasswordException( this );
return masterKey;
} }
public String exportKeyID()
throws MPInvalidatedException {
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithmVersion() ) );
}
public abstract MPMasterKey.Version getAlgorithmVersion();
public int getAvatar() { public int getAvatar() {
return avatar; return 0;
} }
public void setAvatar(final int avatar) { public abstract void addSite(S site);
this.avatar = avatar;
}
public MPSiteType getDefaultType() { public abstract void deleteSite(S site);
return defaultType;
}
public void setDefaultType(final MPSiteType defaultType) { public abstract Collection<S> findSites(String query);
this.defaultType = defaultType;
}
public ReadableInstant getLastUsed() { @Nonnull
return lastUsed; public abstract MPMasterKey authenticate(char[] masterPassword)
} throws MPIncorrectMasterPasswordException;
public void updateLastUsed() { @Override
lastUsed = new Instant(); public int hashCode() {
} return Objects.hashCode( getFullName() );
public Iterable<MPSite> getSites() {
return sites;
} }
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( fullName, ((MPUser) obj).fullName )); return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
}
@Override
public int hashCode() {
return Objects.hashCode( fullName );
} }
@Override @Override
public String toString() { public String toString() {
return strf( "{MPUser: %s}", fullName ); return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
}
@Override
public int compareTo(final MPUser o) {
int comparison = lastUsed.compareTo( o.lastUsed );
if (comparison == 0)
comparison = fullName.compareTo( o.fullName );
return comparison;
} }
} }

View File

@@ -1,124 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.io.CharSink;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.MPConstant;
import java.io.*;
import javax.annotation.Nullable;
/**
* Manages user data stored in user-specific {@code .mpsites} files under {@code .mpw.d}.
* @author lhunath, 14-12-07
*/
public class MPUserFileManager extends MPUserManager {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPUserFileManager.class );
private static final MPUserFileManager instance;
static {
String rcDir = System.getenv( MPConstant.env_rcDir );
if (rcDir != null)
instance = create( new File( rcDir ) );
else
instance = create( new File( ifNotNullElseNullable( System.getProperty( "user.home" ), System.getenv( "HOME" ) ), ".mpw.d" ) );
}
private final File userFilesDirectory;
public static MPUserFileManager get() {
MPUserManager.instance = instance;
return instance;
}
public static MPUserFileManager create(final File userFilesDirectory) {
return new MPUserFileManager( userFilesDirectory );
}
protected MPUserFileManager(final File userFilesDirectory) {
super( unmarshallUsers( userFilesDirectory ) );
this.userFilesDirectory = userFilesDirectory;
}
private static Iterable<MPUser> unmarshallUsers(final File userFilesDirectory) {
if (!userFilesDirectory.mkdirs() && !userFilesDirectory.isDirectory()) {
logger.err( "Couldn't create directory for user files: %s", userFilesDirectory );
return ImmutableList.of();
}
return FluentIterable.from( listUserFiles( userFilesDirectory ) ).transform( new Function<File, MPUser>() {
@Nullable
@Override
public MPUser apply(@Nullable final File file) {
try {
return MPSiteUnmarshaller.unmarshall( Preconditions.checkNotNull( file ) ).getUser();
}
catch (final IOException e) {
logger.err( e, "Couldn't read user from: %s", file );
return null;
}
}
} ).filter( Predicates.notNull() );
}
private static ImmutableList<File> listUserFiles(final File userFilesDirectory) {
return ImmutableList.copyOf( ifNotNullElse( userFilesDirectory.listFiles( new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.endsWith( ".mpsites" );
}
} ), new File[0] ) );
}
@Override
public void addUser(final MPUser user) {
super.addUser( user );
save();
}
@Override
public void deleteUser(final MPUser user) {
super.deleteUser( user );
save();
}
/**
* Write the current user state to disk.
*/
public void save() {
// Save existing users.
for (final MPUser user : getUsers())
try {
new CharSink() {
@Override
public Writer openStream()
throws IOException {
File mpsitesFile = new File( userFilesDirectory, user.getFullName() + ".mpsites" );
return new OutputStreamWriter( new FileOutputStream( mpsitesFile ), Charsets.UTF_8 );
}
}.write( MPSiteMarshaller.marshallSafe( user ).getExport() );
}
catch (final IOException e) {
logger.err( e, "Unable to save sites for user: %s", user );
}
// Remove deleted users.
for (final File userFile : listUserFiles( userFilesDirectory ))
if (getUserNamed( userFile.getName().replaceFirst( "\\.mpsites$", "" ) ) == null)
if (!userFile.delete())
logger.err( "Couldn't delete file: %s", userFile );
}
/**
* @return The location on the file system where the user models are stored.
*/
public File getPath() {
return userFilesDirectory;
}
}

View File

@@ -1,6 +1,25 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword.model; package com.lyndir.masterpassword.model;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.lyndir.masterpassword.MPInvalidatedException;
import java.util.*; import java.util.*;
@@ -9,31 +28,31 @@ import java.util.*;
*/ */
public abstract class MPUserManager { public abstract class MPUserManager {
private final Map<String, MPUser> usersByName = Maps.newHashMap(); private final Map<String, MPFileUser> usersByName = Maps.newHashMap();
static MPUserManager instance; static MPUserManager instance;
public static MPUserManager get() { public static MPUserManager get() {
return instance; return instance;
} }
protected MPUserManager(final Iterable<MPUser> users) { protected MPUserManager(final Iterable<MPFileUser> users) {
for (final MPUser user : users) for (final MPFileUser user : users)
usersByName.put( user.getFullName(), user ); usersByName.put( user.getFullName(), user );
} }
public SortedSet<MPUser> getUsers() { public SortedSet<MPFileUser> getUsers() {
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() ); return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
} }
public MPUser getUserNamed(final String fullName) { public MPFileUser getUserNamed(final String fullName) {
return usersByName.get( fullName ); return usersByName.get( fullName );
} }
public void addUser(final MPUser user) { public void addUser(final MPFileUser user) {
usersByName.put( user.getFullName(), user ); usersByName.put( user.getFullName(), user );
} }
public void deleteUser(final MPUser user) { public void deleteUser(final MPFileUser user) {
usersByName.remove( user.getFullName() ); usersByName.remove( user.getFullName() );
} }
} }

View File

@@ -1,3 +1,21 @@
//==============================================================================
// 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/>.
//==============================================================================
/** /**
* *
* @author lhunath, 15-02-04 * @author lhunath, 15-02-04

View File

@@ -23,12 +23,10 @@ import com.google.common.collect.Lists;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils; import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
import java.io.IOException; import java.io.IOException;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import javax.annotation.Nonnull;
import javax.xml.parsers.*; import javax.xml.parsers.*;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@@ -38,7 +36,7 @@ import org.xml.sax.ext.DefaultHandler2;
/** /**
* @author lhunath, 2015-12-22 * @author lhunath, 2015-12-22
*/ */
@SuppressWarnings("HardCodedStringLiteral") @SuppressWarnings({ "HardCodedStringLiteral", "ProhibitedExceptionDeclared" })
public class MPTestSuite implements Callable<Boolean> { public class MPTestSuite implements Callable<Boolean> {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
@@ -99,12 +97,12 @@ public class MPTestSuite implements Callable<Boolean> {
currentCase.siteName = text; currentCase.siteName = text;
if ("siteCounter".equals( qName )) if ("siteCounter".equals( qName ))
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text ); currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
if ("siteType".equals( qName )) if ("resultType".equals( qName ))
currentCase.siteType = text; currentCase.resultType = text;
if ("siteVariant".equals( qName )) if ("keyPurpose".equals( qName ))
currentCase.siteVariant = text; currentCase.keyPurpose = text;
if ("siteContext".equals( qName )) if ("keyContext".equals( qName ))
currentCase.siteContext = text; currentCase.keyContext = text;
if ("result".equals( qName )) if ("result".equals( qName ))
currentCase.result = text; currentCase.result = text;
} }
@@ -134,7 +132,8 @@ public class MPTestSuite implements Callable<Boolean> {
return tests; return tests;
} }
public boolean forEach(final String testName, final NNFunctionNN<MPTests.Case, Boolean> testFunction) { public boolean forEach(final String testName, final TestCase testFunction)
throws Exception {
List<MPTests.Case> cases = tests.getCases(); List<MPTests.Case> cases = tests.getCases();
for (int c = 0; c < cases.size(); c++) { for (int c = 0; c < cases.size(); c++) {
MPTests.Case testCase = cases.get( c ); MPTests.Case testCase = cases.get( c );
@@ -144,7 +143,7 @@ public class MPTestSuite implements Callable<Boolean> {
progress( Logger.Target.INFO, c, cases.size(), // progress( Logger.Target.INFO, c, cases.size(), //
"[%s] on %s...", testName, testCase.getIdentifier() ); "[%s] on %s...", testName, testCase.getIdentifier() );
if (!testFunction.apply( testCase )) { if (!testFunction.run( testCase )) {
progress( Logger.Target.ERROR, cases.size(), cases.size(), // progress( Logger.Target.ERROR, cases.size(), cases.size(), //
"[%s] on %s: FAILED!", testName, testCase.getIdentifier() ); "[%s] on %s: FAILED!", testName, testCase.getIdentifier() );
@@ -168,13 +167,14 @@ public class MPTestSuite implements Callable<Boolean> {
@Override @Override
public Boolean call() public Boolean call()
throws Exception { throws Exception {
return forEach( "mpw", new NNFunctionNN<MPTests.Case, Boolean>() { return forEach( "mpw", new TestCase() {
@Nonnull
@Override @Override
public Boolean apply(@Nonnull final MPTests.Case testCase) { public boolean run(final MPTests.Case testCase)
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() ); throws Exception {
String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(), MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), testCase.getMasterPassword().toCharArray() );
testCase.getSiteVariant(), testCase.getSiteContext() ); String sitePassword = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
testCase.getKeyContext(), testCase.getResultType(),
null, testCase.getAlgorithm() );
return testCase.getResult().equals( sitePassword ); return testCase.getResult().equals( sitePassword );
} }
@@ -195,4 +195,11 @@ public class MPTestSuite implements Callable<Boolean> {
void progress(int current, int max, String messageFormat, Object... args); void progress(int current, int max, String messageFormat, Object... args);
} }
public interface TestCase {
boolean run(MPTests.Case testCase)
throws Exception;
}
} }

View File

@@ -66,18 +66,18 @@ public class MPTests {
public static class Case { public static class Case {
String identifier; String identifier;
String parent; String parent;
Integer algorithm; Integer algorithm;
String fullName; String fullName;
String masterPassword; String masterPassword;
String keyID; String keyID;
String siteName; String siteName;
UnsignedInteger siteCounter; UnsignedInteger siteCounter;
String siteType; String resultType;
String siteVariant; String keyPurpose;
String siteContext; String keyContext;
String result; String result;
private transient Case parentCase; private transient Case parentCase;
@@ -130,25 +130,25 @@ public class MPTests {
return checkNotNull( parentCase.siteCounter ); return checkNotNull( parentCase.siteCounter );
} }
} ); } );
siteType = ifNotNullElse( siteType, new NNSupplier<String>() { resultType = ifNotNullElse( resultType, new NNSupplier<String>() {
@Nonnull @Nonnull
@Override @Override
public String get() { public String get() {
return checkNotNull( parentCase.siteType ); return checkNotNull( parentCase.resultType );
} }
} ); } );
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() { keyPurpose = ifNotNullElse( keyPurpose, new NNSupplier<String>() {
@Nonnull @Nonnull
@Override @Override
public String get() { public String get() {
return checkNotNull( parentCase.siteVariant ); return checkNotNull( parentCase.keyPurpose );
} }
} ); } );
siteContext = ifNotNullElse( siteContext, new NNSupplier<String>() { keyContext = ifNotNullElse( keyContext, new NNSupplier<String>() {
@Nonnull @Nonnull
@Override @Override
public String get() { public String get() {
return (parentCase == null)? "": checkNotNull( parentCase.siteContext ); return (parentCase == null)? "": checkNotNull( parentCase.keyContext );
} }
} ); } );
result = ifNotNullElse( result, new NNSupplier<String>() { result = ifNotNullElse( result, new NNSupplier<String>() {
@@ -171,8 +171,8 @@ public class MPTests {
} }
@Nonnull @Nonnull
public MasterKey.Version getAlgorithm() { public MPMasterKey.Version getAlgorithm() {
return MasterKey.Version.fromInt( checkNotNull( algorithm ) ); return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) );
} }
@Nonnull @Nonnull
@@ -181,8 +181,8 @@ public class MPTests {
} }
@Nonnull @Nonnull
public char[] getMasterPassword() { public String getMasterPassword() {
return checkNotNull( masterPassword ).toCharArray(); return checkNotNull( masterPassword );
} }
@Nonnull @Nonnull
@@ -200,18 +200,18 @@ public class MPTests {
} }
@Nonnull @Nonnull
public MPSiteType getSiteType() { public MPResultType getResultType() {
return MPSiteType.forName( checkNotNull( siteType ) ); return MPResultType.forName( checkNotNull( resultType ) );
} }
@Nonnull @Nonnull
public MPSiteVariant getSiteVariant() { public MPKeyPurpose getKeyPurpose() {
return MPSiteVariant.forName( checkNotNull( siteVariant ) ); return MPKeyPurpose.forName( checkNotNull( keyPurpose ) );
} }
@Nonnull @Nonnull
public String getSiteContext() { public String getKeyContext() {
return checkNotNull( siteContext ); return checkNotNull( keyContext );
} }
@Nonnull @Nonnull

View File

@@ -1,279 +0,0 @@
<tests>
<!-- Default values for all parameters. -->
<case id="default">
<algorithm>-1</algorithm>
<fullName>Robert Lee Mitchell</fullName>
<masterPassword>banana colored duckling</masterPassword>
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
<siteName>masterpasswordapp.com</siteName>
<siteCounter>1</siteCounter>
<resultType>GeneratedLong</resultType>
<keyPurpose>Authentication</keyPurpose>
<result><!-- abstract --></result>
</case>
<!-- Algorithm 3 -->
<case id="v3" parent="default">
<algorithm>3</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v3_mb_fullName" parent="v3">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>NopaDajh8=Fene</result>
</case>
<case id="v3_mb_masterPassword" parent="v3">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v3_mb_siteName" parent="v3">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v3_loginName" parent="v3">
<keyPurpose>Identification</keyPurpose>
<resultType>GeneratedName</resultType>
<result>wohzaqage</result>
</case>
<case id="v3_securityAnswer" parent="v3">
<keyPurpose>Recovery</keyPurpose>
<resultType>GeneratedPhrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v3_securityAnswer_context" parent="v3_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v3_type_maximum" parent="v3">
<resultType>GeneratedMaximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v3_type_medium" parent="v3">
<resultType>GeneratedMedium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v3_type_basic" parent="v3">
<resultType>GeneratedBasic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v3_type_short" parent="v3">
<resultType>GeneratedShort</resultType>
<result>Jej2</result>
</case>
<case id="v3_type_pin" parent="v3">
<resultType>GeneratedPIN</resultType>
<result>7662</result>
</case>
<case id="v3_type_name" parent="v3">
<resultType>GeneratedName</resultType>
<result>jejraquvo</result>
</case>
<case id="v3_type_phrase" parent="v3">
<resultType>GeneratedPhrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v3_counter_ceiling" parent="v3">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 2 -->
<case id="v2" parent="default">
<algorithm>2</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v2_mb_fullName" parent="v2">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v2_mb_masterPassword" parent="v2">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v2_mb_siteName" parent="v2">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v2_loginName" parent="v2">
<keyPurpose>Identification</keyPurpose>
<resultType>GeneratedName</resultType>
<result>wohzaqage</result>
</case>
<case id="v2_securityAnswer" parent="v2">
<keyPurpose>Recovery</keyPurpose>
<resultType>GeneratedPhrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v2_type_maximum" parent="v2">
<resultType>GeneratedMaximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v2_type_medium" parent="v2">
<resultType>GeneratedMedium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v2_type_basic" parent="v2">
<resultType>GeneratedBasic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v2_type_short" parent="v2">
<resultType>GeneratedShort</resultType>
<result>Jej2</result>
</case>
<case id="v2_type_pin" parent="v2">
<resultType>GeneratedPIN</resultType>
<result>7662</result>
</case>
<case id="v2_type_name" parent="v2">
<resultType>GeneratedName</resultType>
<result>jejraquvo</result>
</case>
<case id="v2_type_phrase" parent="v2">
<resultType>GeneratedPhrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v2_counter_ceiling" parent="v2">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 1 -->
<case id="v1" parent="default">
<algorithm>1</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v1_mb_fullName" parent="v1">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v1_mb_masterPassword" parent="v1">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v1_mb_siteName" parent="v1">
<siteName></siteName>
<result>WawiYarp2@Kodh</result>
</case>
<case id="v1_loginName" parent="v1">
<keyPurpose>Identification</keyPurpose>
<resultType>GeneratedName</resultType>
<result>wohzaqage</result>
</case>
<case id="v1_securityAnswer" parent="v1">
<keyPurpose>Recovery</keyPurpose>
<resultType>GeneratedPhrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v1_type_maximum" parent="v1">
<resultType>GeneratedMaximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v1_type_medium" parent="v1">
<resultType>GeneratedMedium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v1_type_basic" parent="v1">
<resultType>GeneratedBasic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v1_type_short" parent="v1">
<resultType>GeneratedShort</resultType>
<result>Jej2</result>
</case>
<case id="v1_type_pin" parent="v1">
<resultType>GeneratedPIN</resultType>
<result>7662</result>
</case>
<case id="v1_type_name" parent="v1">
<resultType>GeneratedName</resultType>
<result>jejraquvo</result>
</case>
<case id="v1_type_phrase" parent="v1">
<resultType>GeneratedPhrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v1_counter_ceiling" parent="v1">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 0 -->
<case id="v0" parent="default">
<algorithm>0</algorithm>
<result>Feji5@ReduWosh</result>
</case>
<case id="v0_mb_fullName" parent="v0">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>HajrYudo7@Mamh</result>
</case>
<case id="v0_mb_masterPassword" parent="v0">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>MewmDini0]Meho</result>
</case>
<case id="v0_mb_siteName" parent="v0">
<siteName></siteName>
<result>HahiVana2@Nole</result>
</case>
<case id="v0_loginName" parent="v0">
<keyPurpose>Identification</keyPurpose>
<resultType>GeneratedName</resultType>
<result>lozwajave</result>
</case>
<case id="v0_securityAnswer" parent="v0">
<keyPurpose>Recovery</keyPurpose>
<resultType>GeneratedPhrase</resultType>
<result>miy lirfijoja dubu</result>
</case>
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
<keyContext>question</keyContext>
<result>movm bex gevrica jaf</result>
</case>
<case id="v0_type_maximum" parent="v0">
<resultType>GeneratedMaximum</resultType>
<result>w1!3bA3icmRAc)SS@lwl</result>
</case>
<case id="v0_type_medium" parent="v0">
<resultType>GeneratedMedium</resultType>
<result>Fej7]Jug</result>
</case>
<case id="v0_type_basic" parent="v0">
<resultType>GeneratedBasic</resultType>
<result>wvH7irC1</result>
</case>
<case id="v0_type_short" parent="v0">
<resultType>GeneratedShort</resultType>
<result>Fej7</result>
</case>
<case id="v0_type_pin" parent="v0">
<resultType>GeneratedPIN</resultType>
<result>2117</result>
</case>
<case id="v0_type_name" parent="v0">
<resultType>GeneratedName</resultType>
<result>fejrajugo</result>
</case>
<case id="v0_type_phrase" parent="v0">
<resultType>GeneratedPhrase</resultType>
<result>fejr jug gabsibu bax</result>
</case>
<case id="v0_counter_ceiling" parent="v0">
<siteCounter>4294967295</siteCounter>
<result>QateDojh1@Hecn</result>
</case>
</tests>

View File

@@ -0,0 +1 @@
../../../../../mpw_tests.xml

View File

@@ -0,0 +1,145 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static org.testng.Assert.*;
import com.google.common.base.Charsets;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Random;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MPMasterKeyTest {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPMasterKeyTest.class );
private MPTestSuite testSuite;
@BeforeMethod
public void setUp()
throws Exception {
testSuite = new MPTestSuite();
}
@Test
public void testMasterKey()
throws Exception {
testSuite.forEach( "testMasterKey", new MPTestSuite.TestCase() {
@Override
public boolean run(final MPTests.Case testCase)
throws Exception {
char[] masterPassword = testCase.getMasterPassword().toCharArray();
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
// Test key
assertEquals(
CodeUtils.encodeHex( masterKey.getKeyID( testCase.getAlgorithm() ) ),
testCase.getKeyID(),
"[testMasterKey] keyID mismatch: " + testCase );
// Test invalidation
masterKey.invalidate();
try {
masterKey.getKeyID( testCase.getAlgorithm() );
fail( "[testMasterKey] invalidate ineffective: " + testCase );
}
catch (final MPInvalidatedException ignored) {
}
assertNotEquals(
masterPassword,
testCase.getMasterPassword().toCharArray(),
"[testMasterKey] masterPassword not wiped: " + testCase );
return true;
}
} );
}
@Test
public void testSiteResult()
throws Exception {
testSuite.forEach( "testSiteResult", new MPTestSuite.TestCase() {
@Override
public boolean run(final MPTests.Case testCase)
throws Exception {
char[] masterPassword = testCase.getMasterPassword().toCharArray();
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
// Test site result
assertEquals(
masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
testCase.getKeyContext(), testCase.getResultType(),
null, testCase.getAlgorithm() ),
testCase.getResult(),
"[testSiteResult] result mismatch: " + testCase );
return true;
}
} );
}
@Test
public void testSiteState()
throws Exception {
MPTests.Case testCase = testSuite.getTests().getDefaultCase();
char[] masterPassword = testCase.getMasterPassword().toCharArray();
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
String password = randomString( 8 );
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
MPResultType resultType = MPResultType.StoredPersonal;
// Test site state
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
testCase.getKeyContext(), resultType, password, version );
String result = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
testCase.getKeyContext(), resultType, state, version );
assertEquals(
result,
password,
"[testSiteState] state mismatch: " + testCase );
}
}
public static String randomString(int length) {
Random random = new Random();
StringBuilder builder = new StringBuilder();
while (length > 0) {
int codePoint = random.nextInt( Character.MAX_CODE_POINT - Character.MIN_CODE_POINT ) + Character.MIN_CODE_POINT;
if (!Character.isDefined( codePoint ) || (Character.getType( codePoint ) == Character.PRIVATE_USE) || Character.isSurrogate(
(char) codePoint ))
continue;
builder.appendCodePoint( codePoint );
length--;
}
return builder.toString();
}
}

View File

@@ -1,112 +0,0 @@
//==============================================================================
// 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/>.
//==============================================================================
package com.lyndir.masterpassword;
import static org.testng.Assert.*;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
import javax.annotation.Nonnull;
import org.jetbrains.annotations.NonNls;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MasterKeyTest {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyTest.class );
@NonNls
private MPTestSuite testSuite;
@BeforeMethod
public void setUp()
throws Exception {
testSuite = new MPTestSuite();
}
@Test
public void testEncode()
throws Exception {
testSuite.forEach( "testEncode", new NNFunctionNN<MPTests.Case, Boolean>() {
@Nonnull
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
assertEquals(
masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
testCase.getSiteVariant(), testCase.getSiteContext() ),
testCase.getResult(), "[testEncode] Failed test case: " + testCase );
return true;
}
} );
}
@Test
public void testGetUserName()
throws Exception {
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
assertEquals( MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getFullName(),
defaultCase.getFullName(), "[testGetUserName] Failed test case: " + defaultCase );
}
@Test
public void testGetKeyID()
throws Exception {
testSuite.forEach( "testGetKeyID", new NNFunctionNN<MPTests.Case, Boolean>() {
@Nonnull
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() );
assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ),
testCase.getKeyID(), "[testGetKeyID] Failed test case: " + testCase );
return true;
}
} );
}
@Test
public void testInvalidate()
throws Exception {
try {
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() );
masterKey.invalidate();
masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(),
defaultCase.getSiteVariant(), defaultCase.getSiteContext() );
fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
}
catch (final IllegalStateException ignored) {
}
}
}

View File

@@ -6,7 +6,7 @@
</encoder> </encoder>
</appender> </appender>
<logger name="com.lyndir" level="${mp.log.level:-INFO}" /> <logger name="com.lyndir" level="${mp.log.level:-TRACE}" />
<root level="INFO"> <root level="INFO">
<appender-ref ref="stdout" /> <appender-ref ref="stdout" />

279
core/mpw_tests.xml Normal file
View File

@@ -0,0 +1,279 @@
<tests>
<!-- Default values for all parameters. -->
<case id="default">
<algorithm>-1</algorithm>
<fullName>Robert Lee Mitchell</fullName>
<masterPassword>banana colored duckling</masterPassword>
<keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
<siteName>masterpasswordapp.com</siteName>
<siteCounter>1</siteCounter>
<resultType>Long</resultType>
<keyPurpose>Authentication</keyPurpose>
<result><!-- abstract --></result>
</case>
<!-- Algorithm 3 -->
<case id="v3" parent="default">
<algorithm>3</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v3_mb_fullName" parent="v3">
<fullName></fullName>
<keyID>1717AA1F9BF5BA56CD0965CDA3D78E6D2E6A1EA8C067A8EA621F3DDAD4A87EB8</keyID>
<result>NopaDajh8=Fene</result>
</case>
<case id="v3_mb_masterPassword" parent="v3">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v3_mb_siteName" parent="v3">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v3_loginName" parent="v3">
<keyPurpose>Identification</keyPurpose>
<resultType>Name</resultType>
<result>wohzaqage</result>
</case>
<case id="v3_securityAnswer" parent="v3">
<keyPurpose>Recovery</keyPurpose>
<resultType>Phrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v3_securityAnswer_context" parent="v3_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v3_type_maximum" parent="v3">
<resultType>Maximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v3_type_medium" parent="v3">
<resultType>Medium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v3_type_basic" parent="v3">
<resultType>Basic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v3_type_short" parent="v3">
<resultType>Short</resultType>
<result>Jej2</result>
</case>
<case id="v3_type_pin" parent="v3">
<resultType>PIN</resultType>
<result>7662</result>
</case>
<case id="v3_type_name" parent="v3">
<resultType>Name</resultType>
<result>jejraquvo</result>
</case>
<case id="v3_type_phrase" parent="v3">
<resultType>Phrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v3_counter_ceiling" parent="v3">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 2 -->
<case id="v2" parent="default">
<algorithm>2</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v2_mb_fullName" parent="v2">
<fullName></fullName>
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v2_mb_masterPassword" parent="v2">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v2_mb_siteName" parent="v2">
<siteName></siteName>
<result>LiheCuwhSerz6)</result>
</case>
<case id="v2_loginName" parent="v2">
<keyPurpose>Identification</keyPurpose>
<resultType>Name</resultType>
<result>wohzaqage</result>
</case>
<case id="v2_securityAnswer" parent="v2">
<keyPurpose>Recovery</keyPurpose>
<resultType>Phrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v2_securityAnswer_context" parent="v2_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v2_type_maximum" parent="v2">
<resultType>Maximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v2_type_medium" parent="v2">
<resultType>Medium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v2_type_basic" parent="v2">
<resultType>Basic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v2_type_short" parent="v2">
<resultType>Short</resultType>
<result>Jej2</result>
</case>
<case id="v2_type_pin" parent="v2">
<resultType>PIN</resultType>
<result>7662</result>
</case>
<case id="v2_type_name" parent="v2">
<resultType>Name</resultType>
<result>jejraquvo</result>
</case>
<case id="v2_type_phrase" parent="v2">
<resultType>Phrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v2_counter_ceiling" parent="v2">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 1 -->
<case id="v1" parent="default">
<algorithm>1</algorithm>
<result>Jejr5[RepuSosp</result>
</case>
<case id="v1_mb_fullName" parent="v1">
<fullName></fullName>
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
<result>WaqoGuho2[Xaxw</result>
</case>
<case id="v1_mb_masterPassword" parent="v1">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>QesuHirv5-Xepl</result>
</case>
<case id="v1_mb_siteName" parent="v1">
<siteName></siteName>
<result>WawiYarp2@Kodh</result>
</case>
<case id="v1_loginName" parent="v1">
<keyPurpose>Identification</keyPurpose>
<resultType>Name</resultType>
<result>wohzaqage</result>
</case>
<case id="v1_securityAnswer" parent="v1">
<keyPurpose>Recovery</keyPurpose>
<resultType>Phrase</resultType>
<result>xin diyjiqoja hubu</result>
</case>
<case id="v1_securityAnswer_context" parent="v1_securityAnswer">
<keyContext>question</keyContext>
<result>xogx tem cegyiva jab</result>
</case>
<case id="v1_type_maximum" parent="v1">
<resultType>Maximum</resultType>
<result>W6@692^B1#&amp;@gVdSdLZ@</result>
</case>
<case id="v1_type_medium" parent="v1">
<resultType>Medium</resultType>
<result>Jej2$Quv</result>
</case>
<case id="v1_type_basic" parent="v1">
<resultType>Basic</resultType>
<result>WAo2xIg6</result>
</case>
<case id="v1_type_short" parent="v1">
<resultType>Short</resultType>
<result>Jej2</result>
</case>
<case id="v1_type_pin" parent="v1">
<resultType>PIN</resultType>
<result>7662</result>
</case>
<case id="v1_type_name" parent="v1">
<resultType>Name</resultType>
<result>jejraquvo</result>
</case>
<case id="v1_type_phrase" parent="v1">
<resultType>Phrase</resultType>
<result>jejr quv cabsibu tam</result>
</case>
<case id="v1_counter_ceiling" parent="v1">
<siteCounter>4294967295</siteCounter>
<result>XambHoqo6[Peni</result>
</case>
<!-- Algorithm 0 -->
<case id="v0" parent="default">
<algorithm>0</algorithm>
<result>Feji5@ReduWosh</result>
</case>
<case id="v0_mb_fullName" parent="v0">
<fullName></fullName>
<keyID>4D5851D0B093D65DE0CF13D94877270468C0B65A6E42CA50D393AC9B99C457B5</keyID>
<result>HajrYudo7@Mamh</result>
</case>
<case id="v0_mb_masterPassword" parent="v0">
<masterPassword></masterPassword>
<keyID>351432B8528A5ABECAB768CA95015097DE76FE14C41E10AF36C67DCFB8917E08</keyID>
<result>MewmDini0]Meho</result>
</case>
<case id="v0_mb_siteName" parent="v0">
<siteName></siteName>
<result>HahiVana2@Nole</result>
</case>
<case id="v0_loginName" parent="v0">
<keyPurpose>Identification</keyPurpose>
<resultType>Name</resultType>
<result>lozwajave</result>
</case>
<case id="v0_securityAnswer" parent="v0">
<keyPurpose>Recovery</keyPurpose>
<resultType>Phrase</resultType>
<result>miy lirfijoja dubu</result>
</case>
<case id="v0_securityAnswer_context" parent="v0_securityAnswer">
<keyContext>question</keyContext>
<result>movm bex gevrica jaf</result>
</case>
<case id="v0_type_maximum" parent="v0">
<resultType>Maximum</resultType>
<result>w1!3bA3icmRAc)SS@lwl</result>
</case>
<case id="v0_type_medium" parent="v0">
<resultType>Medium</resultType>
<result>Fej7]Jug</result>
</case>
<case id="v0_type_basic" parent="v0">
<resultType>Basic</resultType>
<result>wvH7irC1</result>
</case>
<case id="v0_type_short" parent="v0">
<resultType>Short</resultType>
<result>Fej7</result>
</case>
<case id="v0_type_pin" parent="v0">
<resultType>PIN</resultType>
<result>2117</result>
</case>
<case id="v0_type_name" parent="v0">
<resultType>Name</resultType>
<result>fejrajugo</result>
</case>
<case id="v0_type_phrase" parent="v0">
<resultType>Phrase</resultType>
<result>fejr jug gabsibu bax</result>
</case>
<case id="v0_counter_ceiling" parent="v0">
<siteCounter>4294967295</siteCounter>
<result>QateDojh1@Hecn</result>
</case>
</tests>

View File

@@ -6,20 +6,18 @@
<option name="PM_INSTALL_OPTIONS" value="" /> <option name="PM_INSTALL_OPTIONS" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" /> <option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" /> <option name="MODE" value="default_activity" />
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
<option name="PREFERRED_AVD" value="" /> <option name="PREFERRED_AVD" value="" />
<option name="CLEAR_LOGCAT" value="false" /> <option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" /> <option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" /> <option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" /> <option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="DEBUGGER_TYPE" value="Java" /> <option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" /> <option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" /> <option name="PREFERRED_AVD" value="" />
<option name="DEBUGGER_TYPE" value="Java" />
<Java /> <Java />
<Profilers> <Profilers>
<option name="ENABLE_ADVANCED_PROFILING" value="false" /> <option name="ENABLE_ADVANCED_PROFILING" value="false" />
<option name="GAPID_ENABLED" value="false" />
<option name="GAPID_DISABLE_PCS" value="false" />
<option name="SUPPORT_LIB_ENABLED" value="true" /> <option name="SUPPORT_LIB_ENABLED" value="true" />
<option name="INSTRUMENTATION_ENABLED" value="true" /> <option name="INSTRUMENTATION_ENABLED" value="true" />
</Profilers> </Profilers>

View File

@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="GUI" type="Application" factoryName="Application"> <configuration default="false" name="GUI" type="Application" factoryName="Application" show_console_on_std_err="true">
<option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" /> <option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
<option name="VM_PARAMETERS" value="" /> <option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="" /> <option name="PROGRAM_PARAMETERS" value="" />
@@ -9,7 +9,7 @@
<option name="ENABLE_SWING_INSPECTOR" value="false" /> <option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" /> <option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<module name="gui" /> <module name="masterpassword-gui" />
<envs /> <envs />
<method /> <method />
</configuration> </configuration>

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG"> <configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
<module name="tests" /> <module name="" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" /> <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" /> <option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" value="" /> <option name="SUITE_NAME" value="" />
@@ -17,7 +17,7 @@
<option name="ENV_VARIABLES" /> <option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" /> <option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE"> <option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" /> <value defaultName="wholeProject" />
</option> </option>
<option name="USE_DEFAULT_REPORTERS" value="false" /> <option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" value="" /> <option name="PROPERTIES_FILE" value="" />

View File

@@ -1,3 +1,3 @@
<component name="DependencyValidationManager"> <component name="DependencyValidationManager">
<scope name="masterpassword" pattern="com.lyndir.masterpassword.*" /> <scope name="masterpassword" pattern="com.lyndir.masterpassword..*" />
</component> </component>

View File

@@ -22,7 +22,7 @@ buildscript {
} }
dependencies { dependencies {
classpath group: 'com.android.tools.build', name: 'gradle', version: '2.2.3' classpath group: 'com.android.tools.build', name: 'gradle', version: '2.3.0'
} }
} }

View File

@@ -22,7 +22,6 @@
<module>masterpassword-tests</module> <module>masterpassword-tests</module>
<module>masterpassword-algorithm</module> <module>masterpassword-algorithm</module>
<module>masterpassword-model</module> <module>masterpassword-model</module>
<module>masterpassword-cli</module>
<module>masterpassword-gui</module> <module>masterpassword-gui</module>
</modules> </modules>

View File

@@ -1,5 +1,11 @@
rootProject.name = 'masterpassword' rootProject.name = 'masterpassword'
def local = new Properties();
try {
local.load(file('local.properties').newDataInputStream())
} catch (FileNotFoundException ignored) {
}
include 'masterpassword-algorithm' include 'masterpassword-algorithm'
project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' ) project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
@@ -9,11 +15,12 @@ project(':masterpassword-model').projectDir = new File( '../core/java/model' )
include 'masterpassword-tests' include 'masterpassword-tests'
project(':masterpassword-tests').projectDir = new File( '../core/java/tests' ) project(':masterpassword-tests').projectDir = new File( '../core/java/tests' )
include 'masterpassword-cli'
project(':masterpassword-cli').projectDir = new File( '../platform-independent/cli-java' )
include 'masterpassword-gui' include 'masterpassword-gui'
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' ) project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
include 'masterpassword-android' if (local.containsKey('sdk.dir')) {
project(':masterpassword-android').projectDir = new File( '../platform-android' ) include 'masterpassword-android'
project(':masterpassword-android').projectDir = new File( '../platform-android' )
} else {
logger.warn( "Skipping masterpassword-android since sdk.dir is not defined in local.properties." )
}

View File

@@ -33,7 +33,6 @@ import android.view.WindowManager;
import android.widget.*; import android.widget.*;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.google.common.util.concurrent.*; import com.google.common.util.concurrent.*;
@@ -52,12 +51,12 @@ public class EmergencyActivity extends Activity {
private static final int PASSWORD_NOTIFICATION = 0; private static final int PASSWORD_NOTIFICATION = 0;
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S; public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
private final Preferences preferences = Preferences.get( this ); private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() ); private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ImmutableList<MPSiteType> allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) ); private final ImmutableList<MPResultType> allResultTypes = ImmutableList.copyOf( MPResultType.forClass( MPResultTypeClass.Template ) );
private final ImmutableList<MasterKey.Version> allVersions = ImmutableList.copyOf( MasterKey.Version.values() ); private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() );
private ListenableFuture<MasterKey> masterKeyFuture; private MPMasterKey masterKey;
@BindView(R.id.progressView) @BindView(R.id.progressView)
ProgressBar progressView; ProgressBar progressView;
@@ -71,8 +70,8 @@ public class EmergencyActivity extends Activity {
@BindView(R.id.siteNameField) @BindView(R.id.siteNameField)
EditText siteNameField; EditText siteNameField;
@BindView(R.id.siteTypeButton) @BindView(R.id.resultTypeButton)
Button siteTypeButton; Button resultTypeButton;
@BindView(R.id.counterField) @BindView(R.id.counterField)
Button siteCounterButton; Button siteCounterButton;
@@ -97,7 +96,6 @@ public class EmergencyActivity extends Activity {
private int id_userName; private int id_userName;
private int id_masterPassword; private int id_masterPassword;
private int id_version;
private String sitePassword; private String sitePassword;
public static void start(final Context context) { public static void start(final Context context) {
@@ -131,15 +129,15 @@ public class EmergencyActivity extends Activity {
updateSitePassword(); updateSitePassword();
} }
} ); } );
siteTypeButton.setOnClickListener( new View.OnClickListener() { resultTypeButton.setOnClickListener( new View.OnClickListener() {
@Override @Override
public void onClick(final View v) { public void onClick(final View v) {
@SuppressWarnings("SuspiciousMethodCalls") @SuppressWarnings("SuspiciousMethodCalls")
MPSiteType siteType = MPResultType resultType =
allSiteTypes.get( (allSiteTypes.indexOf( siteTypeButton.getTag() ) + 1) % allSiteTypes.size() ); allResultTypes.get( (allResultTypes.indexOf( resultTypeButton.getTag() ) + 1) % allResultTypes.size() );
preferences.setDefaultSiteType( siteType ); preferences.setDefaultResultType( resultType );
siteTypeButton.setTag( siteType ); resultTypeButton.setTag( resultType );
siteTypeButton.setText( siteType.getShortName() ); resultTypeButton.setText( resultType.getShortName() );
updateSitePassword(); updateSitePassword();
} }
} ); } );
@@ -156,7 +154,7 @@ public class EmergencyActivity extends Activity {
@Override @Override
public void onClick(final View v) { public void onClick(final View v) {
@SuppressWarnings("SuspiciousMethodCalls") @SuppressWarnings("SuspiciousMethodCalls")
MasterKey.Version siteVersion = MPMasterKey.Version siteVersion =
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() ); allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
preferences.setDefaultVersion( siteVersion ); preferences.setDefaultVersion( siteVersion );
siteVersionButton.setTag( siteVersion ); siteVersionButton.setTag( siteVersion );
@@ -213,17 +211,17 @@ public class EmergencyActivity extends Activity {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() ); // FIXME: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
fullNameField.setText( preferences.getFullName() ); fullNameField.setText( preferences.getFullName() );
rememberFullNameField.setChecked( preferences.isRememberFullName() ); rememberFullNameField.setChecked( preferences.isRememberFullName() );
forgetPasswordField.setChecked( preferences.isForgetPassword() ); forgetPasswordField.setChecked( preferences.isForgetPassword() );
maskPasswordField.setChecked( preferences.isMaskPassword() ); maskPasswordField.setChecked( preferences.isMaskPassword() );
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null ); sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
MPSiteType defaultSiteType = preferences.getDefaultSiteType(); MPResultType defaultResultType = preferences.getDefaultResultType();
siteTypeButton.setTag( defaultSiteType ); resultTypeButton.setTag( defaultResultType );
siteTypeButton.setText( defaultSiteType.getShortName() ); resultTypeButton.setText( defaultResultType.getShortName() );
MasterKey.Version defaultVersion = preferences.getDefaultVersion(); MPMasterKey.Version defaultVersion = preferences.getDefaultVersion();
siteVersionButton.setTag( defaultVersion ); siteVersionButton.setTag( defaultVersion );
siteVersionButton.setText( defaultVersion.name() ); siteVersionButton.setText( defaultVersion.name() );
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) ); siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
@@ -241,10 +239,8 @@ public class EmergencyActivity extends Activity {
if (preferences.isForgetPassword()) { if (preferences.isForgetPassword()) {
synchronized (this) { synchronized (this) {
id_userName = id_masterPassword = 0; id_userName = id_masterPassword = 0;
if (masterKeyFuture != null) { if (masterKey != null)
masterKeyFuture.cancel( true ); masterKey = null;
masterKeyFuture = null;
}
masterPasswordField.setText( "" ); masterPasswordField.setText( "" );
} }
@@ -260,23 +256,17 @@ public class EmergencyActivity extends Activity {
private synchronized void updateMasterKey() { private synchronized void updateMasterKey() {
final String fullName = fullNameField.getText().toString(); final String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray(); final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
if ((id_userName == fullName.hashCode()) if ((id_userName == fullName.hashCode())
&& (id_masterPassword == Arrays.hashCode( masterPassword )) && (id_masterPassword == Arrays.hashCode( masterPassword )))
&& (id_version == version.ordinal())) if (masterKey != null)
if ((masterKeyFuture != null) && !masterKeyFuture.isCancelled())
return; return;
id_userName = fullName.hashCode(); id_userName = fullName.hashCode();
id_masterPassword = Arrays.hashCode( masterPassword ); id_masterPassword = Arrays.hashCode( masterPassword );
id_version = version.ordinal();
if (preferences.isRememberFullName()) if (preferences.isRememberFullName())
preferences.setFullName( fullName ); preferences.setFullName( fullName );
if (masterKeyFuture != null)
masterKeyFuture.cancel( true );
if (fullName.isEmpty() || (masterPassword.length == 0)) { if (fullName.isEmpty() || (masterPassword.length == 0)) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
@@ -285,43 +275,21 @@ public class EmergencyActivity extends Activity {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.VISIBLE ); progressView.setVisibility( View.VISIBLE );
(masterKeyFuture = executor.submit( new Callable<MasterKey>() { masterKey = new MPMasterKey( fullName, masterPassword );
@Override updateSitePassword();
public MasterKey call()
throws Exception {
try {
return MasterKey.create( version, fullName, masterPassword );
}
catch (final Exception e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating master key." );
throw e;
}
}
} )).addListener( new Runnable() {
@Override
public void run() {
runOnUiThread( new Runnable() {
@Override
public void run() {
updateSitePassword();
}
} );
}
}, executor );
} }
private void updateSitePassword() { private void updateSitePassword() {
final String siteName = siteNameField.getText().toString(); final String siteName = siteNameField.getText().toString();
final MPSiteType type = (MPSiteType) siteTypeButton.getTag(); final MPResultType type = (MPResultType) resultTypeButton.getTag();
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() ); final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
final MPMasterKey.Version version = (MPMasterKey.Version) siteVersionButton.getTag();
if ((masterKeyFuture == null) || siteName.isEmpty() || (type == null)) { if ((masterKey == null) || siteName.isEmpty() || (type == null)) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
if (masterKeyFuture == null) if (masterKey == null)
updateMasterKey(); updateMasterKey();
return; return;
} }
@@ -332,7 +300,7 @@ public class EmergencyActivity extends Activity {
@Override @Override
public void run() { public void run() {
try { try {
sitePassword = masterKeyFuture.get().encode( siteName, type, counter, MPSiteVariant.Password, null ); sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version );
runOnUiThread( new Runnable() { runOnUiThread( new Runnable() {
@Override @Override
@@ -342,16 +310,10 @@ public class EmergencyActivity extends Activity {
} }
} ); } );
} }
catch (final InterruptedException ignored) { catch (final MPInvalidatedException ignored) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
} }
catch (final ExecutionException e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." );
throw Throwables.propagate( e );
}
catch (final RuntimeException e) { catch (final RuntimeException e) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
@@ -363,10 +325,9 @@ public class EmergencyActivity extends Activity {
} }
public void integrityTests(final View view) { public void integrityTests(final View view) {
if (masterKeyFuture != null) { if (masterKey != null)
masterKeyFuture.cancel( true ); masterKey = null;
masterKeyFuture = null;
}
TestActivity.startNoSkip( this ); TestActivity.startNoSkip( this );
} }

View File

@@ -38,7 +38,7 @@ public final class Preferences {
private static final String PREF_FORGET_PASSWORD = "forgetPassword"; private static final String PREF_FORGET_PASSWORD = "forgetPassword";
private static final String PREF_MASK_PASSWORD = "maskPassword"; private static final String PREF_MASK_PASSWORD = "maskPassword";
private static final String PREF_FULL_NAME = "fullName"; private static final String PREF_FULL_NAME = "fullName";
private static final String PREF_SITE_TYPE = "siteType"; private static final String PREF_RESULT_TYPE = "resultType";
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion"; private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
private static Preferences instance; private static Preferences instance;
@@ -74,7 +74,7 @@ public final class Preferences {
} }
public boolean isAllowNativeKDF() { public boolean isAllowNativeKDF() {
return prefs().getBoolean( PREF_NATIVE_KDF, MasterKey.isAllowNativeByDefault() ); return prefs().getBoolean( PREF_NATIVE_KDF, true );
} }
public boolean setTestsPassed(final Set<String> value) { public boolean setTestsPassed(final Set<String> value) {
@@ -138,20 +138,20 @@ public final class Preferences {
return prefs().getString( PREF_FULL_NAME, "" ); return prefs().getString( PREF_FULL_NAME, "" );
} }
public boolean setDefaultSiteType(@Nonnull final MPSiteType value) { public boolean setDefaultResultType(final MPResultType value) {
if (getDefaultSiteType() == value) if (getDefaultResultType() == value)
return false; return false;
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply(); prefs().edit().putInt( PREF_RESULT_TYPE, value.ordinal() ).apply();
return true; return true;
} }
@Nonnull @Nonnull
public MPSiteType getDefaultSiteType() { public MPResultType getDefaultResultType() {
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )]; return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPResultType.DEFAULT.ordinal() )];
} }
public boolean setDefaultVersion(@Nonnull final MasterKey.Version value) { public boolean setDefaultVersion(final MPMasterKey.Version value) {
if (getDefaultVersion() == value) if (getDefaultVersion() == value)
return false; return false;
@@ -160,7 +160,7 @@ public final class Preferences {
} }
@Nonnull @Nonnull
public MasterKey.Version getDefaultVersion() { public MPMasterKey.Version getDefaultVersion() {
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )]; return MPMasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MPMasterKey.Version.CURRENT.ordinal() )];
} }
} }

View File

@@ -80,7 +80,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
preferences.setNativeKDFEnabled( isChecked ); preferences.setNativeKDFEnabled( isChecked );
MasterKey.setAllowNativeByDefault( isChecked ); // TODO: MasterKey.setAllowNativeByDefault( isChecked );
} }
} ); } );
@@ -122,7 +122,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
if (testFuture != null) if (testFuture != null)
testFuture.cancel( true ); testFuture.cancel( true );
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() ); // TODO: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null ); setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() { Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {

View File

@@ -105,7 +105,7 @@
android:id="@id/sitePasswordField" android:id="@id/sitePasswordField"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteTypeButton" android:nextFocusForward="@+id/resultTypeButton"
android:gravity="center" android:gravity="center"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textColor="#FFFFFF" android:textColor="#FFFFFF"
@@ -157,7 +157,7 @@
android:gravity="center"> android:gravity="center">
<Button <Button
android:id="@id/siteTypeButton" android:id="@id/resultTypeButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
@@ -175,12 +175,12 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:labelFor="@id/siteTypeButton" android:labelFor="@id/resultTypeButton"
android:gravity="center" android:gravity="center"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textSize="12sp" android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark" android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteType_hint" /> android:text="@string/resultType_hint" />
</LinearLayout> </LinearLayout>

View File

@@ -8,7 +8,7 @@
<string name="masterPassword_hint">Your master password</string> <string name="masterPassword_hint">Your master password</string>
<string name="siteName_hint">eg. google.com</string> <string name="siteName_hint">eg. google.com</string>
<string name="sitePassword_hint">Tap to copy</string> <string name="sitePassword_hint">Tap to copy</string>
<string name="siteType_hint">Type</string> <string name="resultType_hint">Type</string>
<string name="siteCounter_hint">Counter</string> <string name="siteCounter_hint">Counter</string>
<string name="siteVersion_hint">Algorithm</string> <string name="siteVersion_hint">Algorithm</string>
<string name="empty" /> <string name="empty" />

View File

@@ -20,7 +20,6 @@
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39D8508BF868907E9732E /* PearlHangDetector.h */; }; 93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39D8508BF868907E9732E /* PearlHangDetector.h */; };
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; }; 93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.m */; };
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; }; 93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3957D76F71A652716EECC /* MPStoreViewController.m */; };
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39488AB33616661725929 /* UIView+AlphaScale.m */; };
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; }; 93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */; };
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */; }; 93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */; };
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; }; 93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */; };
@@ -32,7 +31,6 @@
93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; }; 93D3954FCE045A3CC7E804B7 /* MPUsersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */; };
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; }; 93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.m */; };
93D39577FD8BB0945DB2F0A3 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */; }; 93D39577FD8BB0945DB2F0A3 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */; };
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */; };
93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */; }; 93D395B715D15F2B56F2A2EE /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */; };
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; }; 93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; };
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; }; 93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B050DD5F55E9794EFD4 /* MPPopdownSegue.m */; };
@@ -40,9 +38,7 @@
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; }; 93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; };
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; }; 93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.m */; };
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; }; 93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */; };
93D397FCAAC6FA885247A4F9 /* PearlLinks.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */; };
93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; }; 93D3980046016EFD05B35BC5 /* PearlUICollectionView.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */; };
93D39861AEE621B287EA93E9 /* PearlLinks.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D399C408B705172FA0FA02 /* PearlLinks.h */; };
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; }; 93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.m */; };
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; }; 93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */; };
93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; }; 93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; };
@@ -134,8 +130,6 @@
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; }; DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; };
DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; }; DA2CA4DD18D28859007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */; };
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; }; DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */; };
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */; };
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */; };
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */; }; DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */; };
DA2CA4E618D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */; }; DA2CA4E618D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */; };
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; }; DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
@@ -165,7 +159,6 @@
DA32D07C19D7D784004F3F0E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07919D7D784004F3F0E /* background.png */; }; DA32D07C19D7D784004F3F0E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA32D07919D7D784004F3F0E /* background.png */; };
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; }; DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; }; DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3509FD15F101A500C14A8E /* PearlQueue.m */; };
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */; };
DA3BCFCB19BD09D5006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */; }; DA3BCFCB19BD09D5006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCA19BD09D5006B2681 /* SourceCodePro-Regular.otf */; };
DA4522441902355C008F650A /* icon_book.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370C1711E29500CF925C /* icon_book.png */; }; DA4522441902355C008F650A /* icon_book.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370C1711E29500CF925C /* icon_book.png */; };
DA4522451902355C008F650A /* icon_book@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370D1711E29500CF925C /* icon_book@2x.png */; }; DA4522451902355C008F650A /* icon_book@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD370D1711E29500CF925C /* icon_book@2x.png */; };
@@ -175,7 +168,6 @@
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; }; 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 */; }; 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 */; }; 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 */; }; DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.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 */; }; DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
@@ -212,7 +204,6 @@
DA92614E1BE1A57500369DE5 /* MPAppDelegate_InApp.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92614D1BE1A57500369DE5 /* MPAppDelegate_InApp.m */; }; DA92614E1BE1A57500369DE5 /* MPAppDelegate_InApp.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92614D1BE1A57500369DE5 /* MPAppDelegate_InApp.m */; };
DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; }; DA945C8717E3F3FD0053236B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA945C8617E3F3FD0053236B /* Images.xcassets */; };
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95B50B1C476B6A0067F5EF /* LocalAuthentication.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95B50B1C476B6A0067F5EF /* LocalAuthentication.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */; };
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; }; DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; }; DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; }; DAA141211922FF020032B392 /* PearlTween.h in Headers */ = {isa = PBXBuildFile; fileRef = DAA1411D1922FF020032B392 /* PearlTween.h */; };
@@ -249,11 +240,26 @@
DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; }; DAA1765219D8B82B0044227B /* copy_pw.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763C19D8B82B0044227B /* copy_pw.png */; };
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; }; DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; }; 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 */; }; DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */; };
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; }; DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9B1F7725C500CC6D43 /* aes.c */; };
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */; };
DAB4FBC5202FDDDD002768FB /* NSInvocation+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */; };
DAB4FBC6202FDDEC002768FB /* NSMutableSet+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */; };
DAB4FBC7202FDDEF002768FB /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */; };
DAB4FBC8202FDDF3002768FB /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */; };
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DA45711C1F572F1E00D54152 /* PearlCryptUtils.h */; };
DAB4FBCA202FDE13002768FB /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */; };
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBCB202FDE47002768FB /* PearlLinks.m */; };
DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */; };
DAB4FBD5202FDE48002768FB /* UIView+PearlSize.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */; };
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBCE202FDE47002768FB /* PearlLinks.h */; };
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */; };
DAB4FBD8202FDE48002768FB /* WTFViews.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBD0202FDE47002768FB /* WTFViews.h */; };
DAB4FBD9202FDE48002768FB /* UIView+PearlSize.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */; };
DAB4FBDA202FDE48002768FB /* WTFViews.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBD2202FDE48002768FB /* WTFViews.m */; };
DAB7AE5D1F3D752900C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE5C1F3D752900C856B1 /* libjson-c.a */; }; 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-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */; };
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 */; }; DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; }; 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 */; }; DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
@@ -349,7 +355,6 @@
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; }; DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379A1711E29600CF925C /* icon_key.png */; }; DAC8DF47192831E100BA7D71 /* icon_key.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379A1711E29600CF925C /* icon_key.png */; };
DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379B1711E29600CF925C /* icon_key@2x.png */; }; DAC8DF48192831E100BA7D71 /* icon_key@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD379B1711E29600CF925C /* icon_key@2x.png */; };
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; }; DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; }; DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; }; DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
@@ -504,7 +509,6 @@
93D3924EE15017F8A12CB436 /* MPSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesViewController.m; sourceTree = "<group>"; }; 93D3924EE15017F8A12CB436 /* MPSitesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSitesViewController.m; sourceTree = "<group>"; };
93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; }; 93D392876BE5C011DE73B43F /* MPPopdownSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPopdownSegue.h; sourceTree = "<group>"; };
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; }; 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+AlphaScale.h"; sourceTree = "<group>"; };
93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; }; 93D393310223DDB35218467A /* MPCombinedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCombinedViewController.m; sourceTree = "<group>"; };
93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; }; 93D393B97158D7BE9332EA53 /* NSDictionary+Indexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Indexing.h"; sourceTree = "<group>"; };
93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; }; 93D393BB973253D4BAAC84AA /* PearlEMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlEMail.m; sourceTree = "<group>"; };
@@ -512,7 +516,6 @@
93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; 93D394077F8FAB8167647187 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; };
93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; }; 93D3942A356B639724157982 /* PearlOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlOverlay.h; sourceTree = "<group>"; };
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; }; 93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+PearlFirstResponder.h"; sourceTree = "<group>"; };
93D39488AB33616661725929 /* UIView+AlphaScale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+AlphaScale.m"; sourceTree = "<group>"; };
93D394D73F5BC92297CE8D7B /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; }; 93D394D73F5BC92297CE8D7B /* MPAlgorithmV3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAlgorithmV3.h; sourceTree = "<group>"; };
93D395105935859D71679931 /* MPOverlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOverlayViewController.m; sourceTree = "<group>"; }; 93D395105935859D71679931 /* MPOverlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOverlayViewController.m; sourceTree = "<group>"; };
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Visible.m"; sourceTree = "<group>"; }; 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Visible.m"; sourceTree = "<group>"; };
@@ -540,7 +543,6 @@
93D399A8E3181B442D347CD7 /* MPAlgorithmV2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV2.m; sourceTree = "<group>"; }; 93D399A8E3181B442D347CD7 /* MPAlgorithmV2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV2.m; sourceTree = "<group>"; };
93D399B36CDB2004D7C51391 /* MPMessageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMessageViewController.m; sourceTree = "<group>"; }; 93D399B36CDB2004D7C51391 /* MPMessageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMessageViewController.m; sourceTree = "<group>"; };
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; }; 93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPersistentStore+PearlMigration.m"; sourceTree = "<group>"; };
93D399C408B705172FA0FA02 /* PearlLinks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLinks.h; sourceTree = "<group>"; };
93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; }; 93D399E571F61E50A9BF8FAF /* MPUsersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUsersViewController.m; sourceTree = "<group>"; };
93D399F244BB522A317811BB /* MPFixable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixable.h; sourceTree = "<group>"; }; 93D399F244BB522A317811BB /* MPFixable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixable.h; sourceTree = "<group>"; };
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; }; 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+PearlFirstResponder.m"; sourceTree = "<group>"; };
@@ -582,7 +584,6 @@
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; }; 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+PearlFullDescription.m"; sourceTree = "<group>"; };
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; }; 93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; }; 93D39FD9623E8D5571C0AEB3 /* MPAlgorithmV3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAlgorithmV3.m; sourceTree = "<group>"; };
93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLinks.m; sourceTree = "<group>"; };
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; }; DA071BF1190187FE00179766 /* empty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "empty@2x.png"; sourceTree = "<group>"; };
DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; }; DA071BF2190187FE00179766 /* empty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree = "<group>"; };
@@ -762,8 +763,6 @@
DA2C3D641BD9612F001137B3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; DA2C3D641BD9612F001137B3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; }; DA2CA4D918D28859007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; }; DA2CA4DA18D28859007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = "<group>"; };
DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+PearlBlock.h"; sourceTree = "<group>"; };
DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PearlUIKit.h"; sourceTree = "<group>"; }; DA2CA4E218D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLayoutConstraint+PearlUIKit.h"; sourceTree = "<group>"; };
DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PearlUIKit.m"; sourceTree = "<group>"; }; DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLayoutConstraint+PearlUIKit.m"; sourceTree = "<group>"; };
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; }; DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
@@ -790,7 +789,6 @@
DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; }; DA32D07919D7D784004F3F0E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = background.png; path = ios/launch/background.png; sourceTree = "<group>"; };
DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; }; DA3509FC15F101A500C14A8E /* PearlQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlQueue.h; sourceTree = "<group>"; };
DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; }; DA3509FD15F101A500C14A8E /* PearlQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlQueue.m; sourceTree = "<group>"; };
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>"; }; 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>"; }; 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>"; }; DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlCryptUtils.m; sourceTree = "<group>"; };
@@ -871,9 +869,22 @@
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; }; DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; }; DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; }; DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; }; DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; }; DAA449D11EEC4B5800E7BDD5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
DAB07C9B1F7725C500CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
DAB07C9C1F7725C500CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+Pearl.h"; sourceTree = "<group>"; };
DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+Pearl.m"; sourceTree = "<group>"; };
DAB4FBCB202FDE47002768FB /* PearlLinks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLinks.m; sourceTree = "<group>"; };
DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PearlLayout.h"; sourceTree = "<group>"; };
DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PearlSize.h"; sourceTree = "<group>"; };
DAB4FBCE202FDE47002768FB /* PearlLinks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLinks.h; sourceTree = "<group>"; };
DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PearlLayout.m"; sourceTree = "<group>"; };
DAB4FBD0202FDE47002768FB /* WTFViews.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WTFViews.h; sourceTree = "<group>"; };
DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PearlSize.m"; sourceTree = "<group>"; };
DAB4FBD2202FDE48002768FB /* WTFViews.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WTFViews.m; sourceTree = "<group>"; };
DAB4FBDB202FDE5E002768FB /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Pearl-Prefix.pch"; sourceTree = "<group>"; };
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>"; }; 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>"; }; 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>"; }; DAB7AE621F3D755B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
@@ -896,8 +907,8 @@
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.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>"; }; 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>"; }; 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>"; }; DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; }; DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; DABB981515100B4000B05417 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
DABD360F1711E29400CF925C /* ui_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ui_background.png; sourceTree = "<group>"; }; 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>"; }; DABD36101711E29400CF925C /* ui_background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ui_background@2x.png"; sourceTree = "<group>"; };
@@ -1511,7 +1522,7 @@
DABD38C11711E29700CF925C /* tip_location_teal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_teal@2x.png"; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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 = 1; lastKnownFileType = sourcecode.javascript; path = "jquery-1.6.1.min.js"; 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>"; };
DABD38C91711E29700CF925C /* keypad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = keypad.png; 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>"; }; 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>"; }; DABD38CB1711E29700CF925C /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
@@ -1562,8 +1573,6 @@
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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; }; DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = 1; 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>"; }; 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>"; }; DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
@@ -1680,7 +1689,6 @@
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */, DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */,
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */, DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */, DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */,
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */, DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */, DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */, DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
@@ -1751,6 +1759,8 @@
93D39A2239FFFE6BEC83E191 /* C */ = { 93D39A2239FFFE6BEC83E191 /* C */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DAB07C9B1F7725C500CC6D43 /* aes.c */,
DAB07C9C1F7725C500CC6D43 /* aes.h */,
DA5B0B3E1F36469400B663F0 /* base64.c */, DA5B0B3E1F36469400B663F0 /* base64.c */,
DA5B0B3F1F36469400B663F0 /* base64.h */, DA5B0B3F1F36469400B663F0 /* base64.h */,
93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */, 93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */,
@@ -1759,10 +1769,10 @@
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */, 93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */, 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */, 93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */, DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */,
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */, DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */,
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */, DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */,
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */, DAA449D11EEC4B5800E7BDD5 /* mpw-marshal.h */,
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */, 93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
93D39AFD17CBE324D745DAB0 /* mpw-types.h */, 93D39AFD17CBE324D745DAB0 /* mpw-types.h */,
93D396C311C3725870343EE0 /* mpw-util.c */, 93D396C311C3725870343EE0 /* mpw-util.c */,
@@ -2993,7 +3003,6 @@
93D39F556F2F142740A65E59 /* MPWebViewController.h */, 93D39F556F2F142740A65E59 /* MPWebViewController.h */,
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */, 93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
DABD3BF91711E2DC00CF925C /* Settings.bundle */, DABD3BF91711E2DC00CF925C /* Settings.bundle */,
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */,
); );
path = iOS; path = iOS;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3004,7 +3013,7 @@
DAFE45D715039823003ABA7C /* Pearl */, DAFE45D715039823003ABA7C /* Pearl */,
DAFE45FC15039823003ABA7C /* Pearl-Crypto */, DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
DAFE460715039823003ABA7C /* Pearl-UIKit */, DAFE460715039823003ABA7C /* Pearl-UIKit */,
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */, DAB4FBDB202FDE5E002768FB /* Pearl-Prefix.pch */,
); );
path = Pearl; path = Pearl;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3039,7 +3048,6 @@
DACA29701705E1A8002C6C22 /* Data */ = { DACA29701705E1A8002C6C22 /* Data */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DACA29711705E1A8002C6C22 /* ciphers.plist */,
DACA29721705E1A8002C6C22 /* dictionary.lst */, DACA29721705E1A8002C6C22 /* dictionary.lst */,
); );
path = Data; path = Data;
@@ -3091,6 +3099,8 @@
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */, 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */,
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */, 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */,
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */, 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */,
DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */,
DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */,
DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */, DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */,
DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */, DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */,
DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */, DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */,
@@ -3100,14 +3110,14 @@
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */, DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */,
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */, DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */,
DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */, DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */,
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */, 93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */,
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */, 93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */,
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */, DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */,
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */, DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */, DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */, DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */,
DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */,
DAFE45DE15039823003ABA7C /* Pearl.h */, DAFE45DE15039823003ABA7C /* Pearl.h */,
DA30E9CD15722ECA00A68B4C /* Pearl.m */, DA30E9CD15722ECA00A68B4C /* Pearl.m */,
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */, DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
@@ -3118,6 +3128,8 @@
DAFE45E615039823003ABA7C /* PearlConfig.m */, DAFE45E615039823003ABA7C /* PearlConfig.m */,
DAFE45E715039823003ABA7C /* PearlDeviceUtils.h */, DAFE45E715039823003ABA7C /* PearlDeviceUtils.h */,
DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */, DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */,
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
DAFE45E915039823003ABA7C /* PearlInfoPlist.h */, DAFE45E915039823003ABA7C /* PearlInfoPlist.h */,
DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */, DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */,
DA30E9D515723E6900A68B4C /* PearlLazy.h */, DA30E9D515723E6900A68B4C /* PearlLazy.h */,
@@ -3141,10 +3153,6 @@
DAA1411C1922FF020032B392 /* PearlTween.m */, DAA1411C1922FF020032B392 /* PearlTween.m */,
DAFE45F815039823003ABA7C /* README */, DAFE45F815039823003ABA7C /* README */,
DAFE45F915039823003ABA7C /* Resources */, DAFE45F915039823003ABA7C /* Resources */,
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
); );
path = Pearl; path = Pearl;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3193,6 +3201,8 @@
DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */, DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */,
DAFE461015039823003ABA7C /* PearlGradientView.h */, DAFE461015039823003ABA7C /* PearlGradientView.h */,
DAFE461115039823003ABA7C /* PearlGradientView.m */, DAFE461115039823003ABA7C /* PearlGradientView.m */,
DAB4FBCE202FDE47002768FB /* PearlLinks.h */,
DAB4FBCB202FDE47002768FB /* PearlLinks.m */,
DAFE461615039823003ABA7C /* PearlMessageView.h */, DAFE461615039823003ABA7C /* PearlMessageView.h */,
DAFE461715039823003ABA7C /* PearlMessageView.m */, DAFE461715039823003ABA7C /* PearlMessageView.m */,
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */, DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */,
@@ -3245,14 +3255,16 @@
DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */, DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */,
DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */, DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */,
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */, DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */,
DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */,
DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */,
DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */,
DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */, DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */,
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */, DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */,
93D39488AB33616661725929 /* UIView+AlphaScale.m */,
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */,
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */, 93D39B7B765546B1F1900CB7 /* UIView+Visible.h */,
93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */, 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
93D399C408B705172FA0FA02 /* PearlLinks.h */, DAB4FBD0202FDE47002768FB /* WTFViews.h */,
DAB4FBD2202FDE48002768FB /* WTFViews.m */,
); );
path = "Pearl-UIKit"; path = "Pearl-UIKit";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -3295,10 +3307,12 @@
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */, DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */, DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */, DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
DAB4FBD8202FDE48002768FB /* WTFViews.h in Headers */,
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */, DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */, DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */, DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */, DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */,
DAB4FBD5202FDE48002768FB /* UIView+PearlSize.h in Headers */,
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */, DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */,
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */, DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */, DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
@@ -3307,13 +3321,13 @@
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */, DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */, DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */, DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */,
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */, DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */, DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */, DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */, DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */, DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */,
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */, DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */,
DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */, DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */, DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */, DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
@@ -3321,9 +3335,11 @@
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */, DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */, DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */, DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */,
DAB4FBC6202FDDEC002768FB /* NSMutableSet+Pearl.h in Headers */,
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */, DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */,
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */, DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */, DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */,
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */, DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */, DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */, DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
@@ -3341,6 +3357,7 @@
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */, DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */,
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */, 93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */, 93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */,
DAB4FBC8202FDDF3002768FB /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */, DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */, DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */,
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */, 93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
@@ -3353,12 +3370,12 @@
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */, 93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */, 93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */,
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */, 93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */,
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */,
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */, 93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */,
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */, 93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */,
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */, 93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
93D3959696396A91961C6148 /* UIView+AlphaScale.h in Headers */,
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */, 93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
93D39861AEE621B287EA93E9 /* PearlLinks.h in Headers */, DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */,
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */, 93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -3527,15 +3544,15 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
CLASSPREFIX = MP; CLASSPREFIX = MP;
LastUpgradeCheck = 0820; LastUpgradeCheck = 0920;
ORGANIZATIONNAME = Lyndir; ORGANIZATIONNAME = Lyndir;
TargetAttributes = { TargetAttributes = {
DA32D01F19D111C6004F3F0E = { DA32D01F19D111C6004F3F0E = {
CreatedOnToolsVersion = 6.0;
DevelopmentTeam = HL3Q45LX9N; DevelopmentTeam = HL3Q45LX9N;
}; };
DA5BFA43147E415C00F98B1E = { DA5BFA43147E415C00F98B1E = {
DevelopmentTeam = HL3Q45LX9N; DevelopmentTeam = HL3Q45LX9N;
LastSwiftMigration = 0920;
ProvisioningStyle = Automatic; ProvisioningStyle = Automatic;
SystemCapabilities = { SystemCapabilities = {
com.apple.BackgroundModes = { com.apple.BackgroundModes = {
@@ -3553,7 +3570,6 @@
}; };
}; };
DAA1757C19D86BE70044227B = { DAA1757C19D86BE70044227B = {
CreatedOnToolsVersion = 6.0;
DevelopmentTeam = HL3Q45LX9N; DevelopmentTeam = HL3Q45LX9N;
}; };
DAB7AE3D1F3D464A00C856B1 = { DAB7AE3D1F3D464A00C856B1 = {
@@ -3699,7 +3715,6 @@
files = ( files = (
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */, DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */, DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */, DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */, DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */, DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
@@ -3869,7 +3884,6 @@
DA8495311A93049300B3053D /* icon_down.png in Resources */, DA8495311A93049300B3053D /* icon_down.png in Resources */,
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */, DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */, DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */,
DA5A09DF171A70E4005284AB /* play.png in Resources */, DA5A09DF171A70E4005284AB /* play.png in Resources */,
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */, DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */, DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
@@ -3970,7 +3984,7 @@
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */, DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m in Sources */, DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.m in Sources */,
DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */, DABD3C1C1711E2DC00CF925C /* MPGuideViewController.m in Sources */,
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */, DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */,
DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */, DABD3C1E1711E2DC00CF925C /* MPPreferencesViewController.m in Sources */,
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */, DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */, DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
@@ -3988,8 +4002,7 @@
DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */, DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */,
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */, 93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */,
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */, 93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */, DAB7AE991F3DDEE000C856B1 /* mpw-marshal-util.c in Sources */,
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */,
93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */, 93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */,
DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */, DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */, 93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
@@ -3998,12 +4011,12 @@
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */, 93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */, DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */,
DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */, DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */,
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */,
93D39EAA4D064193074D3021 /* MPFixable.m in Sources */, 93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */, 93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */, 93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */, 93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */, 93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */,
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */, 93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */, 93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */, 93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
@@ -4100,24 +4113,28 @@
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */, 93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */, DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */,
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */, 93D39262A8A97DB748213309 /* PearlEMail.m in Sources */,
DAB4FBD9202FDE48002768FB /* UIView+PearlSize.m in Sources */,
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */, DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
DAB4FBDA202FDE48002768FB /* WTFViews.m in Sources */,
DAB4FBC7202FDDEF002768FB /* NSMutableSet+Pearl.m in Sources */,
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */, 93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */,
DA32D01A19D046E1004F3F0E /* PearlFixedTableView.m in Sources */, DA32D01A19D046E1004F3F0E /* PearlFixedTableView.m in Sources */,
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */, 93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */, 93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */,
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */,
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */, 93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
DAB4FBCA202FDE13002768FB /* PearlCryptUtils.m in Sources */,
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */, 93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */, 93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
DAA141201922FF020032B392 /* PearlTween.m in Sources */, DAA141201922FF020032B392 /* PearlTween.m in Sources */,
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */,
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */, 93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */,
93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */, 93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */,
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */, 93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */,
93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */, 93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */,
93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */, 93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */,
93D393AA69A1193401160418 /* UIView+AlphaScale.m in Sources */,
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */, 93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */,
93D397FCAAC6FA885247A4F9 /* PearlLinks.m in Sources */, DAB4FBC5202FDDDD002768FB /* NSInvocation+Pearl.m in Sources */,
93D395373A425B05C86B2268 /* PearlHangDetector.m in Sources */, 93D395373A425B05C86B2268 /* PearlHangDetector.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -4215,11 +4232,19 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_STATIC_ANALYZER_MODE = deep; CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -4230,19 +4255,25 @@
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = HL3Q45LX9N; DEVELOPMENT_TEAM = HL3Q45LX9N;
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
@@ -4253,6 +4284,10 @@
"NDEBUG=1", "NDEBUG=1",
"NS_BLOCK_ASSERTIONS=1", "NS_BLOCK_ASSERTIONS=1",
"CRASHLYTICS=1", "CRASHLYTICS=1",
PEARL,
PEARL_UIKIT,
PEARL_CRYPTO,
PEARL_WITH_MESSAGEUI,
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -4275,7 +4310,7 @@
GCC_WARN_SIGN_COMPARE = NO; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = NO; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
@@ -4288,6 +4323,7 @@
"$(inherited)", "$(inherited)",
); );
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
PUBLIC_HEADERS_FOLDER_PATH = include; PUBLIC_HEADERS_FOLDER_PATH = include;
@@ -4295,6 +4331,7 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
WARNING_CFLAGS = "-Wno-float-conversion"; WARNING_CFLAGS = "-Wno-float-conversion";
@@ -4310,16 +4347,17 @@
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements; CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
COPY_PHASE_STRIP = YES;
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a; EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"\"$(SRCROOT)/External/iOS\"", "\"$(SRCROOT)/External/iOS\"",
); );
GCC_C_LANGUAGE_STANDARD = c11;
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch"; GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist"; INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib", "$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
@@ -4332,7 +4370,10 @@
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword; PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO; SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;
TARGETED_DEVICE_FAMILY = 1; STRIP_SWIFT_SYMBOLS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0;
}; };
name = Test; name = Test;
}; };
@@ -4340,11 +4381,13 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
"$(inherited)", "$(inherited)",
); );
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
SWIFT_VERSION = 4.0;
}; };
name = Test; name = Test;
}; };
@@ -4403,10 +4446,18 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -4417,19 +4468,26 @@
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = HL3Q45LX9N; DEVELOPMENT_TEAM = HL3Q45LX9N;
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES; ENABLE_TESTABILITY = YES;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
@@ -4440,6 +4498,10 @@
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
"CRASHLYTICS=1", "CRASHLYTICS=1",
PEARL,
PEARL_UIKIT,
PEARL_CRYPTO,
PEARL_WITH_MESSAGEUI,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@@ -4476,6 +4538,7 @@
"$(inherited)", "$(inherited)",
); );
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
@@ -4483,6 +4546,8 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
WARNING_CFLAGS = "-Wno-float-conversion"; WARNING_CFLAGS = "-Wno-float-conversion";
}; };
@@ -4493,11 +4558,19 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_STATIC_ANALYZER_MODE = deep; CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -4508,19 +4581,25 @@
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
DEVELOPMENT_TEAM = HL3Q45LX9N; DEVELOPMENT_TEAM = HL3Q45LX9N;
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
@@ -4531,6 +4610,10 @@
"NDEBUG=1", "NDEBUG=1",
"NS_BLOCK_ASSERTIONS=1", "NS_BLOCK_ASSERTIONS=1",
"CRASHLYTICS=1", "CRASHLYTICS=1",
PEARL,
PEARL_UIKIT,
PEARL_CRYPTO,
PEARL_WITH_MESSAGEUI,
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -4553,7 +4636,7 @@
GCC_WARN_SIGN_COMPARE = NO; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = NO; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
@@ -4566,6 +4649,7 @@
"$(inherited)", "$(inherited)",
); );
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
PUBLIC_HEADERS_FOLDER_PATH = include; PUBLIC_HEADERS_FOLDER_PATH = include;
@@ -4573,6 +4657,7 @@
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
STRIP_INSTALLED_PRODUCT = NO; STRIP_INSTALLED_PRODUCT = NO;
STRIP_SWIFT_SYMBOLS = NO;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
WARNING_CFLAGS = "-Wno-float-conversion"; WARNING_CFLAGS = "-Wno-float-conversion";
@@ -4592,44 +4677,12 @@
"$(inherited)", "$(inherited)",
"\"$(SRCROOT)/External/iOS\"", "\"$(SRCROOT)/External/iOS\"",
); );
GCC_C_LANGUAGE_STANDARD = c11;
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch"; GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist"; INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
"$(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",
);
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO;
TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
DA5BFA6F147E415C00F98B1E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/External/iOS\"",
);
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib", "$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
@@ -4642,6 +4695,49 @@
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword; PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO; SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;
STRIP_SWIFT_SYMBOLS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
};
name = Debug;
};
DA5BFA6F147E415C00F98B1E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
EXCLUDED_SOURCE_FILE_NAMES = libDCIntrospect.a;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/External/iOS\"",
);
GCC_C_LANGUAGE_STANDARD = c11;
GCC_PREFIX_HEADER = "Source/MasterPassword-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
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",
);
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
SKIP_INSTALL = NO;
STRIP_INSTALLED_PRODUCT = YES;
STRIP_SWIFT_SYMBOLS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1; TARGETED_DEVICE_FAMILY = 1;
}; };
name = Release; name = Release;
@@ -4820,11 +4916,13 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
"$(inherited)", "$(inherited)",
); );
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
SWIFT_VERSION = 4.0;
}; };
name = Debug; name = Debug;
}; };
@@ -4832,7 +4930,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
"$(inherited)", "$(inherited)",

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0830" LastUpgradeVersion = "0920"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@@ -31,7 +31,7 @@
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; }; DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; }; DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; }; DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; }; DA1C7AAA1F1A8F24009A3551 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; }; DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; }; DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; }; DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
@@ -64,8 +64,6 @@
DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; }; DA2CA4EE18D323D3007798F8 /* NSError+PearlFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */; };
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; }; DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */; };
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */; }; DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */; };
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */; };
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */; };
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; }; DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; }; DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; };
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; }; DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; };
@@ -77,7 +75,6 @@
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; }; DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3B8451190FC86F00246EEA /* NSManagedObject+Pearl.h */; };
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; }; DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; }; 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 */; }; DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; }; DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; }; DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
@@ -110,8 +107,8 @@
DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; }; DA6774431A474A3B004F356A /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773BB1A4746AF004F356A /* mpw-algorithm.c */; };
DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; }; DA6774451A474A3B004F356A /* mpw-types.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C21A4746AF004F356A /* mpw-types.c */; };
DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; }; DA6774461A474A3B004F356A /* mpw-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA6773C51A4746AF004F356A /* mpw-util.c */; };
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */; }; DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
DA7471A61F2B71B9005F3468 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */; }; DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */; };
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; }; DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = DA89D4EA1A51EABD00AC64D7 /* Pearl-Cocoa.h */; };
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = DA89D4EB1A51EABD00AC64D7 /* Pearl-Cocoa.m */; }; DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = DA89D4EB1A51EABD00AC64D7 /* Pearl-Cocoa.m */; };
DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; }; DA8ED895192906920099B726 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8ED891192906920099B726 /* PearlTween.m */; };
@@ -121,7 +118,7 @@
DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; }; DA9261521BE1A86700369DE5 /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261501BE1A86700369DE5 /* Fabric.framework */; };
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; }; DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; }; DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; }; DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; }; DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; }; DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; };
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; }; DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
@@ -130,6 +127,20 @@
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; }; DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; }; 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 */; }; DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
DAB07CA31F77261400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
DAB07CA51F77261C00CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
DAB07CA61F77262400CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9E1F7725D400CC6D43 /* aes.c */; };
DAB4FBE3202FF93E002768FB /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */; };
DAB4FBE4202FF93E002768FB /* PearlHangDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */; };
DAB4FBE5202FF93E002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */; };
DAB4FBE6202FF93E002768FB /* NSInvocation+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */; };
DAB4FBE7202FF93E002768FB /* NSOrderedSetOrArray.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */; };
DAB4FBE8202FF93E002768FB /* NSOrderedSetOrArray.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */; };
DAB4FBE9202FF94C002768FB /* NSMutableSet+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DACBFCDB1C59B22E007EF90F /* NSMutableSet+Pearl.h */; };
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */; };
DAB4FBEB202FF975002768FB /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DA45711F1F572F3200D54152 /* PearlCryptUtils.h */; };
DAB4FBEC202FF979002768FB /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711E1F572F3200D54152 /* PearlCryptUtils.m */; };
DAB7AE5A1F3D74E700C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE591F3D74E700C856B1 /* libjson-c.a */; }; 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 */; }; 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 */; }; DAB7AE941F3D757B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE901F3D757B00C856B1 /* libjson-c.a */; };
@@ -177,11 +188,9 @@
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24581705DF7D002C6C22 /* menu-icon.png */; }; DACA27381705DF81002C6C22 /* menu-icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DACA24581705DF7D002C6C22 /* menu-icon.png */; };
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; }; DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */; };
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; }; DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */ = {isa = PBXBuildFile; fileRef = DACA268F1705DF81002C6C22 /* SourceCodePro-Black.otf */; };
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; }; DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; }; DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; }; DACA299A1705E2BD002C6C22 /* JRSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = DACA298C1705E2BD002C6C22 /* JRSwizzle.m */; };
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DACBFCDC1C59B22E007EF90F /* NSMutableSet+Pearl.m */; };
DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; }; DAD9B5F01762CAA4001835F9 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAD9B5EF1762CAA4001835F9 /* ServiceManagement.framework */; };
DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; }; DAD9B5F11762CAB9001835F9 /* MasterPassword-Mac-LoginHelper.app in Copy LoginHelper */ = {isa = PBXBuildFile; fileRef = DAD9B5E6176299BA001835F9 /* MasterPassword-Mac-LoginHelper.app */; };
DADD5DFA1EA173B0005E7D96 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; }; DADD5DFA1EA173B0005E7D96 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA0979571E9A824700F0BFE8 /* libsodium.a */; };
@@ -480,8 +489,6 @@
DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; }; DA2CA4E818D323D3007798F8 /* NSError+PearlFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+PearlFullDescription.h"; sourceTree = "<group>"; };
DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; }; DA2CA4E918D323D3007798F8 /* NSArray+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Pearl.m"; sourceTree = "<group>"; };
DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; }; DA2CA4EA18D323D3007798F8 /* NSArray+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Pearl.h"; sourceTree = "<group>"; };
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+PearlBlock.m"; sourceTree = "<group>"; };
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+PearlBlock.h"; sourceTree = "<group>"; };
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; }; DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-Crypto.m"; sourceTree = "<group>"; }; DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-Crypto.m"; sourceTree = "<group>"; };
DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; }; DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; };
@@ -950,8 +957,8 @@
DA6773C51A4746AF004F356A /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; }; DA6773C51A4746AF004F356A /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; };
DA6773C61A4746AF004F356A /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; }; DA6773C61A4746AF004F356A /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; };
DA67743B1A474A03004F356A /* mpw-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-test"; sourceTree = BUILT_PRODUCTS_DIR; }; DA67743B1A474A03004F356A /* mpw-test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "mpw-test"; sourceTree = BUILT_PRODUCTS_DIR; };
DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; }; DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; }; DA7471A11F2B71A9005F3468 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
DA771FE51E6E15A1004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; }; DA771FE51E6E15A1004D7EDE /* MasterPassword-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MasterPassword-Prefix.pch"; sourceTree = "<group>"; };
DA831A271A6E1146000AC234 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; }; DA831A271A6E1146000AC234 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
DA831A281A6E1146000AC234 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; }; DA831A281A6E1146000AC234 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; };
@@ -966,8 +973,8 @@
DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; }; DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; }; DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; }; DAA449D41EEC4B6B00E7BDD5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; }; DAAA81AF195A8D1300FA30D9 /* gradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = gradient.png; sourceTree = "<group>"; };
DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; }; DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; }; DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPersistentStore+PearlMigration.h"; sourceTree = "<group>"; };
@@ -977,6 +984,15 @@
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; 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>"; }; 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>"; }; DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
DAB07C9E1F7725D400CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
DAB07C9F1F7725D400CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
DAB4FBB3202FD60A002768FB /* Pearl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Pearl-Prefix.pch"; sourceTree = "<group>"; };
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlHangDetector.h; sourceTree = "<group>"; };
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlHangDetector.m; sourceTree = "<group>"; };
DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+Pearl.h"; sourceTree = "<group>"; };
DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+Pearl.m"; sourceTree = "<group>"; };
DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSOrderedSetOrArray.h; sourceTree = "<group>"; };
DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSOrderedSetOrArray.m; 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>"; }; 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>"; }; 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>"; }; DAB7AE7C1F3D757B00C856B1 /* bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bits.h; sourceTree = "<group>"; };
@@ -1003,7 +1019,6 @@
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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; }; DAC632871486D95D0075AEA5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
DAC77CAD148291A600BCF976 /* libPearl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPearl.a; sourceTree = BUILT_PRODUCTS_DIR; }; 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>"; };
DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; }; DACA241C1705DF7D002C6C22 /* logo-bare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "logo-bare.png"; sourceTree = "<group>"; };
DACA24321705DF7D002C6C22 /* avatar-13@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-13@2x.png"; sourceTree = "<group>"; }; DACA24321705DF7D002C6C22 /* avatar-13@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-13@2x.png"; sourceTree = "<group>"; };
DACA24331705DF7D002C6C22 /* avatar-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-3@2x.png"; sourceTree = "<group>"; }; DACA24331705DF7D002C6C22 /* avatar-3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-3@2x.png"; sourceTree = "<group>"; };
@@ -1046,7 +1061,6 @@
DACA24581705DF7D002C6C22 /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; }; DACA24581705DF7D002C6C22 /* menu-icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-icon.png"; sourceTree = "<group>"; };
DACA268E1705DF81002C6C22 /* SourceCodePro-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceCodePro-ExtraLight.otf"; sourceTree = "<group>"; }; 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>"; }; 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 = 1; 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>"; }; 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>"; }; DACA298C1705E2BD002C6C22 /* JRSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JRSwizzle.m; sourceTree = "<group>"; };
@@ -1878,6 +1892,8 @@
DA6773291A4746AF004F356A /* C */ = { DA6773291A4746AF004F356A /* C */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DAB07C9E1F7725D400CC6D43 /* aes.c */,
DAB07C9F1F7725D400CC6D43 /* aes.h */,
DA5B0B381F36467300B663F0 /* base64.c */, DA5B0B381F36467300B663F0 /* base64.c */,
DA5B0B391F36467300B663F0 /* base64.h */, DA5B0B391F36467300B663F0 /* base64.h */,
DA1C7AB71F1A8F6E009A3551 /* cli */, DA1C7AB71F1A8F6E009A3551 /* cli */,
@@ -1887,10 +1903,10 @@
DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */, DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */,
DA6773BB1A4746AF004F356A /* mpw-algorithm.c */, DA6773BB1A4746AF004F356A /* mpw-algorithm.c */,
DA6773BC1A4746AF004F356A /* mpw-algorithm.h */, DA6773BC1A4746AF004F356A /* mpw-algorithm.h */,
DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */, DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */,
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */, DA7471A11F2B71A9005F3468 /* mpw-marshal-util.h */,
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */, DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */,
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */, DAA449D41EEC4B6B00E7BDD5 /* mpw-marshal.h */,
DA6773C21A4746AF004F356A /* mpw-types.c */, DA6773C21A4746AF004F356A /* mpw-types.c */,
DA6773C31A4746AF004F356A /* mpw-types.h */, DA6773C31A4746AF004F356A /* mpw-types.h */,
DA6773C51A4746AF004F356A /* mpw-util.c */, DA6773C51A4746AF004F356A /* mpw-util.c */,
@@ -1987,7 +2003,7 @@
DAFE45D715039823003ABA7C /* Pearl */, DAFE45D715039823003ABA7C /* Pearl */,
DA89D4E51A51E53100AC64D7 /* Pearl-Cocoa */, DA89D4E51A51E53100AC64D7 /* Pearl-Cocoa */,
DAFE45FC15039823003ABA7C /* Pearl-Crypto */, DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */, DAB4FBB3202FD60A002768FB /* Pearl-Prefix.pch */,
); );
path = Pearl; path = Pearl;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2095,7 +2111,6 @@
DACA29701705E1A8002C6C22 /* Data */ = { DACA29701705E1A8002C6C22 /* Data */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DACA29711705E1A8002C6C22 /* ciphers.plist */,
DACA29721705E1A8002C6C22 /* dictionary.lst */, DACA29721705E1A8002C6C22 /* dictionary.lst */,
); );
path = Data; path = Data;
@@ -2147,6 +2162,12 @@
DAFE45D715039823003ABA7C /* Pearl */ = { DAFE45D715039823003ABA7C /* Pearl */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */,
DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */,
DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */,
DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */,
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */,
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */,
DA8ED893192906920099B726 /* include */, DA8ED893192906920099B726 /* include */,
93D396D04E57792A54D437AC /* NSArray+Indexing.h */, 93D396D04E57792A54D437AC /* NSArray+Indexing.h */,
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */, 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */,
@@ -2173,8 +2194,6 @@
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */, DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */, DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */, DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */,
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */,
DAFE45DE15039823003ABA7C /* Pearl.h */, DAFE45DE15039823003ABA7C /* Pearl.h */,
DA30E9CD15722ECA00A68B4C /* Pearl.m */, DA30E9CD15722ECA00A68B4C /* Pearl.m */,
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */, DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
@@ -2250,15 +2269,16 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */, DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */,
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */,
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */, DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */, DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */, DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */, DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */,
DA8ED897192906920099B726 /* map-macro.h in Headers */, DA8ED897192906920099B726 /* map-macro.h in Headers */,
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */, DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
DAB4FBE9202FF94C002768FB /* NSMutableSet+Pearl.h in Headers */,
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */, DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */, DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
DAB4FBE3202FF93E002768FB /* PearlHangDetector.h in Headers */,
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */, DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */, DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
DA8ED896192906920099B726 /* PearlTween.h in Headers */, DA8ED896192906920099B726 /* PearlTween.h in Headers */,
@@ -2266,13 +2286,16 @@
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */, DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */, DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */,
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */, DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
DAB4FBE7202FF93E002768FB /* NSOrderedSetOrArray.h in Headers */,
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */, DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */, DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */, DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */, DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */, DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
DAB4FBEB202FF975002768FB /* PearlCryptUtils.h in Headers */,
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */, DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */, DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
DAB4FBE5202FF93E002768FB /* NSInvocation+Pearl.h in Headers */,
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */, DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */, DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */, DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
@@ -2606,7 +2629,6 @@
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */, DACA27381705DF81002C6C22 /* menu-icon.png in Resources */,
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */, DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */, DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */, DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */, DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */, DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
@@ -2670,13 +2692,14 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */, DA1C7AAA1F1A8F24009A3551 /* mpw-marshal.c in Sources */,
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */, DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
DA5B0B3D1F36467900B663F0 /* base64.c in Sources */, DA5B0B3D1F36467900B663F0 /* base64.c in Sources */,
DAB07CA31F77261400CC6D43 /* aes.c in Sources */,
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */, DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */,
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */, DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */, DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */, DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */,
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */, DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2688,6 +2711,7 @@
DA5B0B3C1F36467900B663F0 /* base64.c in Sources */, DA5B0B3C1F36467900B663F0 /* base64.c in Sources */,
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */, DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */,
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */, DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */,
DAB07CA61F77262400CC6D43 /* aes.c in Sources */,
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */, DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */,
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */, DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */,
); );
@@ -2701,13 +2725,12 @@
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */, DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.m in Sources */, DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.m in Sources */,
DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */, DA5E5CF71724A667003798D8 /* MPAlgorithmV0.m in Sources */,
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */, DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */,
DA26861E1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */, DA26861E1EBFD7A40001E37E /* MPGeneratedSiteEntity+CoreDataProperties.m in Sources */,
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */, DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */, DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */, DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */,
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */, DAB07CA01F7725D400CC6D43 /* aes.c in Sources */,
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */,
DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */, DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
DA6774311A4746AF004F356A /* mpw-util.c in Sources */, DA6774311A4746AF004F356A /* mpw-util.c in Sources */,
DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */, DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */,
@@ -2738,7 +2761,7 @@
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */, DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */,
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */, DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */,
93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */, 93D393A1646430FAAC73E7FE /* MPMacApplication.m in Sources */,
DA7471A61F2B71B9005F3468 /* mpw-marshall-util.c in Sources */, DA7471A61F2B71B9005F3468 /* mpw-marshal-util.c in Sources */,
93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */, 93D398D1F5D8CD5A22AF6929 /* MPGradientView.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2749,6 +2772,7 @@
files = ( files = (
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */, DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */,
DA6774451A474A3B004F356A /* mpw-types.c in Sources */, DA6774451A474A3B004F356A /* mpw-types.c in Sources */,
DAB07CA51F77261C00CC6D43 /* aes.c in Sources */,
DA6774461A474A3B004F356A /* mpw-util.c in Sources */, DA6774461A474A3B004F356A /* mpw-util.c in Sources */,
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */, DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */,
DA5B0B3B1F36467800B663F0 /* base64.c in Sources */, DA5B0B3B1F36467800B663F0 /* base64.c in Sources */,
@@ -2778,6 +2802,7 @@
files = ( files = (
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */, DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */, DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */,
DAB4FBE8202FF93E002768FB /* NSOrderedSetOrArray.m in Sources */,
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */, DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */, DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */, DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */,
@@ -2785,6 +2810,7 @@
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */, DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */, DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
DAFE4A2315039824003ABA7C /* PearlDeviceUtils.m in Sources */, DAFE4A2315039824003ABA7C /* PearlDeviceUtils.m in Sources */,
DAB4FBE6202FF93E002768FB /* NSInvocation+Pearl.m in Sources */,
DAFE4A2515039824003ABA7C /* PearlInfoPlist.m in Sources */, DAFE4A2515039824003ABA7C /* PearlInfoPlist.m in Sources */,
DAFE4A2715039824003ABA7C /* PearlLogger.m in Sources */, DAFE4A2715039824003ABA7C /* PearlLogger.m in Sources */,
DA2C3D691BD9665B001137B3 /* PearlProfiler.m in Sources */, DA2C3D691BD9665B001137B3 /* PearlProfiler.m in Sources */,
@@ -2795,12 +2821,14 @@
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */, DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */,
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */, DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
DA8ED895192906920099B726 /* PearlTween.m in Sources */, DA8ED895192906920099B726 /* PearlTween.m in Sources */,
DA2CA4F118D323D3007798F8 /* NSTimer+PearlBlock.m in Sources */, DAB4FBE4202FF93E002768FB /* PearlHangDetector.m in Sources */,
DAB4FBEC202FF979002768FB /* PearlCryptUtils.m in Sources */,
DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */, DA3B8452190FC86F00246EEA /* NSManagedObject+Pearl.m in Sources */,
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */, DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */, DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */, DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */,
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */, DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */,
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */, DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */, DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */, 93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
@@ -2888,10 +2916,15 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_WARN_BOOL_CONVERSION = NO; CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -2899,16 +2932,21 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -2926,6 +2964,9 @@
"NDEBUG=1", "NDEBUG=1",
"NS_BLOCK_ASSERTIONS=1", "NS_BLOCK_ASSERTIONS=1",
"CRASHLYTICS=1", "CRASHLYTICS=1",
PEARL,
PEARL_COCOA,
PEARL_CRYPTO,
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -2946,12 +2987,12 @@
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = NO; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
@@ -3012,7 +3053,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
@@ -3048,7 +3089,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"", "\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2", /usr/include/libxml2,
"$(inherited)", "$(inherited)",
); );
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
@@ -3231,10 +3272,14 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_WARN_BOOL_CONVERSION = NO; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -3242,16 +3287,21 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -3268,6 +3318,10 @@
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
"CRASHLYTICS=1",
PEARL,
PEARL_COCOA,
PEARL_CRYPTO,
); );
GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@@ -3289,12 +3343,12 @@
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = NO; GCC_WARN_UNINITIALIZED_AUTOS = NO;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = NO; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
@@ -3315,6 +3369,7 @@
PUBLIC_HEADERS_FOLDER_PATH = include; PUBLIC_HEADERS_FOLDER_PATH = include;
SDKROOT = macosx; SDKROOT = macosx;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
}; };
name = Debug; name = Debug;
@@ -3324,10 +3379,15 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES; CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES; CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_WARN_BOOL_CONVERSION = NO; CLANG_STATIC_ANALYZER_MODE = deep;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
@@ -3335,16 +3395,21 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_RECEIVER_WEAK = NO; CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO; CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -3362,6 +3427,9 @@
"NDEBUG=1", "NDEBUG=1",
"NS_BLOCK_ASSERTIONS=1", "NS_BLOCK_ASSERTIONS=1",
"CRASHLYTICS=1", "CRASHLYTICS=1",
PEARL,
PEARL_COCOA,
PEARL_CRYPTO,
); );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
@@ -3382,12 +3450,12 @@
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES; GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = NO; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
@@ -3482,7 +3550,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"", "\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2", /usr/include/libxml2,
"$(inherited)", "$(inherited)",
); );
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
@@ -3502,7 +3570,7 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"", "\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
"/usr/include//libxml2", /usr/include/libxml2,
"$(inherited)", "$(inherited)",
); );
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
@@ -3621,7 +3689,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
@@ -3634,7 +3702,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch"; GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"", "\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0830" LastUpgradeVersion = "0920"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0830" LastUpgradeVersion = "0920"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0830" LastUpgradeVersion = "0920"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0830" LastUpgradeVersion = "0920"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@@ -26,6 +26,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@@ -45,6 +46,7 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "YES" useCustomWorkingDirectory = "YES"
customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c" customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c"

View File

@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MPGeneratedSiteEntity</key>
<dict>
<key>Login Name</key>
<array>
<string>cvccvcvcv</string>
</array>
<key>Phrase</key>
<array>
<string>cvcc cvc cvccvcv cvc</string>
<string>cvc cvccvcvcv cvcv</string>
<string>cv cvccv cvc cvcvccv</string>
</array>
<key>Maximum Security Password</key>
<array>
<string>anoxxxxxxxxxxxxxxxxx</string>
<string>axxxxxxxxxxxxxxxxxno</string>
</array>
<key>Long Password</key>
<array>
<string>CvcvnoCvcvCvcv</string>
<string>CvcvCvcvnoCvcv</string>
<string>CvcvCvcvCvcvno</string>
<string>CvccnoCvcvCvcv</string>
<string>CvccCvcvnoCvcv</string>
<string>CvccCvcvCvcvno</string>
<string>CvcvnoCvccCvcv</string>
<string>CvcvCvccnoCvcv</string>
<string>CvcvCvccCvcvno</string>
<string>CvcvnoCvcvCvcc</string>
<string>CvcvCvcvnoCvcc</string>
<string>CvcvCvcvCvccno</string>
<string>CvccnoCvccCvcv</string>
<string>CvccCvccnoCvcv</string>
<string>CvccCvccCvcvno</string>
<string>CvcvnoCvccCvcc</string>
<string>CvcvCvccnoCvcc</string>
<string>CvcvCvccCvccno</string>
<string>CvccnoCvcvCvcc</string>
<string>CvccCvcvnoCvcc</string>
<string>CvccCvcvCvccno</string>
</array>
<key>Medium Password</key>
<array>
<string>CvcnoCvc</string>
<string>CvcCvcno</string>
</array>
<key>Basic Password</key>
<array>
<string>aaanaaan</string>
<string>aannaaan</string>
<string>aaannaaa</string>
</array>
<key>Short Password</key>
<array>
<string>Cvcn</string>
</array>
<key>PIN</key>
<array>
<string>nnnn</string>
</array>
</dict>
<key>MPCharacterClasses</key>
<dict>
<key>V</key>
<string>AEIOU</string>
<key>C</key>
<string>BCDFGHJKLMNPQRSTVWXYZ</string>
<key>v</key>
<string>aeiou</string>
<key>c</key>
<string>bcdfghjklmnpqrstvwxyz</string>
<key>A</key>
<string>AEIOUBCDFGHJKLMNPQRSTVWXYZ</string>
<key>a</key>
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</string>
<key>n</key>
<string>0123456789</string>
<key>o</key>
<string>@&amp;%?,=[]_:-+*$#!'^~;()/.</string>
<key>x</key>
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&amp;*()</string>
<key> </key>
<string> </string>
</dict>
</dict>
</plist>

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
hash automake || { echo >&2 "Missing automake."; exit 1; }
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
cd "${BASH_SOURCE%/*}/../External/libjson-c" cd "${BASH_SOURCE%/*}/../External/libjson-c"
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit [[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
# Prepare # Prepare
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /' autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
rm -rf "${prefix=$PWD/libjson-c-ios}" rm -rf "${prefix=$PWD/libjson-c-ios}"
mkdir -p "$prefix/lib" \ mkdir -p "$prefix/lib" \
"${prefix_i386=$prefix/tmp/i386}" \ "${prefix_i386=$prefix/tmp/i386}" \
@@ -17,8 +22,8 @@ mkdir -p "$prefix/lib" \
# Targets # Targets
( (
## ARCH: i386 ## ARCH: i386
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)" SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH" 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 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 LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
@@ -28,8 +33,8 @@ mkdir -p "$prefix/lib" \
) )
( (
## ARCH: x86_64 ## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)" SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH" 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 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 LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
@@ -39,8 +44,8 @@ mkdir -p "$prefix/lib" \
) )
( (
## ARCH: armv7 ## ARCH: armv7
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
@@ -50,8 +55,8 @@ mkdir -p "$prefix/lib" \
) )
( (
## ARCH: armv7s ## ARCH: armv7s
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
@@ -61,8 +66,8 @@ mkdir -p "$prefix/lib" \
) )
( (
## ARCH: arm64 ## ARCH: arm64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"

View File

@@ -1,19 +1,24 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
hash automake || { echo >&2 "Missing automake."; exit 1; }
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
cd "${BASH_SOURCE%/*}/../External/libjson-c" cd "${BASH_SOURCE%/*}/../External/libjson-c"
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit [[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
# Prepare # Prepare
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /' autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
rm -rf "${prefix=$PWD/libjson-c-osx}" rm -rf "${prefix=$PWD/libjson-c-osx}"
mkdir -p "$prefix" mkdir -p "$prefix"
# Targets # Targets
( (
## ARCH: x86_64 ## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)" SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH" 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 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 LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"

View File

@@ -1,11 +1,16 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
hash automake || { echo >&2 "Missing automake."; exit 1; }
hash autoreconf || { echo >&2 "Missing autoconf."; exit 1; }
hash libtool || hash glibtool || { echo >&2 "Missing libtool."; exit 1; }
cd "${BASH_SOURCE%/*}/../External/libsodium" cd "${BASH_SOURCE%/*}/../External/libsodium"
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit [[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
# Prepare # Prepare
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /' autoreconf --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
rm -rf "${prefix=$PWD/libsodium-ios}" rm -rf "${prefix=$PWD/libsodium-ios}"
mkdir -p "$prefix/lib" \ mkdir -p "$prefix/lib" \
"${prefix_i386=$prefix/tmp/i386}" \ "${prefix_i386=$prefix/tmp/i386}" \
@@ -17,57 +22,57 @@ mkdir -p "$prefix/lib" \
# Targets # Targets
( (
## ARCH: i386 ## ARCH: i386
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)" SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH" 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 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 LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean [[ -e Makefile ]] && make -s distclean
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386" ./configure --host=i686-apple --disable-shared --enable-minimal --prefix="$prefix_i386"
make -j3 install make -j3 install
) )
( (
## ARCH: x86_64 ## ARCH: x86_64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)" SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH" 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 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 LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean [[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64" ./configure --host=x86_64-apple --disable-shared --enable-minimal --prefix="$prefix_x86_64"
make -j3 install make -j3 install
) )
( (
## ARCH: armv7 ## ARCH: armv7
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean [[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7" ./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7"
make -j3 install make -j3 install
) )
( (
## ARCH: armv7s ## ARCH: armv7s
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean [[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s" ./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7s"
make -j3 install make -j3 install
) )
( (
## ARCH: arm64 ## ARCH: arm64
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)" SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH" 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 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 LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS" export CPPFLAGS="$CFLAGS $CPPFLAGS"
[[ -e Makefile ]] && make -s distclean [[ -e Makefile ]] && make -s distclean
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64" ./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_arm64"
make -j3 install make -j3 install
) )

View File

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

View File

@@ -27,7 +27,7 @@
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock; + (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
+ (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock; + (BOOL)managedObjectContextPerformBlock:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
+ (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock; + (BOOL)managedObjectContextPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *context))mocBlock;
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock; - (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock;
- (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context; - (MPFixableResult)findAndFixInconsistenciesSaveInContext:(NSManagedObjectContext *)context;
- (void)deleteAndResetStore; - (void)deleteAndResetStore;

View File

@@ -17,7 +17,7 @@
//============================================================================== //==============================================================================
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "mpw-marshall.h" #import "mpw-marshal.h"
#import "mpw-util.h" #import "mpw-util.h"
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
@@ -133,12 +133,11 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
return YES; return YES;
} }
+ (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock { - (id)managedObjectContextChanged:(void ( ^ )(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects))changedBlock {
NSManagedObjectContext *privateManagedObjectContextIfReady = [[self get] privateManagedObjectContextIfReady]; NSManagedObjectContext *privateManagedObjectContextIfReady = [self privateManagedObjectContextIfReady];
if (!privateManagedObjectContextIfReady) if (!privateManagedObjectContextIfReady)
return nil; return nil;
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil, return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
^(id host, NSNotification *note) { ^(id host, NSNotification *note) {
NSMutableDictionary *affectedObjects = [NSMutableDictionary new]; NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
@@ -217,7 +216,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext; self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext;
if ([self.mainManagedObjectContext respondsToSelector:@selector( automaticallyMergesChangesFromParent )]) // iOS 10+ if (@available(iOS 10.0, macOS 10.12, *))
self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES; self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES;
else else
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext. // When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
@@ -566,10 +565,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
saveInContext:(NSManagedObjectContext *)context { saveInContext:(NSManagedObjectContext *)context {
// Read metadata for the import file. // Read metadata for the import file.
MPMarshallInfo *info = mpw_marshall_read_info( importData.UTF8String ); MPMarshalInfo *info = mpw_marshal_read_info( importData.UTF8String );
if (info->format == MPMarshallFormatNone) if (info->format == MPMarshalFormatNone)
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{ return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
@"type" : @(MPMarshallErrorFormat), @"type" : @(MPMarshalErrorFormat),
NSLocalizedDescriptionKey: @"This is not a Master Password import file.", NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
}]), @"While importing sites." ); }]), @"While importing sites." );
@@ -589,13 +588,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame); caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
// Parse import data. // Parse import data.
MPMarshallError importError = { .type = MPMarshallSuccess }; MPMarshalError importError = { .type = MPMarshalSuccess };
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError ); MPMarshalledUser *importUser = mpw_marshal_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
mpw_marshal_info_free( &info ); mpw_marshal_info_free( &info );
@try { @try {
if (!importUser || importError.type != MPMarshallSuccess) if (!importUser || importError.type != MPMarshalSuccess)
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{ return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
@"type" : @(importError.type), @"type" : @(importError.type),
NSLocalizedDescriptionKey: @(importError.description), NSLocalizedDescriptionKey: @(importError.description),
}]), @"While importing sites." ); }]), @"While importing sites." );
@@ -707,7 +706,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
NSString *masterPassword = askImportPassword( user.name ); NSString *masterPassword = askImportPassword( user.name );
inf( @"Exporting sites, %@, for user: %@", revealPasswords? @"revealing passwords": @"omitting passwords", user.userID ); 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 ); MPMarshalledUser *exportUser = mpw_marshal_user( user.name.UTF8String, masterPassword.UTF8String, user.algorithm.version );
exportUser->redacted = !revealPasswords; exportUser->redacted = !revealPasswords;
exportUser->avatar = (unsigned int)user.avatar; exportUser->avatar = (unsigned int)user.avatar;
exportUser->defaultType = user.defaultType; exportUser->defaultType = user.defaultType;
@@ -721,7 +720,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
? [site.algorithm exportPasswordForSite:site usingKey:self.key] ? [site.algorithm exportPasswordForSite:site usingKey:self.key]
: [site.algorithm resolvePasswordForSite:site usingKey:self.key]; : [site.algorithm resolvePasswordForSite:site usingKey:self.key];
MPMarshalledSite *exportSite = mpw_marshall_site( exportUser, MPMarshalledSite *exportSite = mpw_marshal_site( exportUser,
site.name.UTF8String, site.type, counter, site.algorithm.version ); site.name.UTF8String, site.type, counter, site.algorithm.version );
exportSite->content = content.UTF8String; exportSite->content = content.UTF8String;
exportSite->loginContent = site.loginName.UTF8String; exportSite->loginContent = site.loginName.UTF8String;
@@ -735,15 +734,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
} }
char *export = NULL; char *export = NULL;
MPMarshallError exportError = (MPMarshallError){ .type= MPMarshallSuccess }; MPMarshalError exportError = (MPMarshalError){ .type= MPMarshalSuccess };
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser, &exportError ); mpw_marshal_write( &export, MPMarshalFormatFlat, exportUser, &exportError );
NSString *mpsites = nil; NSString *mpsites = nil;
if (export && exportError.type == MPMarshallSuccess) if (export && exportError.type == MPMarshalSuccess)
mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding]; mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
mpw_free_string( &export ); mpw_free_string( &export );
resultBlock( mpsites, exportError.type == MPMarshallSuccess? nil: resultBlock( mpsites, exportError.type == MPMarshalSuccess? nil:
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{ [NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
@"type" : @(exportError.type), @"type" : @(exportError.type),
NSLocalizedDescriptionKey: @(exportError.description), NSLocalizedDescriptionKey: @(exportError.description),
}] ); }] );

View File

@@ -22,7 +22,7 @@
__BEGIN_DECLS __BEGIN_DECLS
extern NSString *const MPErrorDomain; extern NSString *const MPErrorDomain;
extern NSInteger const MPErrorHangCode; extern NSInteger const MPErrorHangCode;
extern NSInteger const MPErrorMarshallCode; extern NSInteger const MPErrorMarshalCode;
extern NSString *const MPSignedInNotification; extern NSString *const MPSignedInNotification;
extern NSString *const MPSignedOutNotification; extern NSString *const MPSignedOutNotification;

View File

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

View File

@@ -166,41 +166,66 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8; MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
@@ -231,17 +256,31 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
@@ -259,20 +298,30 @@
GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = NO;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8; MACOSX_DEPLOYMENT_TARGET = 10.8;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
@@ -292,41 +341,66 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_CXX0X_EXTENSIONS = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
COPY_PHASE_STRIP = YES; COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_NO_COMMON_BLOCKS = YES; GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
GCC_WARN_MISSING_PARENTHESES = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_SIGN_COMPARE = NO;
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNKNOWN_PRAGMAS = NO;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.8; MACOSX_DEPLOYMENT_TARGET = 10.8;
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";

View File

@@ -49,7 +49,7 @@
#import <objc/NSObjCRuntime.h> #import <objc/NSObjCRuntime.h>
#import <stdlib.h> #import <stdlib.h>
#define log(level, format, ...) \ #define mpw_log(level, format, ...) \
do { \ do { \
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \ void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
char *_msg = NULL; \ char *_msg = NULL; \
@@ -64,11 +64,11 @@
CFRelease( msgStr ); \ CFRelease( msgStr ); \
} while (0) } while (0)
#define trc(format, ...) log( 0, format, ##__VA_ARGS__ ); #define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );
#define dbg(format, ...) log( 1, format, ##__VA_ARGS__ ); #define dbg(format, ...) mpw_log( 1, format, ##__VA_ARGS__ );
#define inf(format, ...) log( 2, format, ##__VA_ARGS__ ); #define inf(format, ...) mpw_log( 2, format, ##__VA_ARGS__ );
#define wrn(format, ...) log( 3, format, ##__VA_ARGS__ ); #define wrn(format, ...) mpw_log( 3, format, ##__VA_ARGS__ );
#define err(format, ...) log( 4, format, ##__VA_ARGS__ ); #define err(format, ...) mpw_log( 4, format, ##__VA_ARGS__ );
#define ftl(format, ...) log( 5, format, ##__VA_ARGS__ ); #define ftl(format, ...) mpw_log( 5, format, ##__VA_ARGS__ );
#endif #endif

View File

@@ -1,25 +0,0 @@
//
// Prefix header for all source files of the 'Pearl' target in the 'Pearl' project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#define PEARL_WITH_MESSAGEUI
#define PEARL
#define PEARL_CRYPTO
#if TARGET_OS_IOS
#define PEARL_UIKIT
#elif TARGET_OS_OSX
#define PEARL_COCOA
#endif
#import "Pearl.h"
#import "Pearl-Crypto.h"
#if TARGET_OS_IOS
#import "Pearl-UIKit.h"
#elif TARGET_OS_OSX
#import "Pearl-Cocoa.h"
#endif
#endif

View File

@@ -225,7 +225,7 @@
- (void)copyAnswer:(NSString *)answer { - (void)copyAnswer:(NSString *)answer {
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
if ([pasteboard respondsToSelector:@selector( setItems:options: )]) { if (@available(iOS 10.0, *)) {
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ] [pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
options:@{ options:@{
UIPasteboardOptionLocalOnly : @NO, UIPasteboardOptionLocalOnly : @NO,

Some files were not shown because too many files have changed in this diff Show More