Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
344771dbdf | ||
|
|
d38dba7272 | ||
|
|
409f005eec | ||
|
|
df7903e146 | ||
|
|
49edaef79d | ||
|
|
fcbed9ef01 | ||
|
|
3edb414d23 | ||
|
|
d779c21cc1 | ||
|
|
8d32bc56ae | ||
|
|
9d03ed06c3 | ||
|
|
ee290e5c14 | ||
|
|
789761b177 | ||
|
|
cd0876d58a | ||
|
|
bfae4da56c | ||
|
|
f342ed5940 | ||
|
|
c7373fee28 | ||
|
|
44b2955652 | ||
|
|
8a4af69008 | ||
|
|
6650382e19 | ||
|
|
a1f5e0ba1c | ||
|
|
035bb6b285 | ||
|
|
c0107fb90e | ||
|
|
138be9d14c | ||
|
|
61f474217b | ||
|
|
d31c5eed0a | ||
|
|
5060de689b | ||
|
|
b95424ddf3 | ||
|
|
e40a442a30 | ||
|
|
b5134a9faf | ||
|
|
a791d449ce | ||
|
|
43e1a9d539 | ||
|
|
e91f80d10e | ||
|
|
9db855c7fb | ||
|
|
2dc3636b26 | ||
|
|
4d9df012f6 | ||
|
|
ff9d0d75ef | ||
|
|
4e160b3b33 | ||
|
|
5048acc9f9 | ||
|
|
1841541bc4 | ||
|
|
11d9af3844 | ||
|
|
e30b618241 | ||
|
|
966327571d | ||
|
|
303d50c197 | ||
|
|
bcdfdec211 | ||
|
|
fb769d2ac5 | ||
|
|
f8043ae16d | ||
|
|
7150f2f5c5 | ||
|
|
81bd2e3065 | ||
|
|
78c9618807 | ||
|
|
bed8939b8a | ||
|
|
9443d93500 | ||
|
|
877eba66be | ||
|
|
3af8aba40c | ||
|
|
7ece02c73d | ||
|
|
ebbd2b3ac4 | ||
|
|
a85eff4277 | ||
|
|
98f1c776be | ||
|
|
6b554c67ed | ||
|
|
f2ae35080d | ||
|
|
0ff6c93a95 | ||
|
|
9147600b97 | ||
|
|
fafe56166e | ||
|
|
0a024b2594 | ||
|
|
b4c2a393f1 | ||
|
|
39dcef46d2 | ||
|
|
d6a88583f5 | ||
|
|
1c17b84dcf | ||
|
|
cecaf1b5cc | ||
|
|
888338e107 | ||
|
|
32055abf29 | ||
|
|
0f72dffaf1 | ||
|
|
5d1be43b65 | ||
|
|
dc7089c38c | ||
|
|
34540f0844 | ||
|
|
e818713484 | ||
|
|
6e2289994c | ||
|
|
05a9ba46d0 | ||
|
|
70bb30ba0c | ||
|
|
444d7e9b35 | ||
|
|
47164c7a92 | ||
|
|
ad00ceb4ce | ||
|
|
473e3ca11f | ||
|
|
35c0431cec | ||
|
|
70c784db83 | ||
|
|
d448099a2d | ||
|
|
e3a7ea57e0 | ||
|
|
fa6133200e | ||
|
|
dfa67bdca9 | ||
|
|
8c9c4ef7b2 | ||
|
|
1adb18a7e7 | ||
|
|
f50fdb7777 | ||
|
|
33bf2c93d0 | ||
|
|
f2abcc9e43 | ||
|
|
5ef69aa045 | ||
|
|
1c0f274868 | ||
|
|
1f592f50a9 | ||
|
|
30fdb54e94 | ||
|
|
4f552be5a9 | ||
|
|
1439df9f9a | ||
|
|
e676a0e258 |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -25,3 +25,9 @@
|
||||
[submodule "platform-darwin/External/libjson-c"]
|
||||
path = platform-darwin/External/libjson-c
|
||||
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
|
||||
|
||||
12
.travis.yml
12
.travis.yml
@@ -1,10 +1,20 @@
|
||||
language: objective-c
|
||||
osx_image: xcode8.3
|
||||
os: osx
|
||||
osx_image: xcode9.2
|
||||
env: TERM=dumb SHLVL=0
|
||||
git:
|
||||
submodules: true
|
||||
script:
|
||||
- "( brew install libsodium json-c )"
|
||||
- "( 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 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
606
core/c/aes.c
Normal 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
50
core/c/aes.h
Normal 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_
|
||||
@@ -29,9 +29,9 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
|
||||
if (masterPassword && !strlen( masterPassword ))
|
||||
masterPassword = NULL;
|
||||
|
||||
trc( "-- mpw_masterKey (algorithm: %u)\n", algorithmVersion );
|
||||
trc( "fullName: %s\n", fullName );
|
||||
trc( "masterPassword.id: %s\n", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
|
||||
trc( "-- mpw_masterKey (algorithm: %u)", algorithmVersion );
|
||||
trc( "fullName: %s", fullName );
|
||||
trc( "masterPassword.id: %s", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL );
|
||||
if (!fullName || !masterPassword)
|
||||
return NULL;
|
||||
|
||||
@@ -45,7 +45,7 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_masterKey_v3( fullName, masterPassword );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -54,16 +54,14 @@ MPSiteKey mpw_siteKey(
|
||||
MPMasterKey masterKey, const char *siteName, const MPCounterValue siteCounter,
|
||||
const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
|
||||
|
||||
if (siteName && !strlen( siteName ))
|
||||
siteName = NULL;
|
||||
if (keyContext && !strlen( keyContext ))
|
||||
keyContext = NULL;
|
||||
|
||||
trc( "-- mpw_siteKey (algorithm: %u)\n", algorithmVersion );
|
||||
trc( "siteName: %s\n", siteName );
|
||||
trc( "siteCounter: %d\n", siteCounter );
|
||||
trc( "keyPurpose: %d (%s)\n", keyPurpose, mpw_nameForPurpose( keyPurpose ) );
|
||||
trc( "keyContext: %s\n", keyContext );
|
||||
trc( "-- mpw_siteKey (algorithm: %u)", algorithmVersion );
|
||||
trc( "siteName: %s", siteName );
|
||||
trc( "siteCounter: %d", siteCounter );
|
||||
trc( "keyPurpose: %d (%s)", keyPurpose, mpw_nameForPurpose( keyPurpose ) );
|
||||
trc( "keyContext: %s", keyContext );
|
||||
if (!masterKey || !siteName)
|
||||
return NULL;
|
||||
|
||||
@@ -77,7 +75,7 @@ MPSiteKey mpw_siteKey(
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -88,8 +86,6 @@ const char *mpw_siteResult(
|
||||
const MPResultType resultType, const char *resultParam,
|
||||
const MPAlgorithmVersion algorithmVersion) {
|
||||
|
||||
if (siteName && !strlen( siteName ))
|
||||
siteName = NULL;
|
||||
if (keyContext && !strlen( keyContext ))
|
||||
keyContext = NULL;
|
||||
if (resultParam && !strlen( resultParam ))
|
||||
@@ -99,9 +95,9 @@ const char *mpw_siteResult(
|
||||
if (!siteKey)
|
||||
return NULL;
|
||||
|
||||
trc( "-- mpw_siteResult (algorithm: %u)\n", algorithmVersion );
|
||||
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
||||
trc( "resultParam: %s\n", resultParam );
|
||||
trc( "-- mpw_siteResult (algorithm: %u)", algorithmVersion );
|
||||
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
|
||||
trc( "resultParam: %s", resultParam );
|
||||
|
||||
char *sitePassword = NULL;
|
||||
if (resultType & MPResultTypeClassTemplate) {
|
||||
@@ -115,7 +111,7 @@ const char *mpw_siteResult(
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_sitePasswordFromTemplate_v3( masterKey, siteKey, resultType, resultParam );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +126,7 @@ const char *mpw_siteResult(
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_sitePasswordFromCrypt_v3( masterKey, siteKey, resultType, resultParam );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -145,12 +141,12 @@ const char *mpw_siteResult(
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_sitePasswordFromDerive_v3( masterKey, siteKey, resultType, resultParam );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
err( "Unsupported password type: %d\n", resultType );
|
||||
err( "Unsupported password type: %d", resultType );
|
||||
}
|
||||
|
||||
return sitePassword;
|
||||
@@ -162,20 +158,18 @@ const char *mpw_siteState(
|
||||
const MPResultType resultType, const char *resultParam,
|
||||
const MPAlgorithmVersion algorithmVersion) {
|
||||
|
||||
if (siteName && !strlen( siteName ))
|
||||
siteName = NULL;
|
||||
if (keyContext && !strlen( keyContext ))
|
||||
keyContext = NULL;
|
||||
if (resultParam && !strlen( resultParam ))
|
||||
resultParam = NULL;
|
||||
|
||||
MPSiteKey siteKey = mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||
MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
||||
if (!siteKey)
|
||||
return NULL;
|
||||
|
||||
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
|
||||
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
||||
trc( "resultParam: %s\n", resultParam );
|
||||
trc( "-- mpw_siteState (algorithm: %u)", algorithmVersion );
|
||||
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
|
||||
trc( "resultParam: %zu bytes = %s", sizeof( resultParam ), resultParam );
|
||||
if (!masterKey || !resultParam)
|
||||
return NULL;
|
||||
|
||||
@@ -189,7 +183,44 @@ const char *mpw_siteState(
|
||||
case MPAlgorithmVersion3:
|
||||
return mpw_siteState_v3( masterKey, siteKey, resultType, resultParam );
|
||||
default:
|
||||
err( "Unsupported version: %d\n", algorithmVersion );
|
||||
err( "Unsupported version: %d", algorithmVersion );
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -66,4 +66,7 @@ const char *mpw_siteState(
|
||||
const MPResultType resultType, const char *resultParam,
|
||||
const MPAlgorithmVersion algorithmVersion);
|
||||
|
||||
/** @return A fingerprint for a user. */
|
||||
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword);
|
||||
|
||||
#endif // _MPW_ALGORITHM_H
|
||||
|
||||
@@ -52,10 +52,10 @@ static MPMasterKey mpw_masterKey_v0(
|
||||
const char *fullName, const char *masterPassword) {
|
||||
|
||||
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
||||
trc( "keyScope: %s\n", keyScope );
|
||||
trc( "keyScope: %s", keyScope );
|
||||
|
||||
// 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 );
|
||||
size_t masterKeySaltSize = 0;
|
||||
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_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
||||
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;
|
||||
}
|
||||
trc( " => masterKeySalt.id: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
||||
trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
|
||||
|
||||
// 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 );
|
||||
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||
if (!masterKey) {
|
||||
err( "Could not derive master key: %s\n", strerror( errno ) );
|
||||
err( "Could not derive master key: %s", strerror( errno ) );
|
||||
return NULL;
|
||||
}
|
||||
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||
trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
@@ -86,14 +86,14 @@ static MPSiteKey mpw_siteKey_v0(
|
||||
MPKeyPurpose keyPurpose, const char *keyContext) {
|
||||
|
||||
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
||||
trc( "keyScope: %s\n", keyScope );
|
||||
trc( "keyScope: %s", keyScope );
|
||||
|
||||
// OTP counter value.
|
||||
if (siteCounter == MPCounterValueTOTP)
|
||||
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
||||
|
||||
// Calculate the site seed.
|
||||
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
|
||||
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 ),
|
||||
keyContext? mpw_hex_l( (uint32_t)mpw_utf8_strlen( keyContext ) ): NULL, keyContext );
|
||||
size_t siteSaltSize = 0;
|
||||
@@ -107,20 +107,20 @@ static MPSiteKey mpw_siteKey_v0(
|
||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||
}
|
||||
if (!siteSalt) {
|
||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
||||
err( "Could not allocate site salt: %s", strerror( errno ) );
|
||||
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 ) );
|
||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||
mpw_free( &siteSalt, siteSaltSize );
|
||||
if (!siteKey) {
|
||||
err( "Could not derive site key: %s\n", strerror( errno ) );
|
||||
err( "Could not derive site key: %s", strerror( errno ) );
|
||||
return NULL;
|
||||
}
|
||||
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||
trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||
|
||||
return siteKey;
|
||||
}
|
||||
@@ -134,11 +134,11 @@ static const char *mpw_sitePasswordFromTemplate_v0(
|
||||
uint16_t seedByte;
|
||||
mpw_uint16( (uint16_t)_siteKey[0], (uint8_t *)&seedByte );
|
||||
const char *template = mpw_templateForType_v0( resultType, seedByte );
|
||||
trc( "template: %u => %s\n", seedByte, template );
|
||||
trc( "template: %u => %s", seedByte, template );
|
||||
if (!template)
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -147,10 +147,10 @@ static const char *mpw_sitePasswordFromTemplate_v0(
|
||||
for (size_t c = 0; c < strlen( template ); ++c) {
|
||||
mpw_uint16( (uint16_t)_siteKey[c + 1], (uint8_t *)&seedByte );
|
||||
sitePassword[c] = mpw_characterFromClass_v0( template[c], seedByte );
|
||||
trc( " - class: %c, index: %5u (0x%02hX) => character: %c\n",
|
||||
trc( " - class: %c, index: %5u (0x%02hX) => character: %c",
|
||||
template[c], seedByte, seedByte, sitePassword[c] );
|
||||
}
|
||||
trc( " => password: %s\n", sitePassword );
|
||||
trc( " => password: %s", sitePassword );
|
||||
|
||||
return sitePassword;
|
||||
}
|
||||
@@ -159,28 +159,28 @@ static const char *mpw_sitePasswordFromCrypt_v0(
|
||||
MPMasterKey masterKey, MPSiteKey __unused siteKey, MPResultType __unused resultType, const char *cipherText) {
|
||||
|
||||
if (!cipherText) {
|
||||
err( "Missing encrypted state.\n" );
|
||||
err( "Missing encrypted state." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Base64-decode
|
||||
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) {
|
||||
err( "Base64 decoding error." );
|
||||
mpw_free( &cipherBuf, mpw_base64_decode_max( cipherText ) );
|
||||
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
|
||||
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, bufSize );
|
||||
mpw_free( &cipherBuf, bufSize );
|
||||
const char *plainText = strndup( (char *)plainBytes, bufSize );
|
||||
const uint8_t *plainBytes = mpw_aes_decrypt( masterKey, MPMasterKeySize, cipherBuf, &bufSize );
|
||||
mpw_free( &cipherBuf, cipherBufSize );
|
||||
const char *plainText = mpw_strndup( (char *)plainBytes, bufSize );
|
||||
mpw_free( &plainBytes, bufSize );
|
||||
if (!plainText)
|
||||
err( "AES decryption error: %s\n", strerror( errno ) );
|
||||
trc( "decrypted -> plainText: %s = %s\n", plainText, mpw_hex( plainText, sizeof( plainText ) ) );
|
||||
err( "AES decryption error: %s", strerror( errno ) );
|
||||
trc( "decrypted -> plainText: %zu bytes = %s = %s", strlen( plainText ), plainText, mpw_hex( plainText, strlen( plainText ) ) );
|
||||
|
||||
return plainText;
|
||||
}
|
||||
@@ -191,21 +191,23 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
||||
switch (resultType) {
|
||||
case MPResultTypeDeriveKey: {
|
||||
if (!resultParam) {
|
||||
err( "Missing key size parameter.\n" );
|
||||
err( "Missing key size parameter." );
|
||||
return NULL;
|
||||
}
|
||||
int resultParamInt = atoi( resultParam );
|
||||
if (!resultParamInt)
|
||||
resultParamInt = 512;
|
||||
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;
|
||||
}
|
||||
uint16_t keySize = (uint16_t)(resultParamInt / 8);
|
||||
trc( "keySize: %u\n", keySize );
|
||||
trc( "keySize: %u", keySize );
|
||||
|
||||
// Derive key
|
||||
const uint8_t *resultKey = mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
||||
if (!resultKey) {
|
||||
err( "Could not derive result key: %s\n", strerror( errno ) );
|
||||
err( "Could not derive result key: %s", strerror( errno ) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -217,13 +219,13 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
||||
mpw_free_string( &b64Key );
|
||||
}
|
||||
else
|
||||
trc( "b64 encoded -> key.id: %s\n", mpw_id_buf( b64Key, strlen( b64Key ) ) );
|
||||
trc( "b64 encoded -> key: %s", b64Key );
|
||||
mpw_free( &resultKey, keySize );
|
||||
|
||||
return b64Key;
|
||||
}
|
||||
default:
|
||||
err( "Unsupported derived password type: %d\n", resultType );
|
||||
err( "Unsupported derived password type: %d", resultType );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -233,12 +235,12 @@ static const char *mpw_siteState_v0(
|
||||
|
||||
// Encrypt
|
||||
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) {
|
||||
err( "AES encryption error: %s\n", strerror( errno ) );
|
||||
err( "AES encryption error: %s", strerror( errno ) );
|
||||
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
|
||||
size_t b64Max = mpw_base64_encode_max( bufSize );
|
||||
@@ -248,7 +250,7 @@ static const char *mpw_siteState_v0(
|
||||
mpw_free_string( &cipherText );
|
||||
}
|
||||
else
|
||||
trc( "b64 encoded -> cipherText: %s = %s\n", cipherText, mpw_hex( cipherText, sizeof( cipherText ) ) );
|
||||
trc( "b64 encoded -> cipherText: %s", cipherText );
|
||||
mpw_free( &cipherBuf, bufSize );
|
||||
|
||||
return cipherText;
|
||||
|
||||
@@ -58,11 +58,11 @@ static const char *mpw_sitePasswordFromTemplate_v1(
|
||||
// Determine the template.
|
||||
uint8_t seedByte = siteKey[0];
|
||||
const char *template = mpw_templateForType( resultType, seedByte );
|
||||
trc( "template: %u => %s\n", seedByte, template );
|
||||
trc( "template: %u => %s", seedByte, template );
|
||||
if (!template)
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -71,10 +71,10 @@ static const char *mpw_sitePasswordFromTemplate_v1(
|
||||
for (size_t c = 0; c < strlen( template ); ++c) {
|
||||
seedByte = siteKey[c + 1];
|
||||
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] );
|
||||
}
|
||||
trc( " => password: %s\n", sitePassword );
|
||||
trc( " => password: %s", sitePassword );
|
||||
|
||||
return sitePassword;
|
||||
}
|
||||
|
||||
@@ -51,14 +51,14 @@ static MPSiteKey mpw_siteKey_v2(
|
||||
MPKeyPurpose keyPurpose, const char *keyContext) {
|
||||
|
||||
const char *keyScope = mpw_scopeForPurpose( keyPurpose );
|
||||
trc( "keyScope: %s\n", keyScope );
|
||||
trc( "keyScope: %s", keyScope );
|
||||
|
||||
// OTP counter value.
|
||||
if (siteCounter == MPCounterValueTOTP)
|
||||
siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window;
|
||||
|
||||
// Calculate the site seed.
|
||||
trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s\n",
|
||||
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 ),
|
||||
keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext );
|
||||
size_t siteSaltSize = 0;
|
||||
@@ -72,20 +72,20 @@ static MPSiteKey mpw_siteKey_v2(
|
||||
mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
|
||||
}
|
||||
if (!siteSalt) {
|
||||
err( "Could not allocate site salt: %s\n", strerror( errno ) );
|
||||
err( "Could not allocate site salt: %s", strerror( errno ) );
|
||||
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 ) );
|
||||
MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
|
||||
mpw_free( &siteSalt, siteSaltSize );
|
||||
if (!siteKey) {
|
||||
err( "Could not derive site key: %s\n", strerror( errno ) );
|
||||
err( "Could not derive site key: %s", strerror( errno ) );
|
||||
return NULL;
|
||||
}
|
||||
trc( " => siteKey.id: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||
trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) );
|
||||
|
||||
return siteKey;
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ static MPMasterKey mpw_masterKey_v3(
|
||||
const char *fullName, const char *masterPassword) {
|
||||
|
||||
const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
|
||||
trc( "keyScope: %s\n", keyScope );
|
||||
trc( "keyScope: %s", keyScope );
|
||||
|
||||
// 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 );
|
||||
size_t masterKeySaltSize = 0;
|
||||
uint8_t *masterKeySalt = NULL;
|
||||
@@ -55,20 +55,20 @@ static MPMasterKey mpw_masterKey_v3(
|
||||
mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) );
|
||||
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
|
||||
if (!masterKeySalt) {
|
||||
err( "Could not allocate master key salt: %s\n", strerror( errno ) );
|
||||
err( "Could not allocate master key salt: %s", strerror( errno ) );
|
||||
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.
|
||||
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 );
|
||||
mpw_free( &masterKeySalt, masterKeySaltSize );
|
||||
if (!masterKey) {
|
||||
err( "Could not derive master key: %s\n", strerror( errno ) );
|
||||
err( "Could not derive master key: %s", strerror( errno ) );
|
||||
return NULL;
|
||||
}
|
||||
trc( " => masterKey.id: %s\n", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||
trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mpw-marshall-util.h"
|
||||
#include "mpw-marshal-util.h"
|
||||
#include "mpw-util.h"
|
||||
|
||||
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.
|
||||
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.
|
||||
*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(
|
||||
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",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&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 *json_value = obj;
|
||||
char *sectionTokenizer = strdup( section ), *sectionToken = sectionTokenizer;
|
||||
char *sectionTokenizer = mpw_strdup( section ), *sectionToken = sectionTokenizer;
|
||||
for (sectionToken = strtok( sectionToken, "." ); sectionToken; sectionToken = strtok( NULL, "." ))
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ bool mpw_update_masterKey(MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyA
|
||||
*masterKeyAlgorithm = targetKeyAlgorithm;
|
||||
*masterKey = mpw_masterKey( fullName, masterPassword, *masterKeyAlgorithm );
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,13 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _MPW_MARSHALL_UTIL_H
|
||||
#define _MPW_MARSHALL_UTIL_H
|
||||
#ifndef _MPW_MARSHAL_UTIL_H
|
||||
#define _MPW_MARSHAL_UTIL_H
|
||||
|
||||
#include <time.h>
|
||||
#if MPW_JSON
|
||||
#include "json-c/json.h"
|
||||
#endif
|
||||
|
||||
#include "mpw-algorithm.h"
|
||||
|
||||
@@ -37,6 +39,7 @@ time_t mpw_mktime(
|
||||
|
||||
/// JSON parsing.
|
||||
|
||||
#if MPW_JSON
|
||||
/** 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.
|
||||
* @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. */
|
||||
bool mpw_get_json_boolean(
|
||||
json_object *obj, const char *section, bool defaultValue);
|
||||
#endif
|
||||
|
||||
/// mpw.
|
||||
|
||||
@@ -66,4 +70,4 @@ bool mpw_update_masterKey(
|
||||
MPMasterKey *masterKey, MPAlgorithmVersion *masterKeyAlgorithm, MPAlgorithmVersion targetKeyAlgorithm,
|
||||
const char *fullName, const char *masterPassword);
|
||||
|
||||
#endif // _MPW_MARSHALL_UTIL_H
|
||||
#endif // _MPW_MARSHAL_UTIL_H
|
||||
@@ -21,11 +21,11 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mpw-marshall.h"
|
||||
#include "mpw-marshal.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) {
|
||||
|
||||
MPMarshalledUser *user;
|
||||
@@ -33,8 +33,8 @@ MPMarshalledUser *mpw_marshall_user(
|
||||
return NULL;
|
||||
|
||||
*user = (MPMarshalledUser){
|
||||
.fullName = strdup( fullName ),
|
||||
.masterPassword = strdup( masterPassword ),
|
||||
.fullName = mpw_strdup( fullName ),
|
||||
.masterPassword = mpw_strdup( masterPassword ),
|
||||
.algorithm = algorithmVersion,
|
||||
.redacted = true,
|
||||
|
||||
@@ -46,9 +46,9 @@ MPMarshalledUser *mpw_marshall_user(
|
||||
.sites = NULL,
|
||||
};
|
||||
return user;
|
||||
};
|
||||
}
|
||||
|
||||
MPMarshalledSite *mpw_marshall_site(
|
||||
MPMarshalledSite *mpw_marshal_site(
|
||||
MPMarshalledUser *user, const char *siteName, const MPResultType resultType,
|
||||
const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion) {
|
||||
|
||||
@@ -57,7 +57,7 @@ MPMarshalledSite *mpw_marshall_site(
|
||||
|
||||
MPMarshalledSite *site = &user->sites[user->sites_count - 1];
|
||||
*site = (MPMarshalledSite){
|
||||
.name = strdup( siteName ),
|
||||
.name = mpw_strdup( siteName ),
|
||||
.content = NULL,
|
||||
.type = resultType,
|
||||
.counter = siteCounter,
|
||||
@@ -74,7 +74,7 @@ MPMarshalledSite *mpw_marshall_site(
|
||||
.questions = NULL,
|
||||
};
|
||||
return site;
|
||||
};
|
||||
}
|
||||
|
||||
MPMarshalledQuestion *mpw_marshal_question(
|
||||
MPMarshalledSite *site, const char *keyword) {
|
||||
@@ -86,7 +86,7 @@ MPMarshalledQuestion *mpw_marshal_question(
|
||||
|
||||
MPMarshalledQuestion *question = &site->questions[site->questions_count - 1];
|
||||
*question = (MPMarshalledQuestion){
|
||||
.keyword = strdup( keyword ),
|
||||
.keyword = mpw_strdup( keyword ),
|
||||
.content = NULL,
|
||||
.type = MPResultTypeTemplatePhrase,
|
||||
};
|
||||
@@ -94,14 +94,14 @@ MPMarshalledQuestion *mpw_marshal_question(
|
||||
}
|
||||
|
||||
bool mpw_marshal_info_free(
|
||||
MPMarshallInfo **info) {
|
||||
MPMarshalInfo **info) {
|
||||
|
||||
if (!info || !*info)
|
||||
return true;
|
||||
|
||||
bool success = true;
|
||||
success &= mpw_free_strings( &(*info)->fullName, &(*info)->keyID, NULL );
|
||||
success &= mpw_free( info, sizeof( MPMarshallInfo ) );
|
||||
success &= mpw_free( info, sizeof( MPMarshalInfo ) );
|
||||
|
||||
return success;
|
||||
}
|
||||
@@ -132,22 +132,22 @@ bool mpw_marshal_free(
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool mpw_marshall_write_flat(
|
||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
||||
static bool mpw_marshal_write_flat(
|
||||
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 )) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||
return false;
|
||||
}
|
||||
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
|
||||
return false;
|
||||
}
|
||||
MPMasterKey masterKey = NULL;
|
||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ static bool mpw_marshall_write_flat(
|
||||
if (!user->redacted) {
|
||||
// Clear Text
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -198,9 +198,9 @@ static bool mpw_marshall_write_flat(
|
||||
else {
|
||||
// Redacted
|
||||
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 ))
|
||||
loginContent = strdup( site->loginContent );
|
||||
loginContent = mpw_strdup( site->loginContent );
|
||||
}
|
||||
|
||||
if (strftime( dateString, sizeof( dateString ), "%FT%TZ", gmtime( &site->lastUsed ) ))
|
||||
@@ -211,27 +211,27 @@ static bool mpw_marshall_write_flat(
|
||||
}
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return true;
|
||||
}
|
||||
|
||||
#if MPW_JSON
|
||||
static bool mpw_marshall_write_json(
|
||||
char **out, const MPMarshalledUser *user, MPMarshallError *error) {
|
||||
static bool mpw_marshal_write_json(
|
||||
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 )) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing full name." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing full name." };
|
||||
return false;
|
||||
}
|
||||
if (!user->masterPassword || !strlen( user->masterPassword )) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMasterPassword, "Missing master password." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMasterPassword, "Missing master password." };
|
||||
return false;
|
||||
}
|
||||
MPMasterKey masterKey = NULL;
|
||||
MPAlgorithmVersion masterKeyAlgorithm = user->algorithm - 1;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ static bool mpw_marshall_write_json(
|
||||
if (!user->redacted) {
|
||||
// Clear Text
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -284,9 +284,9 @@ static bool mpw_marshall_write_json(
|
||||
else {
|
||||
// Redacted
|
||||
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 ))
|
||||
loginContent = strdup( site->loginContent );
|
||||
loginContent = mpw_strdup( site->loginContent );
|
||||
}
|
||||
|
||||
json_object *json_site = json_object_new_object();
|
||||
@@ -340,32 +340,32 @@ static bool mpw_marshall_write_json(
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
json_object_put( json_file );
|
||||
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool mpw_marshall_write(
|
||||
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error) {
|
||||
bool mpw_marshal_write(
|
||||
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error) {
|
||||
|
||||
switch (outFormat) {
|
||||
case MPMarshallFormatNone:
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
case MPMarshalFormatNone:
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return false;
|
||||
case MPMarshallFormatFlat:
|
||||
return mpw_marshall_write_flat( out, user, error );
|
||||
case MPMarshalFormatFlat:
|
||||
return mpw_marshal_write_flat( out, user, error );
|
||||
#if MPW_JSON
|
||||
case MPMarshallFormatJSON:
|
||||
return mpw_marshall_write_json( out, user, error );
|
||||
case MPMarshalFormatJSON:
|
||||
return mpw_marshal_write_json( out, user, error );
|
||||
#endif
|
||||
default:
|
||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported output format: %u", outFormat ) };
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void mpw_marshall_read_flat_info(
|
||||
const char *in, MPMarshallInfo *info) {
|
||||
static void mpw_marshal_read_flat_info(
|
||||
const char *in, MPMarshalInfo *info) {
|
||||
|
||||
info->algorithm = MPAlgorithmVersionCurrent;
|
||||
|
||||
@@ -397,9 +397,9 @@ static void mpw_marshall_read_flat_info(
|
||||
if (strcmp( headerName, "Algorithm" ) == 0)
|
||||
info->algorithm = (MPAlgorithmVersion)atoi( headerValue );
|
||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||
info->fullName = strdup( headerValue );
|
||||
info->fullName = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Key ID" ) == 0)
|
||||
info->keyID = strdup( headerValue );
|
||||
info->keyID = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Passwords" ) == 0)
|
||||
info->redacted = strcmp( headerValue, "VISIBLE" ) != 0;
|
||||
if (strcmp( headerName, "Date" ) == 0)
|
||||
@@ -411,12 +411,12 @@ static void mpw_marshall_read_flat_info(
|
||||
}
|
||||
}
|
||||
|
||||
static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
const char *in, const char *masterPassword, MPMarshallError *error) {
|
||||
static MPMarshalledUser *mpw_marshal_read_flat(
|
||||
const char *in, const char *masterPassword, MPMarshalError *error) {
|
||||
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||
if (!in || !strlen( in )) {
|
||||
error->type = MPMarshallErrorStructure;
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "No input data." );
|
||||
return NULL;
|
||||
}
|
||||
@@ -455,23 +455,23 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
char *headerName = mpw_get_token( &positionInLine, endOfLine, ":\n" );
|
||||
char *headerValue = mpw_get_token( &positionInLine, endOfLine, "\n" );
|
||||
if (!headerName || !headerValue) {
|
||||
error->type = MPMarshallErrorStructure;
|
||||
error->description = mpw_str( "Invalid header: %s", strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "Invalid header: %s", mpw_strndup( positionInLine, (size_t)(endOfLine - positionInLine) ) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp( headerName, "Format" ) == 0)
|
||||
format = (unsigned int)atoi( headerValue );
|
||||
if (strcmp( headerName, "Full Name" ) == 0 || strcmp( headerName, "User Name" ) == 0)
|
||||
fullName = strdup( headerValue );
|
||||
fullName = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Avatar" ) == 0)
|
||||
avatar = (unsigned int)atoi( headerValue );
|
||||
if (strcmp( headerName, "Key ID" ) == 0)
|
||||
keyID = strdup( headerValue );
|
||||
keyID = mpw_strdup( headerValue );
|
||||
if (strcmp( headerName, "Algorithm" ) == 0) {
|
||||
int value = atoi( headerValue );
|
||||
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;
|
||||
}
|
||||
algorithm = (MPAlgorithmVersion)value;
|
||||
@@ -479,7 +479,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
if (strcmp( headerName, "Default Type" ) == 0) {
|
||||
int value = atoi( headerValue );
|
||||
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;
|
||||
}
|
||||
defaultType = (MPResultType)value;
|
||||
@@ -493,7 +493,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
if (!headerEnded)
|
||||
continue;
|
||||
if (!fullName) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing header: Full Name" };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing header: Full Name" };
|
||||
return NULL;
|
||||
}
|
||||
if (positionInLine >= endOfLine)
|
||||
@@ -501,15 +501,15 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
|
||||
if (!user) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." };
|
||||
if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -527,11 +527,11 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
str_uses = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
char *typeAndVersion = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
if (typeAndVersion) {
|
||||
str_type = strdup( strtok( typeAndVersion, ":" ) );
|
||||
str_algorithm = strdup( strtok( NULL, "" ) );
|
||||
str_type = mpw_strdup( strtok( typeAndVersion, ":" ) );
|
||||
str_algorithm = mpw_strdup( strtok( NULL, "" ) );
|
||||
mpw_free_string( &typeAndVersion );
|
||||
}
|
||||
str_counter = strdup( "1" );
|
||||
str_counter = mpw_strdup( "1" );
|
||||
siteLoginName = NULL;
|
||||
siteName = mpw_get_token( &positionInLine, endOfLine, "\t\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" );
|
||||
char *typeAndVersionAndCounter = mpw_get_token( &positionInLine, endOfLine, " \t\n" );
|
||||
if (typeAndVersionAndCounter) {
|
||||
str_type = strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||
str_algorithm = strdup( strtok( NULL, ":" ) );
|
||||
str_counter = strdup( strtok( NULL, "" ) );
|
||||
str_type = mpw_strdup( strtok( typeAndVersionAndCounter, ":" ) );
|
||||
str_algorithm = mpw_strdup( strtok( NULL, ":" ) );
|
||||
str_counter = mpw_strdup( strtok( NULL, "" ) );
|
||||
mpw_free_string( &typeAndVersionAndCounter );
|
||||
}
|
||||
siteLoginName = mpw_get_token( &positionInLine, endOfLine, "\t\n" );
|
||||
@@ -553,7 +553,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unexpected import format: %u", format ) };
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -561,31 +561,31 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
|
||||
MPResultType siteType = (MPResultType)atoi( str_type );
|
||||
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;
|
||||
}
|
||||
long long int value = atoll( str_counter );
|
||||
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;
|
||||
}
|
||||
MPCounterValue siteCounter = (MPCounterValue)value;
|
||||
value = atoll( str_algorithm );
|
||||
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;
|
||||
}
|
||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
||||
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;
|
||||
}
|
||||
|
||||
MPMarshalledSite *site = mpw_marshall_site(
|
||||
MPMarshalledSite *site = mpw_marshal_site(
|
||||
user, siteName, siteType, siteCounter, siteAlgorithm );
|
||||
if (!site) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -594,7 +594,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
if (!user->redacted) {
|
||||
// Clear Text
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -608,13 +608,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
else {
|
||||
// Redacted
|
||||
if (siteContent && strlen( siteContent ))
|
||||
site->content = strdup( siteContent );
|
||||
site->content = mpw_strdup( siteContent );
|
||||
if (siteLoginName && strlen( siteLoginName ))
|
||||
site->loginContent = strdup( siteLoginName );
|
||||
site->loginContent = mpw_strdup( siteLoginName );
|
||||
}
|
||||
}
|
||||
else {
|
||||
error->type = MPMarshallErrorMissing;
|
||||
error->type = MPMarshalErrorMissing;
|
||||
error->description = mpw_str(
|
||||
"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 );
|
||||
@@ -627,13 +627,13 @@ static MPMarshalledUser *mpw_marshall_read_flat(
|
||||
mpw_free_strings( &fullName, &keyID, NULL );
|
||||
mpw_free( &masterKey, MPMasterKeySize );
|
||||
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return user;
|
||||
}
|
||||
|
||||
#if MPW_JSON
|
||||
static void mpw_marshall_read_json_info(
|
||||
const char *in, MPMarshallInfo *info) {
|
||||
static void mpw_marshal_read_json_info(
|
||||
const char *in, MPMarshalInfo *info) {
|
||||
|
||||
// Parse JSON.
|
||||
enum json_tokener_error json_error = json_tokener_success;
|
||||
@@ -650,18 +650,18 @@ static void mpw_marshall_read_json_info(
|
||||
|
||||
// Section: "user"
|
||||
info->algorithm = (MPAlgorithmVersion)mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||
info->fullName = strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
||||
info->keyID = strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
||||
info->fullName = mpw_strdup( mpw_get_json_string( json_file, "user.full_name", NULL ) );
|
||||
info->keyID = mpw_strdup( mpw_get_json_string( json_file, "user.key_id", NULL ) );
|
||||
|
||||
json_object_put( json_file );
|
||||
}
|
||||
|
||||
static MPMarshalledUser *mpw_marshall_read_json(
|
||||
const char *in, const char *masterPassword, MPMarshallError *error) {
|
||||
static MPMarshalledUser *mpw_marshal_read_json(
|
||||
const char *in, const char *masterPassword, MPMarshalError *error) {
|
||||
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Unexpected internal error." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Unexpected internal error." };
|
||||
if (!in || !strlen( in )) {
|
||||
error->type = MPMarshallErrorStructure;
|
||||
error->type = MPMarshalErrorStructure;
|
||||
error->description = mpw_str( "No input data." );
|
||||
return NULL;
|
||||
}
|
||||
@@ -670,7 +670,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
||||
enum json_tokener_error json_error = json_tokener_success;
|
||||
json_object *json_file = json_tokener_parse_verbose( in, &json_error );
|
||||
if (!json_file || json_error != json_tokener_success) {
|
||||
*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;
|
||||
}
|
||||
|
||||
@@ -682,7 +682,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
||||
// Section: "export"
|
||||
int64_t fileFormat = mpw_get_json_int( json_file, "export.format", 0 );
|
||||
if (fileFormat < 1) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported format: %u", fileFormat ) };
|
||||
return NULL;
|
||||
}
|
||||
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 );
|
||||
int64_t value = mpw_get_json_int( json_file, "user.algorithm", MPAlgorithmVersionCurrent );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user algorithm version: %u", value ) };
|
||||
return NULL;
|
||||
}
|
||||
MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value;
|
||||
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
|
||||
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;
|
||||
}
|
||||
time_t lastUsed = mpw_mktime( str_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;
|
||||
}
|
||||
if (!fullName || !strlen( fullName )) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorMissing, "Missing value for full name." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorMissing, "Missing value for full name." };
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!(user = mpw_marshall_user( fullName, masterPassword, algorithm ))) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new user." };
|
||||
if (!(user = mpw_marshal_user( fullName, masterPassword, algorithm ))) {
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new user." };
|
||||
return NULL;
|
||||
}
|
||||
user->redacted = fileRedacted;
|
||||
@@ -736,18 +736,18 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
||||
const char *siteName = json_site.key;
|
||||
value = mpw_get_json_int( json_site.val, "algorithm", (int32_t)user->algorithm );
|
||||
if (value < MPAlgorithmVersionFirst || value > MPAlgorithmVersionLast) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site algorithm version: %s: %d", siteName, value ) };
|
||||
return NULL;
|
||||
}
|
||||
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
|
||||
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
|
||||
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;
|
||||
}
|
||||
value = mpw_get_json_int( json_site.val, "counter", 1 );
|
||||
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;
|
||||
}
|
||||
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 );
|
||||
time_t siteLastUsed = mpw_mktime( str_lastUsed );
|
||||
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;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
MPMarshalledSite *site = mpw_marshall_site( user, siteName, siteType, siteCounter, siteAlgorithm );
|
||||
MPMarshalledSite *site = mpw_marshal_site( user, siteName, siteType, siteCounter, siteAlgorithm );
|
||||
if (!site) {
|
||||
*error = (MPMarshallError){ MPMarshallErrorInternal, "Couldn't allocate a new site." };
|
||||
*error = (MPMarshalError){ MPMarshalErrorInternal, "Couldn't allocate a new site." };
|
||||
return NULL;
|
||||
}
|
||||
|
||||
site->loginType = siteLoginType;
|
||||
site->url = siteURL? strdup( siteURL ): NULL;
|
||||
site->url = siteURL? mpw_strdup( siteURL ): NULL;
|
||||
site->uses = siteUses;
|
||||
site->lastUsed = siteLastUsed;
|
||||
if (!user->redacted) {
|
||||
// Clear Text
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -792,9 +792,9 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
||||
else {
|
||||
// Redacted
|
||||
if (siteContent && strlen( siteContent ))
|
||||
site->content = strdup( siteContent );
|
||||
site->content = mpw_strdup( siteContent );
|
||||
if (siteLoginName && strlen( siteLoginName ))
|
||||
site->loginContent = strdup( siteLoginName );
|
||||
site->loginContent = mpw_strdup( siteLoginName );
|
||||
}
|
||||
|
||||
json_object_iter json_site_question;
|
||||
@@ -813,32 +813,32 @@ static MPMarshalledUser *mpw_marshall_read_json(
|
||||
else {
|
||||
// Redacted
|
||||
if (answerContent && strlen( answerContent ))
|
||||
question->content = strdup( answerContent );
|
||||
question->content = mpw_strdup( answerContent );
|
||||
}
|
||||
}
|
||||
}
|
||||
json_object_put( json_file );
|
||||
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return user;
|
||||
}
|
||||
#endif
|
||||
|
||||
MPMarshallInfo *mpw_marshall_read_info(
|
||||
MPMarshalInfo *mpw_marshal_read_info(
|
||||
const char *in) {
|
||||
|
||||
MPMarshallInfo *info = malloc( sizeof( MPMarshallInfo ) );
|
||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatNone };
|
||||
MPMarshalInfo *info = malloc( sizeof( MPMarshalInfo ) );
|
||||
*info = (MPMarshalInfo){ .format = MPMarshalFormatNone };
|
||||
|
||||
if (in && strlen( in )) {
|
||||
if (in[0] == '#') {
|
||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatFlat };
|
||||
mpw_marshall_read_flat_info( in, info );
|
||||
*info = (MPMarshalInfo){ .format = MPMarshalFormatFlat };
|
||||
mpw_marshal_read_flat_info( in, info );
|
||||
}
|
||||
else if (in[0] == '{') {
|
||||
*info = (MPMarshallInfo){ .format = MPMarshallFormatJSON };
|
||||
*info = (MPMarshalInfo){ .format = MPMarshalFormatJSON };
|
||||
#if MPW_JSON
|
||||
mpw_marshall_read_json_info( in, info );
|
||||
mpw_marshal_read_json_info( in, info );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -846,30 +846,30 @@ MPMarshallInfo *mpw_marshall_read_info(
|
||||
return info;
|
||||
}
|
||||
|
||||
MPMarshalledUser *mpw_marshall_read(
|
||||
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error) {
|
||||
MPMarshalledUser *mpw_marshal_read(
|
||||
const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error) {
|
||||
|
||||
switch (inFormat) {
|
||||
case MPMarshallFormatNone:
|
||||
*error = (MPMarshallError){ .type = MPMarshallSuccess };
|
||||
case MPMarshalFormatNone:
|
||||
*error = (MPMarshalError){ .type = MPMarshalSuccess };
|
||||
return false;
|
||||
case MPMarshallFormatFlat:
|
||||
return mpw_marshall_read_flat( in, masterPassword, error );
|
||||
case MPMarshalFormatFlat:
|
||||
return mpw_marshal_read_flat( in, masterPassword, error );
|
||||
#if MPW_JSON
|
||||
case MPMarshallFormatJSON:
|
||||
return mpw_marshall_read_json( in, masterPassword, error );
|
||||
case MPMarshalFormatJSON:
|
||||
return mpw_marshal_read_json( in, masterPassword, error );
|
||||
#endif
|
||||
default:
|
||||
*error = (MPMarshallError){ MPMarshallErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
||||
*error = (MPMarshalError){ MPMarshalErrorFormat, mpw_str( "Unsupported input format: %u", inFormat ) };
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const MPMarshallFormat mpw_formatWithName(
|
||||
const MPMarshalFormat mpw_formatWithName(
|
||||
const char *formatName) {
|
||||
|
||||
if (!formatName || !strlen( formatName ))
|
||||
return MPMarshallFormatNone;
|
||||
return MPMarshalFormatNone;
|
||||
|
||||
// Lower-case to standardize it.
|
||||
size_t stdFormatNameSize = strlen( formatName );
|
||||
@@ -878,46 +878,46 @@ const MPMarshallFormat mpw_formatWithName(
|
||||
stdFormatName[c] = (char)tolower( formatName[c] );
|
||||
stdFormatName[stdFormatNameSize] = '\0';
|
||||
|
||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshallFormatNone;
|
||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshallFormatFlat;
|
||||
if (strncmp( mpw_nameForFormat( MPMarshallFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshallFormatJSON;
|
||||
if (strncmp( mpw_nameForFormat( MPMarshalFormatNone ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshalFormatNone;
|
||||
if (strncmp( mpw_nameForFormat( MPMarshalFormatFlat ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshalFormatFlat;
|
||||
if (strncmp( mpw_nameForFormat( MPMarshalFormatJSON ), stdFormatName, strlen( stdFormatName ) ) == 0)
|
||||
return MPMarshalFormatJSON;
|
||||
|
||||
dbg( "Not a format name: %s\n", stdFormatName );
|
||||
return (MPMarshallFormat)ERR;
|
||||
dbg( "Not a format name: %s", stdFormatName );
|
||||
return (MPMarshalFormat)ERR;
|
||||
}
|
||||
|
||||
const char *mpw_nameForFormat(
|
||||
const MPMarshallFormat format) {
|
||||
const MPMarshalFormat format) {
|
||||
|
||||
switch (format) {
|
||||
case MPMarshallFormatNone:
|
||||
case MPMarshalFormatNone:
|
||||
return "none";
|
||||
case MPMarshallFormatFlat:
|
||||
case MPMarshalFormatFlat:
|
||||
return "flat";
|
||||
case MPMarshallFormatJSON:
|
||||
case MPMarshalFormatJSON:
|
||||
return "json";
|
||||
default: {
|
||||
dbg( "Unknown format: %d\n", format );
|
||||
dbg( "Unknown format: %d", format );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *mpw_marshall_format_extension(
|
||||
const MPMarshallFormat format) {
|
||||
const char *mpw_marshal_format_extension(
|
||||
const MPMarshalFormat format) {
|
||||
|
||||
switch (format) {
|
||||
case MPMarshallFormatNone:
|
||||
case MPMarshalFormatNone:
|
||||
return NULL;
|
||||
case MPMarshallFormatFlat:
|
||||
case MPMarshalFormatFlat:
|
||||
return "mpsites";
|
||||
case MPMarshallFormatJSON:
|
||||
case MPMarshalFormatJSON:
|
||||
return "mpsites.json";
|
||||
default: {
|
||||
dbg( "Unknown format: %d\n", format );
|
||||
dbg( "Unknown format: %d", format );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
#ifndef _MPW_MARSHALL_H
|
||||
#define _MPW_MARSHALL_H
|
||||
#ifndef _MPW_MARSHAL_H
|
||||
#define _MPW_MARSHAL_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -25,37 +25,41 @@
|
||||
|
||||
//// Types.
|
||||
|
||||
typedef mpw_enum( unsigned int, MPMarshallFormat ) {
|
||||
/** Generate a key for authentication. */
|
||||
MPMarshallFormatNone,
|
||||
/** Generate a key for authentication. */
|
||||
MPMarshallFormatFlat,
|
||||
/** Generate a name for identification. */
|
||||
MPMarshallFormatJSON,
|
||||
typedef mpw_enum( unsigned int, MPMarshalFormat ) {
|
||||
/** Do not marshal. */
|
||||
MPMarshalFormatNone,
|
||||
/** Marshal using the line-based plain-text format. */
|
||||
MPMarshalFormatFlat,
|
||||
/** Marshal using the JSON structured format. */
|
||||
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. */
|
||||
MPMarshallSuccess,
|
||||
MPMarshalSuccess,
|
||||
/** An error in the structure of the marshall file interrupted marshalling. */
|
||||
MPMarshallErrorStructure,
|
||||
MPMarshalErrorStructure,
|
||||
/** The marshall file uses an unsupported format version. */
|
||||
MPMarshallErrorFormat,
|
||||
MPMarshalErrorFormat,
|
||||
/** A required value is missing or not specified. */
|
||||
MPMarshallErrorMissing,
|
||||
MPMarshalErrorMissing,
|
||||
/** The given master password is not valid. */
|
||||
MPMarshallErrorMasterPassword,
|
||||
MPMarshalErrorMasterPassword,
|
||||
/** An illegal value was specified. */
|
||||
MPMarshallErrorIllegal,
|
||||
MPMarshalErrorIllegal,
|
||||
/** An internal system error interrupted marshalling. */
|
||||
MPMarshallErrorInternal,
|
||||
MPMarshalErrorInternal,
|
||||
};
|
||||
typedef struct MPMarshallError {
|
||||
MPMarshallErrorType type;
|
||||
typedef struct MPMarshalError {
|
||||
MPMarshalErrorType type;
|
||||
const char *description;
|
||||
} MPMarshallError;
|
||||
} MPMarshalError;
|
||||
|
||||
typedef struct MPMarshalledQuestion {
|
||||
const char *keyword;
|
||||
@@ -95,34 +99,34 @@ typedef struct MPMarshalledUser {
|
||||
MPMarshalledSite *sites;
|
||||
} MPMarshalledUser;
|
||||
|
||||
typedef struct MPMarshallInfo {
|
||||
MPMarshallFormat format;
|
||||
typedef struct MPMarshalInfo {
|
||||
MPMarshalFormat format;
|
||||
MPAlgorithmVersion algorithm;
|
||||
const char *fullName;
|
||||
const char *keyID;
|
||||
bool redacted;
|
||||
time_t date;
|
||||
} MPMarshallInfo;
|
||||
} MPMarshalInfo;
|
||||
|
||||
//// Marshalling.
|
||||
|
||||
/** Write the user and all associated data out to the given output buffer using the given marshalling format. */
|
||||
bool mpw_marshall_write(
|
||||
char **out, const MPMarshallFormat outFormat, const MPMarshalledUser *user, MPMarshallError *error);
|
||||
bool mpw_marshal_write(
|
||||
char **out, const MPMarshalFormat outFormat, const MPMarshalledUser *user, MPMarshalError *error);
|
||||
/** Try to read metadata on the sites in the input buffer. */
|
||||
MPMarshallInfo *mpw_marshall_read_info(
|
||||
MPMarshalInfo *mpw_marshal_read_info(
|
||||
const char *in);
|
||||
/** Unmarshall sites in the given input buffer by parsing it using the given marshalling format. */
|
||||
MPMarshalledUser *mpw_marshall_read(
|
||||
const char *in, const MPMarshallFormat inFormat, const char *masterPassword, MPMarshallError *error);
|
||||
MPMarshalledUser *mpw_marshal_read(
|
||||
const char *in, const MPMarshalFormat inFormat, const char *masterPassword, MPMarshalError *error);
|
||||
|
||||
//// Utilities.
|
||||
|
||||
/** 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);
|
||||
/** Create a new site attached to the given user object, ready for marshalling. */
|
||||
MPMarshalledSite *mpw_marshall_site(
|
||||
MPMarshalledSite *mpw_marshal_site(
|
||||
MPMarshalledUser *user,
|
||||
const char *siteName, const MPResultType resultType, const MPCounterValue siteCounter, const MPAlgorithmVersion algorithmVersion);
|
||||
/** Create a new question attached to the given site object, ready for marshalling. */
|
||||
@@ -130,7 +134,7 @@ MPMarshalledQuestion *mpw_marshal_question(
|
||||
MPMarshalledSite *site, const char *keyword);
|
||||
/** Free the given user object and all associated data. */
|
||||
bool mpw_marshal_info_free(
|
||||
MPMarshallInfo **info);
|
||||
MPMarshalInfo **info);
|
||||
bool mpw_marshal_free(
|
||||
MPMarshalledUser **user);
|
||||
|
||||
@@ -139,17 +143,17 @@ bool mpw_marshal_free(
|
||||
/**
|
||||
* @return The purpose represented by the given name.
|
||||
*/
|
||||
const MPMarshallFormat mpw_formatWithName(
|
||||
const MPMarshalFormat mpw_formatWithName(
|
||||
const char *formatName);
|
||||
/**
|
||||
* @return The standard name for the given purpose.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
const char *mpw_marshall_format_extension(
|
||||
const MPMarshallFormat format);
|
||||
const char *mpw_marshal_format_extension(
|
||||
const MPMarshalFormat format);
|
||||
|
||||
#endif // _MPW_MARSHALL_H
|
||||
#endif // _MPW_MARSHAL_H
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "mpw-types.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) {
|
||||
|
||||
// Find what password type is represented by the type letter.
|
||||
@@ -40,22 +43,21 @@ const MPResultType mpw_typeWithName(const char *typeName) {
|
||||
return MPResultTypeTemplatePIN;
|
||||
if ('n' == typeName[0])
|
||||
return MPResultTypeTemplateName;
|
||||
if ('p' == typeName[0])
|
||||
return MPResultTypeTemplatePhrase;
|
||||
if ('P' == typeName[0])
|
||||
return MPResultTypeStatefulPersonal;
|
||||
if ('D' == typeName[0])
|
||||
return MPResultTypeStatefulDevice;
|
||||
if ('k' == typeName[0])
|
||||
if ('K' == typeName[0])
|
||||
return MPResultTypeDeriveKey;
|
||||
}
|
||||
|
||||
// Lower-case and trim optionally leading "Generated" string from typeName to standardize it.
|
||||
size_t stdTypeNameOffset = 0;
|
||||
// Lower-case typeName to standardize it.
|
||||
size_t stdTypeNameSize = strlen( typeName );
|
||||
if (strstr( typeName, "Generated" ) == typeName)
|
||||
stdTypeNameSize -= (stdTypeNameOffset = strlen( "Generated" ));
|
||||
char stdTypeName[stdTypeNameSize + 1];
|
||||
for (size_t c = 0; c < stdTypeNameSize; ++c)
|
||||
stdTypeName[c] = (char)tolower( typeName[c + stdTypeNameOffset] );
|
||||
stdTypeName[c] = (char)tolower( typeName[c] );
|
||||
stdTypeName[stdTypeNameSize] = '\0';
|
||||
|
||||
// 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)
|
||||
return MPResultTypeDeriveKey;
|
||||
|
||||
dbg( "Not a generated type name: %s\n", stdTypeName );
|
||||
dbg( "Not a generated type name: %s", stdTypeName );
|
||||
return (MPResultType)ERR;
|
||||
}
|
||||
|
||||
@@ -112,7 +114,7 @@ const char *mpw_nameForType(MPResultType resultType) {
|
||||
case MPResultTypeDeriveKey:
|
||||
return "key";
|
||||
default: {
|
||||
dbg( "Unknown password type: %d\n", resultType );
|
||||
dbg( "Unknown password type: %d", resultType );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +123,7 @@ const char *mpw_nameForType(MPResultType resultType) {
|
||||
const char **mpw_templatesForType(MPResultType type, size_t *count) {
|
||||
|
||||
if (!(type & MPResultTypeClassTemplate)) {
|
||||
dbg( "Not a generated type: %d\n", type );
|
||||
dbg( "Not a generated type: %d", type );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ const char **mpw_templatesForType(MPResultType type, size_t *count) {
|
||||
return mpw_alloc_array( count, const char *,
|
||||
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
|
||||
default: {
|
||||
dbg( "Unknown generated type: %d\n", type );
|
||||
dbg( "Unknown generated type: %d", type );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -189,7 +191,7 @@ const MPKeyPurpose mpw_purposeWithName(const char *purposeName) {
|
||||
if (strncmp( mpw_nameForPurpose( MPKeyPurposeRecovery ), stdPurposeName, strlen( stdPurposeName ) ) == 0)
|
||||
return MPKeyPurposeRecovery;
|
||||
|
||||
dbg( "Not a purpose name: %s\n", stdPurposeName );
|
||||
dbg( "Not a purpose name: %s", stdPurposeName );
|
||||
return (MPKeyPurpose)ERR;
|
||||
}
|
||||
|
||||
@@ -203,7 +205,7 @@ const char *mpw_nameForPurpose(MPKeyPurpose purpose) {
|
||||
case MPKeyPurposeRecovery:
|
||||
return "recovery";
|
||||
default: {
|
||||
dbg( "Unknown purpose: %d\n", purpose );
|
||||
dbg( "Unknown purpose: %d", purpose );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +221,7 @@ const char *mpw_scopeForPurpose(MPKeyPurpose purpose) {
|
||||
case MPKeyPurposeRecovery:
|
||||
return "com.lyndir.masterpassword.answer";
|
||||
default: {
|
||||
dbg( "Unknown purpose: %d\n", purpose );
|
||||
dbg( "Unknown purpose: %d", purpose );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -249,7 +251,7 @@ const char *mpw_charactersInClass(char characterClass) {
|
||||
case ' ':
|
||||
return " ";
|
||||
default: {
|
||||
dbg( "Unknown character class: %c\n", characterClass );
|
||||
dbg( "Unknown character class: %c", characterClass );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,8 @@
|
||||
|
||||
//// Types.
|
||||
|
||||
#define MPMasterKeySize 64 /* bytes */
|
||||
typedef const uint8_t *MPMasterKey;
|
||||
#define MPSiteKeySize (256 / 8) /* bytes */ // Size of HMAC-SHA-256
|
||||
typedef const uint8_t *MPSiteKey;
|
||||
extern const size_t MPMasterKeySize, MPSiteKeySize; /* bytes */
|
||||
typedef const uint8_t *MPMasterKey, *MPSiteKey;
|
||||
typedef const char *MPKeyID;
|
||||
|
||||
typedef mpw_enum( uint8_t, MPKeyPurpose ) {
|
||||
@@ -72,30 +70,30 @@ typedef mpw_enum( uint16_t, MPSiteFeature ) {
|
||||
|
||||
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
||||
typedef mpw_enum( uint32_t, MPResultType ) {
|
||||
/** pg^VMAUBk5x3p%HP%i4= */
|
||||
/** 16: pg^VMAUBk5x3p%HP%i4= */
|
||||
MPResultTypeTemplateMaximum = 0x0 | MPResultTypeClassTemplate | 0x0,
|
||||
/** BiroYena8:Kixa */
|
||||
/** 17: BiroYena8:Kixa */
|
||||
MPResultTypeTemplateLong = 0x1 | MPResultTypeClassTemplate | 0x0,
|
||||
/** BirSuj0- */
|
||||
/** 18: BirSuj0- */
|
||||
MPResultTypeTemplateMedium = 0x2 | MPResultTypeClassTemplate | 0x0,
|
||||
/** pO98MoD0 */
|
||||
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
|
||||
/** Bir8 */
|
||||
/** 19: Bir8 */
|
||||
MPResultTypeTemplateShort = 0x3 | MPResultTypeClassTemplate | 0x0,
|
||||
/** 2798 */
|
||||
/** 20: pO98MoD0 */
|
||||
MPResultTypeTemplateBasic = 0x4 | MPResultTypeClassTemplate | 0x0,
|
||||
/** 21: 2798 */
|
||||
MPResultTypeTemplatePIN = 0x5 | MPResultTypeClassTemplate | 0x0,
|
||||
/** birsujano */
|
||||
/** 30: birsujano */
|
||||
MPResultTypeTemplateName = 0xE | MPResultTypeClassTemplate | 0x0,
|
||||
/** bir yennoquce fefi */
|
||||
/** 31: bir yennoquce fefi */
|
||||
MPResultTypeTemplatePhrase = 0xF | MPResultTypeClassTemplate | 0x0,
|
||||
|
||||
/** Custom saved password. */
|
||||
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
|
||||
/** Custom saved password that should not be exported from the device. */
|
||||
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
|
||||
/** 1056: Custom saved password. */
|
||||
MPResultTypeStatefulPersonal = 0x0 | MPResultTypeClassStateful | MPSiteFeatureExportContent,
|
||||
/** 2081: Custom saved password that should not be exported from the device. */
|
||||
MPResultTypeStatefulDevice = 0x1 | MPResultTypeClassStateful | MPSiteFeatureDevicePrivate,
|
||||
|
||||
/** Derive a unique binary key. */
|
||||
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
|
||||
/** 4160: Derive a unique binary key. */
|
||||
MPResultTypeDeriveKey = 0x0 | MPResultTypeClassDerive | MPSiteFeatureAlternative,
|
||||
|
||||
MPResultTypeDefault = MPResultTypeTemplateLong,
|
||||
};
|
||||
@@ -111,6 +109,28 @@ typedef mpw_enum ( uint32_t, MPCounterValue ) {
|
||||
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.
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,18 +20,15 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if MPW_COLOR
|
||||
#include <unistd.h>
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
#endif
|
||||
|
||||
#if MPW_CPERCIVA
|
||||
#include <scrypt/crypto_scrypt.h>
|
||||
#include <scrypt/sha256.h>
|
||||
#elif MPW_SODIUM
|
||||
#include "sodium.h"
|
||||
#endif
|
||||
#define AES_ECB 0
|
||||
#define AES_CBC 1
|
||||
#include "aes.h"
|
||||
|
||||
#include "mpw-util.h"
|
||||
|
||||
@@ -134,31 +131,38 @@ bool __mpw_realloc(const void **buffer, size_t *bufferSize, const size_t deltaSi
|
||||
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)
|
||||
return false;
|
||||
|
||||
memset( (void *)*buffer, 0, bufferSize );
|
||||
free( (void *)*buffer );
|
||||
mpw_zero( *buffer, bufferSize );
|
||||
free( *buffer );
|
||||
*buffer = NULL;
|
||||
|
||||
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;
|
||||
|
||||
va_list args;
|
||||
va_start( args, 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 );
|
||||
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 (keySize < crypto_generichash_blake2b_KEYBYTES_MIN || keySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
||||
subkeySize < crypto_generichash_blake2b_KEYBYTES_MIN || subkeySize > crypto_generichash_blake2b_KEYBYTES_MAX ||
|
||||
contextSize < crypto_generichash_blake2b_BYTES_MIN || contextSize > crypto_generichash_blake2b_BYTES_MAX ||
|
||||
(personal && strlen( personal ) > crypto_generichash_blake2b_PERSONALBYTES)) {
|
||||
errno = EINVAL;
|
||||
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];
|
||||
bzero( saltBuf, sizeof saltBuf );
|
||||
mpw_zero( saltBuf, sizeof saltBuf );
|
||||
if (id)
|
||||
mpw_uint64( id, saltBuf );
|
||||
|
||||
uint8_t personalBuf[crypto_generichash_blake2b_PERSONALBYTES];
|
||||
bzero( personalBuf, sizeof saltBuf );
|
||||
mpw_zero( personalBuf, sizeof personalBuf );
|
||||
if (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;
|
||||
}
|
||||
|
||||
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 < crypto_stream_KEYBYTES)
|
||||
if (!key || keySize < 16 || !*bufSize)
|
||||
return NULL;
|
||||
|
||||
uint8_t nonce[crypto_stream_NONCEBYTES];
|
||||
bzero( (void *)nonce, sizeof( nonce ) );
|
||||
// IV = zero
|
||||
uint8_t iv[16];
|
||||
mpw_zero( iv, sizeof iv );
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (encrypt) {
|
||||
uint8_t *const cipherBuf = malloc( bufSize );
|
||||
if (crypto_stream_aes128ctr_xor( cipherBuf, buf, bufSize, nonce, key ) != 0) {
|
||||
mpw_free( &cipherBuf, bufSize );
|
||||
return NULL;
|
||||
}
|
||||
return cipherBuf;
|
||||
}
|
||||
else {
|
||||
uint8_t *const plainBuf = malloc( bufSize );
|
||||
if (crypto_stream_aes128ctr( plainBuf, bufSize, nonce, key ) != 0) {
|
||||
mpw_free( &plainBuf, bufSize );
|
||||
return NULL;
|
||||
}
|
||||
for (size_t c = 0; c < bufSize; ++c)
|
||||
plainBuf[c] = buf[c] ^ plainBuf[c];
|
||||
return plainBuf;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#error No crypto support for mpw_aes.
|
||||
#endif
|
||||
// Add PKCS#7 padding
|
||||
uint32_t aesSize = ((uint32_t)*bufSize + 15 / 16) * 16; // round up to block size.
|
||||
if (encrypt && !(*bufSize % 16)) // add pad block if plain text fits block size.
|
||||
encrypt += 16;
|
||||
uint8_t aesBuf[aesSize];
|
||||
memcpy( aesBuf, buf, *bufSize );
|
||||
memset( aesBuf + *bufSize, aesSize - *bufSize, aesSize - *bufSize );
|
||||
uint8_t *resultBuf = malloc( aesSize );
|
||||
|
||||
if (encrypt)
|
||||
AES_CBC_encrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
||||
else
|
||||
AES_CBC_decrypt_buffer( resultBuf, aesBuf, aesSize, key, iv );
|
||||
mpw_zero( aesBuf, aesSize );
|
||||
mpw_zero( iv, 16 );
|
||||
|
||||
// Truncate PKCS#7 padding
|
||||
if (encrypt)
|
||||
*bufSize = aesSize;
|
||||
else if (*bufSize % 16 == 0 && resultBuf[aesSize - 1] < 16)
|
||||
*bufSize -= resultBuf[aesSize - 1];
|
||||
|
||||
return resultBuf;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
@@ -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.
|
||||
otp %= (int)pow(10, digits);
|
||||
return strdup( mpw_str( "%0*d", digits, otp ) );
|
||||
return mpw_strdup( mpw_str( "%0*d", digits, otp ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -438,99 +438,6 @@ const char *mpw_hex_l(uint32_t number) {
|
||||
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.
|
||||
*/
|
||||
@@ -561,3 +468,31 @@ const size_t mpw_utf8_strlen(const char *utf8String) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -25,49 +25,44 @@
|
||||
#include "mpw-types.h"
|
||||
|
||||
//// 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
|
||||
extern int mpw_verbosity;
|
||||
#define trc_level 3
|
||||
/** Logging internal state. */
|
||||
#define trc(...) ({ \
|
||||
if (mpw_verbosity >= trc_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#endif
|
||||
#ifndef dbg
|
||||
#define dbg_level 2
|
||||
#define trc_level 3
|
||||
#define trc(...) mpw_log( trc_level, ##__VA_ARGS__ )
|
||||
|
||||
/** Logging state and events interesting when investigating issues. */
|
||||
#define dbg(...) ({ \
|
||||
if (mpw_verbosity >= dbg_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#endif
|
||||
#ifndef inf
|
||||
#define inf_level 1
|
||||
#define dbg_level 2
|
||||
#define dbg(...) mpw_log( dbg_level, ##__VA_ARGS__ )
|
||||
|
||||
/** User messages. */
|
||||
#define inf(...) ({ \
|
||||
if (mpw_verbosity >= inf_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#endif
|
||||
#ifndef wrn
|
||||
#define wrn_level 0
|
||||
#define inf_level 1
|
||||
#define inf(...) mpw_log( inf_level, ##__VA_ARGS__ )
|
||||
|
||||
/** Recoverable issues and user suggestions. */
|
||||
#define wrn(...) ({ \
|
||||
if (mpw_verbosity >= wrn_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#endif
|
||||
#ifndef err
|
||||
#define err_level -1
|
||||
#define wrn_level 0
|
||||
#define wrn(...) mpw_log( wrn_level, ##__VA_ARGS__ )
|
||||
|
||||
/** Unrecoverable issues. */
|
||||
#define err(...) ({ \
|
||||
if (mpw_verbosity >= err_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#endif
|
||||
#ifndef ftl
|
||||
#define ftl_level -2
|
||||
#define err_level -1
|
||||
#define err(...) mpw_log( err_level, ##__VA_ARGS__ )
|
||||
|
||||
/** Issues that lead to abortion. */
|
||||
#define ftl(...) ({ \
|
||||
if (mpw_verbosity >= ftl_level) \
|
||||
fprintf( stderr, __VA_ARGS__ ); })
|
||||
#define ftl_level -2
|
||||
#define ftl(...) mpw_log( ftl_level, ##__VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
@@ -136,23 +131,25 @@ bool mpw_push_int(
|
||||
* @return true if successful, false if reallocation failed.
|
||||
*/
|
||||
#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);
|
||||
void mpw_zero(
|
||||
void *buffer, size_t bufferSize);
|
||||
/** Free a buffer after zero'ing its contents, then set the reference to NULL. */
|
||||
#define mpw_free(buffer, bufferSize) \
|
||||
({ typeof(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (const void **)_b, bufferSize ); })
|
||||
({ __typeof__(buffer) _b = buffer; const void *__b = *_b; (void)__b; __mpw_free( (void **)_b, bufferSize ); })
|
||||
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. */
|
||||
#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(
|
||||
const char **string);
|
||||
char **string);
|
||||
/** Free strings after zero'ing their contents, then set the references to NULL. Terminate the va_list with NULL. */
|
||||
#define mpw_free_strings(strings, ...) \
|
||||
({ typeof(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (const char **)_s, __VA_ARGS__ ); })
|
||||
({ __typeof__(strings) _s = strings; const char *__s = *_s; (void)__s; __mpw_free_strings( (char **)_s, __VA_ARGS__ ); })
|
||||
bool __mpw_free_strings(
|
||||
const char **strings, ...);
|
||||
char **strings, ...);
|
||||
|
||||
//// Cryptographic functions.
|
||||
|
||||
@@ -173,11 +170,11 @@ uint8_t const *mpw_hash_hmac_sha256(
|
||||
/** Encrypt a plainBuf with the given key using AES-128-CBC.
|
||||
* @return A new bufSize allocated buffer containing the cipherBuf. */
|
||||
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.
|
||||
* @return A new bufSize allocated buffer containing the plainBuf. */
|
||||
uint8_t const *mpw_aes_decrypt(
|
||||
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, const size_t bufSize);
|
||||
const uint8_t *key, const size_t keySize, const uint8_t *cipherBuf, size_t *bufSize);
|
||||
/** Calculate an OTP using RFC-4226.
|
||||
* @return A newly allocated string containing exactly `digits` decimal OTP digits. */
|
||||
#if UNUSED
|
||||
@@ -201,13 +198,14 @@ MPKeyID mpw_id_buf(const void *buf, size_t length);
|
||||
/** Compare two fingerprints for equality.
|
||||
* @return true if the buffers represent identical fingerprints. */
|
||||
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.
|
||||
|
||||
/** @return The amount of display characters in the given UTF-8 string. */
|
||||
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
|
||||
|
||||
@@ -5,9 +5,10 @@ plugins {
|
||||
description = 'Master Password Algorithm Implementation'
|
||||
|
||||
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' )
|
||||
}
|
||||
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: 'org.jetbrains', name: 'annotations', version: '13.0'
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-system</artifactId>
|
||||
<version>1.6-p9</version>
|
||||
<version>1.6-p11</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>joda-time</groupId>
|
||||
@@ -31,6 +31,11 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-crypto</artifactId>
|
||||
<version>1.6-p11</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,8 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||
import com.lyndir.lhunath.opal.system.MessageDigests;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
|
||||
/**
|
||||
@@ -32,68 +29,18 @@ public final class MPConstant {
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
public static final String env_rcDir = "MP_RCDIR";
|
||||
public static final String env_rcDir = "MPW_RCDIR";
|
||||
/**
|
||||
* mpw: permit automatic update checks.
|
||||
*/
|
||||
public static final String env_checkUpdates = "MP_CHECKUPDATES";
|
||||
public static final String env_checkUpdates = "MPW_CHECKUPDATES";
|
||||
|
||||
/* 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 DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
||||
}
|
||||
|
||||
@@ -16,13 +16,10 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
/**
|
||||
*
|
||||
* @author lhunath, 15-02-04
|
||||
*/
|
||||
|
||||
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
/**
|
||||
* @author lhunath, 2017-09-21
|
||||
*/
|
||||
public class MPInvalidatedException extends Exception {
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nullable;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
|
||||
/**
|
||||
@@ -32,15 +31,21 @@ import org.jetbrains.annotations.NonNls;
|
||||
*
|
||||
* @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
|
||||
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x0 ),
|
||||
/**
|
||||
* pg^VMAUBk5x3p%HP%i4=
|
||||
*/
|
||||
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" ),
|
||||
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
|
||||
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
|
||||
@@ -52,65 +57,92 @@ public enum MPSiteType {
|
||||
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
|
||||
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
|
||||
new MPTemplate( "CvccCvcvCvccno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x1 ),
|
||||
MPResultTypeClass.Template, 0x1 ),
|
||||
|
||||
GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
|
||||
ImmutableList.of( "m", "med", "medium" ), // NON-NLS
|
||||
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x2 ),
|
||||
/**
|
||||
* BirSuj0-
|
||||
*/
|
||||
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
|
||||
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
|
||||
MPSiteTypeClass.Generated, 0x3 ),
|
||||
/**
|
||||
* pO98MoD0
|
||||
*/
|
||||
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" ) ), //
|
||||
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" ) ), //
|
||||
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" ) ), //
|
||||
MPSiteTypeClass.Generated, 0xE ),
|
||||
MPResultTypeClass.Template, 0xE ),
|
||||
|
||||
GeneratedPhrase( "Phrase", "20 character sentence.", //
|
||||
ImmutableList.of( "p", "phrase" ), // NON-NLS
|
||||
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
|
||||
/**
|
||||
* bir yennoquce fefi
|
||||
*/
|
||||
GeneratedPhrase( "phrase", "20 character sentence.", //
|
||||
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
|
||||
new MPTemplate( "cvc cvccvcvcv cvcv" ),
|
||||
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(), //
|
||||
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(), //
|
||||
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 description;
|
||||
private final List<String> options;
|
||||
private final List<MPTemplate> templates;
|
||||
private final MPSiteTypeClass typeClass;
|
||||
private final MPResultTypeClass typeClass;
|
||||
private final int typeIndex;
|
||||
private final Set<MPSiteFeature> typeFeatures;
|
||||
|
||||
MPSiteType(final String shortName, final String description, final List<String> options, final List<MPTemplate> templates,
|
||||
final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||
MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
|
||||
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||
|
||||
this.shortName = shortName;
|
||||
this.description = description;
|
||||
this.options = options;
|
||||
this.templates = templates;
|
||||
this.typeClass = typeClass;
|
||||
this.typeIndex = typeIndex;
|
||||
@@ -131,11 +163,7 @@ public enum MPSiteType {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<String> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public MPSiteTypeClass getTypeClass() {
|
||||
public MPResultTypeClass getTypeClass() {
|
||||
|
||||
return typeClass;
|
||||
}
|
||||
@@ -154,35 +182,22 @@ public enum MPSiteType {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param option The option to select a type with. It is matched case insensitively.
|
||||
*
|
||||
* @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.
|
||||
* @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 with the given name.
|
||||
*/
|
||||
@Nullable
|
||||
@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;
|
||||
|
||||
for (final MPSiteType type : values())
|
||||
if (type.name().equalsIgnoreCase( name ))
|
||||
for (final MPResultType type : values())
|
||||
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
|
||||
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.
|
||||
*/
|
||||
public static ImmutableList<MPSiteType> forClass(final MPSiteTypeClass typeClass) {
|
||||
public static ImmutableList<MPResultType> forClass(final MPResultTypeClass typeClass) {
|
||||
|
||||
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
|
||||
for (final MPSiteType type : values())
|
||||
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
|
||||
for (final MPResultType type : values())
|
||||
if (type.getTypeClass() == typeClass)
|
||||
types.add( type );
|
||||
|
||||
@@ -205,27 +220,28 @@ public enum MPSiteType {
|
||||
*
|
||||
* @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())
|
||||
if (siteType.getType() == type)
|
||||
return siteType;
|
||||
for (final MPResultType resultType : values())
|
||||
if (resultType.getType() == type)
|
||||
return resultType;
|
||||
|
||||
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;
|
||||
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
|
||||
for (final MPSiteType siteType : values())
|
||||
if (((siteType.getType() & ~0xF) & typeMask) != 0)
|
||||
types.add( siteType );
|
||||
int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
|
||||
|
||||
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
|
||||
for (final MPResultType resultType : values())
|
||||
if (((resultType.getType() & ~0xF) & typeMask) != 0)
|
||||
types.add( resultType );
|
||||
|
||||
return types.build();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ package com.lyndir.masterpassword;
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPSiteFeature {
|
||||
// bit 10 - 15
|
||||
|
||||
/**
|
||||
* Export the key-protected content data.
|
||||
@@ -33,7 +34,12 @@ public enum MPSiteFeature {
|
||||
/**
|
||||
* 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) {
|
||||
this.mask = mask;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
172
core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
Executable file
172
core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java
Executable 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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." );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
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 java.util.Objects;
|
||||
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.valueOf( 1 );
|
||||
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.ONE;
|
||||
|
||||
private final MPUser user;
|
||||
private MasterKey.Version algorithmVersion;
|
||||
private Instant lastUsed;
|
||||
private String siteName;
|
||||
private MPSiteType siteType;
|
||||
private UnsignedInteger siteCounter;
|
||||
private int uses;
|
||||
private String loginName;
|
||||
public abstract String getSiteName();
|
||||
|
||||
public MPSite(final MPUser user, final String siteName) {
|
||||
this( user, siteName, DEFAULT_TYPE, DEFAULT_COUNTER );
|
||||
public abstract void setSiteName(String siteName);
|
||||
|
||||
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) {
|
||||
this.user = user;
|
||||
this.algorithmVersion = MasterKey.Version.CURRENT;
|
||||
this.lastUsed = new Instant();
|
||||
this.siteName = siteName;
|
||||
this.siteType = siteType;
|
||||
this.siteCounter = siteCounter;
|
||||
}
|
||||
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
||||
throws MPInvalidatedException {
|
||||
|
||||
protected MPSite(final MPUser user, final MasterKey.Version algorithmVersion, final Instant lastUsed, final String siteName,
|
||||
final MPSiteType siteType, final UnsignedInteger siteCounter, final int uses, @Nullable final String loginName,
|
||||
@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;
|
||||
return masterKey.siteResult(
|
||||
getSiteName(), DEFAULT_COUNTER, MPKeyPurpose.Identification, null, loginType, loginContent, getAlgorithmVersion() );
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public int hashCode() {
|
||||
return Objects.hashCode( siteName );
|
||||
return Objects.hashCode( getSiteName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return strf( "{MPSite: %s}", siteName );
|
||||
return strf( "{%s: %s}", getClass().getSimpleName(), getSiteName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
@@ -10,13 +28,13 @@ import java.util.Objects;
|
||||
*/
|
||||
public class MPSiteResult {
|
||||
|
||||
private final MPSite site;
|
||||
private final MPFileSite site;
|
||||
|
||||
public MPSiteResult(final MPSite site) {
|
||||
public MPSiteResult(final MPFileSite site) {
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
public MPSite getSite() {
|
||||
public MPFileSite getSite() {
|
||||
return site;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -16,24 +16,21 @@
|
||||
// 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
|
||||
* @author lhunath, 14-12-07
|
||||
*/
|
||||
public enum MPSiteTypeClass {
|
||||
Generated( 1 << 4 ),
|
||||
Stored( 1 << 5 );
|
||||
public interface MPUnmarshaller {
|
||||
|
||||
private final int mask;
|
||||
@Nonnull
|
||||
MPFileUser unmarshall(@Nonnull File file)
|
||||
throws IOException;
|
||||
|
||||
MPSiteTypeClass(final int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
public int getMask() {
|
||||
return mask;
|
||||
}
|
||||
@Nonnull
|
||||
MPFileUser unmarshall(@Nonnull String content);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
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.collect.Sets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.masterpassword.MPSiteType;
|
||||
import com.lyndir.masterpassword.MasterKey;
|
||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||
import com.lyndir.masterpassword.MPMasterKey;
|
||||
import java.util.*;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 14-12-07
|
||||
* @author lhunath, 2014-06-08
|
||||
*/
|
||||
public class MPUser implements Comparable<MPUser> {
|
||||
|
||||
private final String fullName;
|
||||
private final Collection<MPSite> sites = Sets.newHashSet();
|
||||
public abstract class MPUser<S extends MPSite> {
|
||||
|
||||
@Nullable
|
||||
private byte[] keyID;
|
||||
private final MasterKey.Version algorithmVersion;
|
||||
private int avatar;
|
||||
private MPSiteType defaultType;
|
||||
private ReadableInstant lastUsed;
|
||||
protected MPMasterKey key;
|
||||
|
||||
public MPUser(final String fullName) {
|
||||
this( fullName, null );
|
||||
public abstract String getFullName();
|
||||
|
||||
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
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
public MasterKey authenticate(final char[] masterPassword)
|
||||
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 MPMasterKey getMasterKey() {
|
||||
return Preconditions.checkNotNull( key, "User is not authenticated: " + getFullName() );
|
||||
}
|
||||
|
||||
public String exportKeyID()
|
||||
throws MPInvalidatedException {
|
||||
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithmVersion() ) );
|
||||
}
|
||||
|
||||
public abstract MPMasterKey.Version getAlgorithmVersion();
|
||||
|
||||
public int getAvatar() {
|
||||
return avatar;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setAvatar(final int avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
public abstract void addSite(S site);
|
||||
|
||||
public MPSiteType getDefaultType() {
|
||||
return defaultType;
|
||||
}
|
||||
public abstract void deleteSite(S site);
|
||||
|
||||
public void setDefaultType(final MPSiteType defaultType) {
|
||||
this.defaultType = defaultType;
|
||||
}
|
||||
public abstract Collection<S> findSites(String query);
|
||||
|
||||
public ReadableInstant getLastUsed() {
|
||||
return lastUsed;
|
||||
}
|
||||
@Nonnull
|
||||
public abstract MPMasterKey authenticate(char[] masterPassword)
|
||||
throws MPIncorrectMasterPasswordException;
|
||||
|
||||
public void updateLastUsed() {
|
||||
lastUsed = new Instant();
|
||||
}
|
||||
|
||||
public Iterable<MPSite> getSites() {
|
||||
return sites;
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode( getFullName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( fullName, ((MPUser) obj).fullName ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode( fullName );
|
||||
return (this == obj) || ((obj instanceof MPUser) && Objects.equals( getFullName(), ((MPUser<?>) obj).getFullName() ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return strf( "{MPUser: %s}", fullName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final MPUser o) {
|
||||
int comparison = lastUsed.compareTo( o.lastUsed );
|
||||
if (comparison == 0)
|
||||
comparison = fullName.compareTo( o.fullName );
|
||||
|
||||
return comparison;
|
||||
return strf( "{%s: %s}", getClass().getSimpleName(), getFullName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@@ -9,31 +28,31 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class MPUserManager {
|
||||
|
||||
private final Map<String, MPUser> usersByName = Maps.newHashMap();
|
||||
private final Map<String, MPFileUser> usersByName = Maps.newHashMap();
|
||||
static MPUserManager instance;
|
||||
|
||||
public static MPUserManager get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected MPUserManager(final Iterable<MPUser> users) {
|
||||
for (final MPUser user : users)
|
||||
protected MPUserManager(final Iterable<MPFileUser> users) {
|
||||
for (final MPFileUser user : users)
|
||||
usersByName.put( user.getFullName(), user );
|
||||
}
|
||||
|
||||
public SortedSet<MPUser> getUsers() {
|
||||
public SortedSet<MPFileUser> getUsers() {
|
||||
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
|
||||
}
|
||||
|
||||
public MPUser getUserNamed(final String fullName) {
|
||||
public MPFileUser getUserNamed(final String fullName) {
|
||||
return usersByName.get( fullName );
|
||||
}
|
||||
|
||||
public void addUser(final MPUser user) {
|
||||
public void addUser(final MPFileUser user) {
|
||||
usersByName.put( user.getFullName(), user );
|
||||
}
|
||||
|
||||
public void deleteUser(final MPUser user) {
|
||||
public void deleteUser(final MPFileUser user) {
|
||||
usersByName.remove( user.getFullName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,12 +23,10 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
|
||||
import java.io.IOException;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.xml.parsers.*;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
@@ -38,7 +36,7 @@ import org.xml.sax.ext.DefaultHandler2;
|
||||
/**
|
||||
* @author lhunath, 2015-12-22
|
||||
*/
|
||||
@SuppressWarnings("HardCodedStringLiteral")
|
||||
@SuppressWarnings({ "HardCodedStringLiteral", "ProhibitedExceptionDeclared" })
|
||||
public class MPTestSuite implements Callable<Boolean> {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
@@ -99,12 +97,12 @@ public class MPTestSuite implements Callable<Boolean> {
|
||||
currentCase.siteName = text;
|
||||
if ("siteCounter".equals( qName ))
|
||||
currentCase.siteCounter = text.isEmpty()? null: UnsignedInteger.valueOf( text );
|
||||
if ("siteType".equals( qName ))
|
||||
currentCase.siteType = text;
|
||||
if ("siteVariant".equals( qName ))
|
||||
currentCase.siteVariant = text;
|
||||
if ("siteContext".equals( qName ))
|
||||
currentCase.siteContext = text;
|
||||
if ("resultType".equals( qName ))
|
||||
currentCase.resultType = text;
|
||||
if ("keyPurpose".equals( qName ))
|
||||
currentCase.keyPurpose = text;
|
||||
if ("keyContext".equals( qName ))
|
||||
currentCase.keyContext = text;
|
||||
if ("result".equals( qName ))
|
||||
currentCase.result = text;
|
||||
}
|
||||
@@ -134,7 +132,8 @@ public class MPTestSuite implements Callable<Boolean> {
|
||||
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();
|
||||
for (int c = 0; c < cases.size(); c++) {
|
||||
MPTests.Case testCase = cases.get( c );
|
||||
@@ -144,7 +143,7 @@ public class MPTestSuite implements Callable<Boolean> {
|
||||
progress( Logger.Target.INFO, c, cases.size(), //
|
||||
"[%s] on %s...", testName, testCase.getIdentifier() );
|
||||
|
||||
if (!testFunction.apply( testCase )) {
|
||||
if (!testFunction.run( testCase )) {
|
||||
progress( Logger.Target.ERROR, cases.size(), cases.size(), //
|
||||
"[%s] on %s: FAILED!", testName, testCase.getIdentifier() );
|
||||
|
||||
@@ -168,13 +167,14 @@ public class MPTestSuite implements Callable<Boolean> {
|
||||
@Override
|
||||
public Boolean call()
|
||||
throws Exception {
|
||||
return forEach( "mpw", new NNFunctionNN<MPTests.Case, Boolean>() {
|
||||
@Nonnull
|
||||
return forEach( "mpw", new TestCase() {
|
||||
@Override
|
||||
public Boolean apply(@Nonnull final MPTests.Case testCase) {
|
||||
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
|
||||
String sitePassword = masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
|
||||
testCase.getSiteVariant(), testCase.getSiteContext() );
|
||||
public boolean run(final MPTests.Case testCase)
|
||||
throws Exception {
|
||||
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), testCase.getMasterPassword().toCharArray() );
|
||||
String sitePassword = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||
testCase.getKeyContext(), testCase.getResultType(),
|
||||
null, testCase.getAlgorithm() );
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public interface TestCase {
|
||||
|
||||
boolean run(MPTests.Case testCase)
|
||||
throws Exception;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,18 +66,18 @@ public class MPTests {
|
||||
|
||||
public static class Case {
|
||||
|
||||
String identifier;
|
||||
String parent;
|
||||
Integer algorithm;
|
||||
String fullName;
|
||||
String masterPassword;
|
||||
String keyID;
|
||||
String siteName;
|
||||
String identifier;
|
||||
String parent;
|
||||
Integer algorithm;
|
||||
String fullName;
|
||||
String masterPassword;
|
||||
String keyID;
|
||||
String siteName;
|
||||
UnsignedInteger siteCounter;
|
||||
String siteType;
|
||||
String siteVariant;
|
||||
String siteContext;
|
||||
String result;
|
||||
String resultType;
|
||||
String keyPurpose;
|
||||
String keyContext;
|
||||
String result;
|
||||
|
||||
private transient Case parentCase;
|
||||
|
||||
@@ -130,25 +130,25 @@ public class MPTests {
|
||||
return checkNotNull( parentCase.siteCounter );
|
||||
}
|
||||
} );
|
||||
siteType = ifNotNullElse( siteType, new NNSupplier<String>() {
|
||||
resultType = ifNotNullElse( resultType, new NNSupplier<String>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String get() {
|
||||
return checkNotNull( parentCase.siteType );
|
||||
return checkNotNull( parentCase.resultType );
|
||||
}
|
||||
} );
|
||||
siteVariant = ifNotNullElse( siteVariant, new NNSupplier<String>() {
|
||||
keyPurpose = ifNotNullElse( keyPurpose, new NNSupplier<String>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String get() {
|
||||
return checkNotNull( parentCase.siteVariant );
|
||||
return checkNotNull( parentCase.keyPurpose );
|
||||
}
|
||||
} );
|
||||
siteContext = ifNotNullElse( siteContext, new NNSupplier<String>() {
|
||||
keyContext = ifNotNullElse( keyContext, new NNSupplier<String>() {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String get() {
|
||||
return (parentCase == null)? "": checkNotNull( parentCase.siteContext );
|
||||
return (parentCase == null)? "": checkNotNull( parentCase.keyContext );
|
||||
}
|
||||
} );
|
||||
result = ifNotNullElse( result, new NNSupplier<String>() {
|
||||
@@ -171,8 +171,8 @@ public class MPTests {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MasterKey.Version getAlgorithm() {
|
||||
return MasterKey.Version.fromInt( checkNotNull( algorithm ) );
|
||||
public MPMasterKey.Version getAlgorithm() {
|
||||
return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -181,8 +181,8 @@ public class MPTests {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public char[] getMasterPassword() {
|
||||
return checkNotNull( masterPassword ).toCharArray();
|
||||
public String getMasterPassword() {
|
||||
return checkNotNull( masterPassword );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -200,18 +200,18 @@ public class MPTests {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPSiteType getSiteType() {
|
||||
return MPSiteType.forName( checkNotNull( siteType ) );
|
||||
public MPResultType getResultType() {
|
||||
return MPResultType.forName( checkNotNull( resultType ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPSiteVariant getSiteVariant() {
|
||||
return MPSiteVariant.forName( checkNotNull( siteVariant ) );
|
||||
public MPKeyPurpose getKeyPurpose() {
|
||||
return MPKeyPurpose.forName( checkNotNull( keyPurpose ) );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getSiteContext() {
|
||||
return checkNotNull( siteContext );
|
||||
public String getKeyContext() {
|
||||
return checkNotNull( keyContext );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -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#&@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#&@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#&@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>
|
||||
|
||||
1
core/java/tests/src/main/resources/mpw_tests.xml
Symbolic link
1
core/java/tests/src/main/resources/mpw_tests.xml
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../../mpw_tests.xml
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
|
||||
<logger name="com.lyndir" level="${mp.log.level:-TRACE}" />
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="stdout" />
|
||||
|
||||
279
core/mpw_tests.xml
Normal file
279
core/mpw_tests.xml
Normal 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#&@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#&@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#&@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>
|
||||
|
||||
6
gradle/.idea/runConfigurations/Android.xml
generated
6
gradle/.idea/runConfigurations/Android.xml
generated
@@ -6,20 +6,18 @@
|
||||
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||
<option name="MODE" value="default_activity" />
|
||||
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
|
||||
<option name="PREFERRED_AVD" value="" />
|
||||
<option name="CLEAR_LOGCAT" value="false" />
|
||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||
<option name="SKIP_NOOP_APK_INSTALLATIONS" 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="PREFERRED_AVD" value="" />
|
||||
<option name="DEBUGGER_TYPE" value="Java" />
|
||||
<Java />
|
||||
<Profilers>
|
||||
<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="INSTRUMENTATION_ENABLED" value="true" />
|
||||
</Profilers>
|
||||
|
||||
4
gradle/.idea/runConfigurations/GUI.xml
generated
4
gradle/.idea/runConfigurations/GUI.xml
generated
@@ -1,5 +1,5 @@
|
||||
<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="VM_PARAMETERS" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
@@ -9,7 +9,7 @@
|
||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<module name="gui" />
|
||||
<module name="masterpassword-gui" />
|
||||
<envs />
|
||||
<method />
|
||||
</configuration>
|
||||
|
||||
6
gradle/.idea/runConfigurations/Tests.xml
generated
6
gradle/.idea/runConfigurations/Tests.xml
generated
@@ -1,6 +1,6 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG">
|
||||
<module name="tests" />
|
||||
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG" show_console_on_std_err="true">
|
||||
<module name="" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" />
|
||||
<option name="SUITE_NAME" value="" />
|
||||
@@ -17,7 +17,7 @@
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
<value defaultName="singleModule" />
|
||||
<value defaultName="wholeProject" />
|
||||
</option>
|
||||
<option name="USE_DEFAULT_REPORTERS" value="false" />
|
||||
<option name="PROPERTIES_FILE" value="" />
|
||||
|
||||
2
gradle/.idea/scopes/masterpassword.xml
generated
2
gradle/.idea/scopes/masterpassword.xml
generated
@@ -1,3 +1,3 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<scope name="masterpassword" pattern="com.lyndir.masterpassword.*" />
|
||||
<scope name="masterpassword" pattern="com.lyndir.masterpassword..*" />
|
||||
</component>
|
||||
@@ -22,7 +22,7 @@ buildscript {
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<module>masterpassword-tests</module>
|
||||
<module>masterpassword-algorithm</module>
|
||||
<module>masterpassword-model</module>
|
||||
<module>masterpassword-cli</module>
|
||||
<module>masterpassword-gui</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
rootProject.name = 'masterpassword'
|
||||
|
||||
def local = new Properties();
|
||||
try {
|
||||
local.load(file('local.properties').newDataInputStream())
|
||||
} catch (FileNotFoundException ignored) {
|
||||
}
|
||||
|
||||
include 'masterpassword-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'
|
||||
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'
|
||||
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
|
||||
|
||||
include 'masterpassword-android'
|
||||
project(':masterpassword-android').projectDir = new File( '../platform-android' )
|
||||
if (local.containsKey('sdk.dir')) {
|
||||
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." )
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import android.view.WindowManager;
|
||||
import android.widget.*;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.google.common.util.concurrent.*;
|
||||
@@ -52,12 +51,12 @@ public class EmergencyActivity extends Activity {
|
||||
private static final int PASSWORD_NOTIFICATION = 0;
|
||||
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
|
||||
|
||||
private final Preferences preferences = Preferences.get( this );
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ImmutableList<MPSiteType> allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) );
|
||||
private final ImmutableList<MasterKey.Version> allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
|
||||
private final Preferences preferences = Preferences.get( this );
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ImmutableList<MPResultType> allResultTypes = ImmutableList.copyOf( MPResultType.forClass( MPResultTypeClass.Template ) );
|
||||
private final ImmutableList<MPMasterKey.Version> allVersions = ImmutableList.copyOf( MPMasterKey.Version.values() );
|
||||
|
||||
private ListenableFuture<MasterKey> masterKeyFuture;
|
||||
private MPMasterKey masterKey;
|
||||
|
||||
@BindView(R.id.progressView)
|
||||
ProgressBar progressView;
|
||||
@@ -71,8 +70,8 @@ public class EmergencyActivity extends Activity {
|
||||
@BindView(R.id.siteNameField)
|
||||
EditText siteNameField;
|
||||
|
||||
@BindView(R.id.siteTypeButton)
|
||||
Button siteTypeButton;
|
||||
@BindView(R.id.resultTypeButton)
|
||||
Button resultTypeButton;
|
||||
|
||||
@BindView(R.id.counterField)
|
||||
Button siteCounterButton;
|
||||
@@ -97,7 +96,6 @@ public class EmergencyActivity extends Activity {
|
||||
|
||||
private int id_userName;
|
||||
private int id_masterPassword;
|
||||
private int id_version;
|
||||
private String sitePassword;
|
||||
|
||||
public static void start(final Context context) {
|
||||
@@ -131,15 +129,15 @@ public class EmergencyActivity extends Activity {
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
siteTypeButton.setOnClickListener( new View.OnClickListener() {
|
||||
resultTypeButton.setOnClickListener( new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
MPSiteType siteType =
|
||||
allSiteTypes.get( (allSiteTypes.indexOf( siteTypeButton.getTag() ) + 1) % allSiteTypes.size() );
|
||||
preferences.setDefaultSiteType( siteType );
|
||||
siteTypeButton.setTag( siteType );
|
||||
siteTypeButton.setText( siteType.getShortName() );
|
||||
MPResultType resultType =
|
||||
allResultTypes.get( (allResultTypes.indexOf( resultTypeButton.getTag() ) + 1) % allResultTypes.size() );
|
||||
preferences.setDefaultResultType( resultType );
|
||||
resultTypeButton.setTag( resultType );
|
||||
resultTypeButton.setText( resultType.getShortName() );
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
@@ -156,7 +154,7 @@ public class EmergencyActivity extends Activity {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
@SuppressWarnings("SuspiciousMethodCalls")
|
||||
MasterKey.Version siteVersion =
|
||||
MPMasterKey.Version siteVersion =
|
||||
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
|
||||
preferences.setDefaultVersion( siteVersion );
|
||||
siteVersionButton.setTag( siteVersion );
|
||||
@@ -213,17 +211,17 @@ public class EmergencyActivity extends Activity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
// FIXME: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
|
||||
fullNameField.setText( preferences.getFullName() );
|
||||
rememberFullNameField.setChecked( preferences.isRememberFullName() );
|
||||
forgetPasswordField.setChecked( preferences.isForgetPassword() );
|
||||
maskPasswordField.setChecked( preferences.isMaskPassword() );
|
||||
sitePasswordField.setTransformationMethod( preferences.isMaskPassword()? new PasswordTransformationMethod(): null );
|
||||
MPSiteType defaultSiteType = preferences.getDefaultSiteType();
|
||||
siteTypeButton.setTag( defaultSiteType );
|
||||
siteTypeButton.setText( defaultSiteType.getShortName() );
|
||||
MasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
||||
MPResultType defaultResultType = preferences.getDefaultResultType();
|
||||
resultTypeButton.setTag( defaultResultType );
|
||||
resultTypeButton.setText( defaultResultType.getShortName() );
|
||||
MPMasterKey.Version defaultVersion = preferences.getDefaultVersion();
|
||||
siteVersionButton.setTag( defaultVersion );
|
||||
siteVersionButton.setText( defaultVersion.name() );
|
||||
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
|
||||
@@ -241,10 +239,8 @@ public class EmergencyActivity extends Activity {
|
||||
if (preferences.isForgetPassword()) {
|
||||
synchronized (this) {
|
||||
id_userName = id_masterPassword = 0;
|
||||
if (masterKeyFuture != null) {
|
||||
masterKeyFuture.cancel( true );
|
||||
masterKeyFuture = null;
|
||||
}
|
||||
if (masterKey != null)
|
||||
masterKey = null;
|
||||
|
||||
masterPasswordField.setText( "" );
|
||||
}
|
||||
@@ -260,23 +256,17 @@ public class EmergencyActivity extends Activity {
|
||||
private synchronized void updateMasterKey() {
|
||||
final String fullName = fullNameField.getText().toString();
|
||||
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||
final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
|
||||
if ((id_userName == fullName.hashCode())
|
||||
&& (id_masterPassword == Arrays.hashCode( masterPassword ))
|
||||
&& (id_version == version.ordinal()))
|
||||
if ((masterKeyFuture != null) && !masterKeyFuture.isCancelled())
|
||||
&& (id_masterPassword == Arrays.hashCode( masterPassword )))
|
||||
if (masterKey != null)
|
||||
return;
|
||||
|
||||
id_userName = fullName.hashCode();
|
||||
id_masterPassword = Arrays.hashCode( masterPassword );
|
||||
id_version = version.ordinal();
|
||||
|
||||
if (preferences.isRememberFullName())
|
||||
preferences.setFullName( fullName );
|
||||
|
||||
if (masterKeyFuture != null)
|
||||
masterKeyFuture.cancel( true );
|
||||
|
||||
if (fullName.isEmpty() || (masterPassword.length == 0)) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
@@ -285,43 +275,21 @@ public class EmergencyActivity extends Activity {
|
||||
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.VISIBLE );
|
||||
(masterKeyFuture = executor.submit( new Callable<MasterKey>() {
|
||||
@Override
|
||||
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 );
|
||||
masterKey = new MPMasterKey( fullName, masterPassword );
|
||||
updateSitePassword();
|
||||
}
|
||||
|
||||
private void updateSitePassword() {
|
||||
final String siteName = siteNameField.getText().toString();
|
||||
final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
|
||||
final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
|
||||
final String siteName = siteNameField.getText().toString();
|
||||
final MPResultType type = (MPResultType) resultTypeButton.getTag();
|
||||
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( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
|
||||
if (masterKeyFuture == null)
|
||||
if (masterKey == null)
|
||||
updateMasterKey();
|
||||
return;
|
||||
}
|
||||
@@ -332,7 +300,7 @@ public class EmergencyActivity extends Activity {
|
||||
@Override
|
||||
public void run() {
|
||||
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() {
|
||||
@Override
|
||||
@@ -342,16 +310,10 @@ public class EmergencyActivity extends Activity {
|
||||
}
|
||||
} );
|
||||
}
|
||||
catch (final InterruptedException ignored) {
|
||||
catch (final MPInvalidatedException ignored) {
|
||||
sitePasswordField.setText( "" );
|
||||
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) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
@@ -363,10 +325,9 @@ public class EmergencyActivity extends Activity {
|
||||
}
|
||||
|
||||
public void integrityTests(final View view) {
|
||||
if (masterKeyFuture != null) {
|
||||
masterKeyFuture.cancel( true );
|
||||
masterKeyFuture = null;
|
||||
}
|
||||
if (masterKey != null)
|
||||
masterKey = null;
|
||||
|
||||
TestActivity.startNoSkip( this );
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class Preferences {
|
||||
private static final String PREF_FORGET_PASSWORD = "forgetPassword";
|
||||
private static final String PREF_MASK_PASSWORD = "maskPassword";
|
||||
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 Preferences instance;
|
||||
|
||||
@@ -74,7 +74,7 @@ public final class Preferences {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -138,20 +138,20 @@ public final class Preferences {
|
||||
return prefs().getString( PREF_FULL_NAME, "" );
|
||||
}
|
||||
|
||||
public boolean setDefaultSiteType(@Nonnull final MPSiteType value) {
|
||||
if (getDefaultSiteType() == value)
|
||||
public boolean setDefaultResultType(final MPResultType value) {
|
||||
if (getDefaultResultType() == value)
|
||||
return false;
|
||||
|
||||
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
|
||||
prefs().edit().putInt( PREF_RESULT_TYPE, value.ordinal() ).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MPSiteType getDefaultSiteType() {
|
||||
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
|
||||
public MPResultType getDefaultResultType() {
|
||||
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)
|
||||
return false;
|
||||
|
||||
@@ -160,7 +160,7 @@ public final class Preferences {
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public MasterKey.Version getDefaultVersion() {
|
||||
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )];
|
||||
public MPMasterKey.Version getDefaultVersion() {
|
||||
return MPMasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MPMasterKey.Version.CURRENT.ordinal() )];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
||||
@Override
|
||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean 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)
|
||||
testFuture.cancel( true );
|
||||
|
||||
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
// TODO: MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
|
||||
|
||||
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
||||
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
android:id="@id/sitePasswordField"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:nextFocusForward="@+id/siteTypeButton"
|
||||
android:nextFocusForward="@+id/resultTypeButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textColor="#FFFFFF"
|
||||
@@ -157,7 +157,7 @@
|
||||
android:gravity="center">
|
||||
|
||||
<Button
|
||||
android:id="@id/siteTypeButton"
|
||||
android:id="@id/resultTypeButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
@@ -175,12 +175,12 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:labelFor="@id/siteTypeButton"
|
||||
android:labelFor="@id/resultTypeButton"
|
||||
android:gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:text="@string/siteType_hint" />
|
||||
android:text="@string/resultType_hint" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<string name="masterPassword_hint">Your master password</string>
|
||||
<string name="siteName_hint">eg. google.com</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="siteVersion_hint">Algorithm</string>
|
||||
<string name="empty" />
|
||||
|
||||
2
platform-darwin/External/Pearl
vendored
2
platform-darwin/External/Pearl
vendored
Submodule platform-darwin/External/Pearl updated: f513a4a63c...b713577cd6
@@ -20,7 +20,6 @@
|
||||
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D39D8508BF868907E9732E /* PearlHangDetector.h */; };
|
||||
93D39392DEDA376F93C6C718 /* MPCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39BAA71DE51B4D8A1286C /* MPCell.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 */; };
|
||||
93D3942C1B117EE4851AA7B6 /* UIView+Visible.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3952910EDB8E0EBC94BA9 /* UIView+Visible.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 */; };
|
||||
93D3957237D303DE2D38C267 /* MPAvatarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39B381350802A194BF332 /* MPAvatarCell.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 */; };
|
||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.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 */; };
|
||||
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3995B1D4DCE5A30D882BA /* MPCoachmarkViewController.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 */; };
|
||||
93D39861AEE621B287EA93E9 /* PearlLinks.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D399C408B705172FA0FA02 /* PearlLinks.h */; };
|
||||
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39ACBA9F4878B6A1CC33B /* MPEmergencyViewController.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 */; };
|
||||
@@ -134,8 +130,6 @@
|
||||
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2C3D641BD9612F001137B3 /* libz.tbd */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
DA2CA4E618D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2CA4E518D2AC10007798F8 /* NSLayoutConstraint+PearlUIKit.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 */; };
|
||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3509FC15F101A500C14A8E /* PearlQueue.h */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -175,7 +168,6 @@
|
||||
DA45224A190628A1008F650A /* icon_wrench@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD386B1711E29700CF925C /* icon_wrench@2x.png */; };
|
||||
DA45224B190628B2008F650A /* icon_gear.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37821711E29500CF925C /* icon_gear.png */; };
|
||||
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD37831711E29500CF925C /* icon_gear@2x.png */; };
|
||||
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */; };
|
||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
||||
DA4DA1DA1564471F00F6F596 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
|
||||
DA5A09DF171A70E4005284AB /* play.png in Resources */ = {isa = PBXBuildFile; fileRef = DA5A09DD171A70E4005284AB /* play.png */; };
|
||||
@@ -212,7 +204,6 @@
|
||||
DA92614E1BE1A57500369DE5 /* MPAppDelegate_InApp.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92614D1BE1A57500369DE5 /* MPAppDelegate_InApp.m */; };
|
||||
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, ); }; };
|
||||
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA95B50E1C4776F00067F5EF /* NSMutableSet+Pearl.m */; };
|
||||
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */; };
|
||||
DAA141201922FF020032B392 /* PearlTween.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA1411C1922FF020032B392 /* PearlTween.m */; };
|
||||
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 */; };
|
||||
DAA1765319D8B82B0044227B /* choose_type@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763D19D8B82B0044227B /* choose_type@2x.png */; };
|
||||
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
|
||||
DAA449D21EEC4B5800E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAB7AE761F3D755B00C856B1 /* libjson-c.a */; };
|
||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */; };
|
||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshal-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */; };
|
||||
DABB981615100B4000B05417 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DABB981515100B4000B05417 /* SystemConfiguration.framework */; };
|
||||
DABD39371711E29700CF925C /* avatar-0.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366C1711E29400CF925C /* avatar-0.png */; };
|
||||
DABD39381711E29700CF925C /* avatar-0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DABD366D1711E29400CF925C /* avatar-0@2x.png */; };
|
||||
@@ -349,7 +355,6 @@
|
||||
DAC77CAE148291A600BCF976 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
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 */; };
|
||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DACA29711705E1A8002C6C22 /* ciphers.plist */; };
|
||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */ = {isa = PBXBuildFile; fileRef = DACA29721705E1A8002C6C22 /* dictionary.lst */; };
|
||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -512,7 +516,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -540,7 +543,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -582,7 +584,6 @@
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
@@ -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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -790,7 +789,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -871,9 +869,22 @@
|
||||
DAA1763C19D8B82B0044227B /* copy_pw.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = copy_pw.png; sourceTree = "<group>"; };
|
||||
DAA1763D19D8B82B0044227B /* choose_type@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "choose_type@2x.png"; sourceTree = "<group>"; };
|
||||
DAA1763E19D8B82B0044227B /* choose_type.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = choose_type.png; sourceTree = "<group>"; };
|
||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
|
||||
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
|
||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; 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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -896,8 +907,8 @@
|
||||
DAB7AE731F3D755B00C856B1 /* strdup_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdup_compat.h; sourceTree = "<group>"; };
|
||||
DAB7AE741F3D755B00C856B1 /* vasprintf_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vasprintf_compat.h; sourceTree = "<group>"; };
|
||||
DAB7AE761F3D755B00C856B1 /* libjson-c.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libjson-c.a"; sourceTree = "<group>"; };
|
||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; };
|
||||
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall-util.c"; sourceTree = "<group>"; };
|
||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; 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; };
|
||||
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>"; };
|
||||
@@ -1511,7 +1522,7 @@
|
||||
DABD38C11711E29700CF925C /* tip_location_teal@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_teal@2x.png"; sourceTree = "<group>"; };
|
||||
DABD38C21711E29700CF925C /* tip_location_wood.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tip_location_wood.png; sourceTree = "<group>"; };
|
||||
DABD38C31711E29700CF925C /* tip_location_wood@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tip_location_wood@2x.png"; sourceTree = "<group>"; };
|
||||
DABD38C81711E29700CF925C /* jquery-1.6.1.min.js */ = {isa = PBXFileReference; fileEncoding = 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>"; };
|
||||
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>"; };
|
||||
@@ -1562,8 +1573,6 @@
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -1680,7 +1689,6 @@
|
||||
DA95B50C1C476B6A0067F5EF /* LocalAuthentication.framework in Frameworks */,
|
||||
DA2C3D651BD9612F001137B3 /* libz.tbd in Frameworks */,
|
||||
DA2C3D631BD96126001137B3 /* libc++.tbd in Frameworks */,
|
||||
DAB7AE771F3D755B00C856B1 /* libjson-c.a in Frameworks */,
|
||||
DAA1761B19D86D0D0044227B /* libAttributedMarkdown.a in Frameworks */,
|
||||
DA0CC5421EB57BD4009A8ED9 /* Crashlytics.framework in Frameworks */,
|
||||
DA32D03E19D11293004F3F0E /* libKCOrderedAccessorFix.a in Frameworks */,
|
||||
@@ -1751,6 +1759,8 @@
|
||||
93D39A2239FFFE6BEC83E191 /* C */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAB07C9B1F7725C500CC6D43 /* aes.c */,
|
||||
DAB07C9C1F7725C500CC6D43 /* aes.h */,
|
||||
DA5B0B3E1F36469400B663F0 /* base64.c */,
|
||||
DA5B0B3F1F36469400B663F0 /* base64.h */,
|
||||
93D390A99850139D0FF0211E /* mpw-algorithm_v0.c */,
|
||||
@@ -1759,10 +1769,10 @@
|
||||
93D39D4E713564B7654341B0 /* mpw-algorithm_v3.c */,
|
||||
93D3969393A3A46BD27D7078 /* mpw-algorithm.c */,
|
||||
93D3990D850D76A94C6B7A4D /* mpw-algorithm.h */,
|
||||
DAB7AE981F3DDEE000C856B1 /* mpw-marshall-util.c */,
|
||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshall-util.h */,
|
||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshall.c */,
|
||||
DAA449D11EEC4B5800E7BDD5 /* mpw-marshall.h */,
|
||||
DAB7AE981F3DDEE000C856B1 /* mpw-marshal-util.c */,
|
||||
DAB7AE971F3DDEE000C856B1 /* mpw-marshal-util.h */,
|
||||
DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */,
|
||||
DAA449D11EEC4B5800E7BDD5 /* mpw-marshal.h */,
|
||||
93D392C5A6572DB0EB5B82C8 /* mpw-types.c */,
|
||||
93D39AFD17CBE324D745DAB0 /* mpw-types.h */,
|
||||
93D396C311C3725870343EE0 /* mpw-util.c */,
|
||||
@@ -2993,7 +3003,6 @@
|
||||
93D39F556F2F142740A65E59 /* MPWebViewController.h */,
|
||||
93D3990E0CD1B5CF9FBB2C07 /* MPWebViewController.m */,
|
||||
DABD3BF91711E2DC00CF925C /* Settings.bundle */,
|
||||
DA38D6A218CCB5BF009AEB3E /* Storyboard.storyboard */,
|
||||
);
|
||||
path = iOS;
|
||||
sourceTree = "<group>";
|
||||
@@ -3004,7 +3013,7 @@
|
||||
DAFE45D715039823003ABA7C /* Pearl */,
|
||||
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
||||
DAFE460715039823003ABA7C /* Pearl-UIKit */,
|
||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
|
||||
DAB4FBDB202FDE5E002768FB /* Pearl-Prefix.pch */,
|
||||
);
|
||||
path = Pearl;
|
||||
sourceTree = "<group>";
|
||||
@@ -3039,7 +3048,6 @@
|
||||
DACA29701705E1A8002C6C22 /* Data */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DACA29711705E1A8002C6C22 /* ciphers.plist */,
|
||||
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
||||
);
|
||||
path = Data;
|
||||
@@ -3091,6 +3099,8 @@
|
||||
93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */,
|
||||
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */,
|
||||
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */,
|
||||
DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */,
|
||||
DAB4FBC3202FDDDD002768FB /* NSInvocation+Pearl.m */,
|
||||
DAF4EF4F190A81E400023C90 /* NSManagedObject+Pearl.h */,
|
||||
DAF4EF4E190A81E400023C90 /* NSManagedObject+Pearl.m */,
|
||||
DA95B50D1C4776F00067F5EF /* NSMutableSet+Pearl.h */,
|
||||
@@ -3100,14 +3110,14 @@
|
||||
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */,
|
||||
DAFE4A63150399FF003ABA87 /* NSObject+PearlKVO.h */,
|
||||
DAFE4A63150399FF003ABA85 /* NSObject+PearlKVO.m */,
|
||||
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
|
||||
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
|
||||
93D397F4BAFFF7CF3F1B21A4 /* NSPersistentStore+PearlMigration.h */,
|
||||
93D399C2F3D48E57C4803BDC /* NSPersistentStore+PearlMigration.m */,
|
||||
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */,
|
||||
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
||||
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
||||
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
||||
DA2CA4DC18D28859007798F8 /* NSTimer+PearlBlock.h */,
|
||||
DA2CA4DB18D28859007798F8 /* NSTimer+PearlBlock.m */,
|
||||
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
||||
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
||||
@@ -3118,6 +3128,8 @@
|
||||
DAFE45E615039823003ABA7C /* PearlConfig.m */,
|
||||
DAFE45E715039823003ABA7C /* PearlDeviceUtils.h */,
|
||||
DAFE45E815039823003ABA7C /* PearlDeviceUtils.m */,
|
||||
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
|
||||
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
|
||||
DAFE45E915039823003ABA7C /* PearlInfoPlist.h */,
|
||||
DAFE45EA15039823003ABA7C /* PearlInfoPlist.m */,
|
||||
DA30E9D515723E6900A68B4C /* PearlLazy.h */,
|
||||
@@ -3141,10 +3153,6 @@
|
||||
DAA1411C1922FF020032B392 /* PearlTween.m */,
|
||||
DAFE45F815039823003ABA7C /* README */,
|
||||
DAFE45F915039823003ABA7C /* Resources */,
|
||||
93D39FBF8FCEB4C106272334 /* NSOrderedSetOrArray.h */,
|
||||
93D39789AAF49338F8AC8B02 /* NSOrderedSetOrArray.m */,
|
||||
93D39BDA5DB85FCDE4E6450A /* PearlHangDetector.m */,
|
||||
93D39D8508BF868907E9732E /* PearlHangDetector.h */,
|
||||
);
|
||||
path = Pearl;
|
||||
sourceTree = "<group>";
|
||||
@@ -3193,6 +3201,8 @@
|
||||
DA32D01819D046E1004F3F0E /* PearlFixedTableView.m */,
|
||||
DAFE461015039823003ABA7C /* PearlGradientView.h */,
|
||||
DAFE461115039823003ABA7C /* PearlGradientView.m */,
|
||||
DAB4FBCE202FDE47002768FB /* PearlLinks.h */,
|
||||
DAB4FBCB202FDE47002768FB /* PearlLinks.m */,
|
||||
DAFE461615039823003ABA7C /* PearlMessageView.h */,
|
||||
DAFE461715039823003ABA7C /* PearlMessageView.m */,
|
||||
DACE2F6919BA6A2A0010F92E /* PearlMutableStaticTableViewController.h */,
|
||||
@@ -3245,14 +3255,16 @@
|
||||
DACE2F6719BA6A2A0010F92E /* UIView+FontScale.m */,
|
||||
DAEFB01D19BCBD9E00525079 /* UIView+LayoutGone.h */,
|
||||
DAEFB01C19BCBD9E00525079 /* UIView+LayoutGone.m */,
|
||||
DAB4FBCC202FDE47002768FB /* UIView+PearlLayout.h */,
|
||||
DAB4FBCF202FDE47002768FB /* UIView+PearlLayout.m */,
|
||||
DAB4FBCD202FDE47002768FB /* UIView+PearlSize.h */,
|
||||
DAB4FBD1202FDE48002768FB /* UIView+PearlSize.m */,
|
||||
DAEC85B418E3DD9A007FC0DF /* UIView+Touches.h */,
|
||||
DAEC85B118E3DD9A007FC0DF /* UIView+Touches.m */,
|
||||
93D39488AB33616661725929 /* UIView+AlphaScale.m */,
|
||||
93D392D76C091DEA3319F11D /* UIView+AlphaScale.h */,
|
||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
|
||||
93D39B7B765546B1F1900CB7 /* UIView+Visible.h */,
|
||||
93D39FEFC296AF6E7DF8E468 /* PearlLinks.m */,
|
||||
93D399C408B705172FA0FA02 /* PearlLinks.h */,
|
||||
93D3952910EDB8E0EBC94BA9 /* UIView+Visible.m */,
|
||||
DAB4FBD0202FDE47002768FB /* WTFViews.h */,
|
||||
DAB4FBD2202FDE48002768FB /* WTFViews.m */,
|
||||
);
|
||||
path = "Pearl-UIKit";
|
||||
sourceTree = "<group>";
|
||||
@@ -3295,10 +3307,12 @@
|
||||
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
||||
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
||||
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
||||
DAB4FBD8202FDE48002768FB /* WTFViews.h in Headers */,
|
||||
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
||||
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
||||
DAFE4A2415039824003ABA7C /* PearlInfoPlist.h in Headers */,
|
||||
DA2CA4E418D28866007798F8 /* NSLayoutConstraint+PearlUIKit.h in Headers */,
|
||||
DAB4FBD5202FDE48002768FB /* UIView+PearlSize.h in Headers */,
|
||||
DACE2F6D19BA6A2A0010F92E /* PearlMutableStaticTableViewController.h in Headers */,
|
||||
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
||||
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
||||
@@ -3307,13 +3321,13 @@
|
||||
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
||||
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
||||
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
||||
DA2CA4E018D28859007798F8 /* NSTimer+PearlBlock.h in Headers */,
|
||||
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
||||
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
||||
DAE2726419CE9CB3007C5262 /* UITableViewCell+PearlDeque.h in Headers */,
|
||||
DACE2F6E19BA6A2A0010F92E /* UIView+FontScale.h in Headers */,
|
||||
DA32D01B19D046E1004F3F0E /* PearlFixedTableView.h in Headers */,
|
||||
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */,
|
||||
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */,
|
||||
DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
|
||||
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
|
||||
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
|
||||
@@ -3321,9 +3335,11 @@
|
||||
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
|
||||
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
|
||||
DAFE4A4415039824003ABA7C /* PearlGradientView.h in Headers */,
|
||||
DAB4FBC6202FDDEC002768FB /* NSMutableSet+Pearl.h in Headers */,
|
||||
DAFE4A4A15039824003ABA7C /* PearlMessageView.h in Headers */,
|
||||
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
|
||||
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
|
||||
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */,
|
||||
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
|
||||
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
|
||||
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
|
||||
@@ -3341,6 +3357,7 @@
|
||||
DA2CA4DE18D28859007798F8 /* NSArray+Pearl.h in Headers */,
|
||||
93D392EC39DA43C46C692C12 /* NSDictionary+Indexing.h in Headers */,
|
||||
93D3932889B6B4206E66A6D6 /* PearlEMail.h in Headers */,
|
||||
DAB4FBC8202FDDF3002768FB /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
||||
DA3509FE15F101A500C14A8E /* PearlQueue.h in Headers */,
|
||||
DAEC85B718E3DD9A007FC0DF /* PearlUINavigationBar.h in Headers */,
|
||||
93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */,
|
||||
@@ -3353,12 +3370,12 @@
|
||||
93D39536EB550E811CCD04BC /* UIResponder+PearlFirstResponder.h in Headers */,
|
||||
93D393DB5325820241BA90A7 /* PearlSizedTextView.h in Headers */,
|
||||
93D392A8777DC30C11361647 /* UITextView+PearlAttributes.h in Headers */,
|
||||
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */,
|
||||
93D39A53D76CA70786423458 /* UICollectionView+PearlReloadItems.h in Headers */,
|
||||
93D39AA4A0BE66A872CCC02E /* NSPersistentStore+PearlMigration.h in Headers */,
|
||||
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
|
||||
93D3959696396A91961C6148 /* UIView+AlphaScale.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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -3527,15 +3544,15 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = MP;
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0920;
|
||||
ORGANIZATIONNAME = Lyndir;
|
||||
TargetAttributes = {
|
||||
DA32D01F19D111C6004F3F0E = {
|
||||
CreatedOnToolsVersion = 6.0;
|
||||
DevelopmentTeam = HL3Q45LX9N;
|
||||
};
|
||||
DA5BFA43147E415C00F98B1E = {
|
||||
DevelopmentTeam = HL3Q45LX9N;
|
||||
LastSwiftMigration = 0920;
|
||||
ProvisioningStyle = Automatic;
|
||||
SystemCapabilities = {
|
||||
com.apple.BackgroundModes = {
|
||||
@@ -3553,7 +3570,6 @@
|
||||
};
|
||||
};
|
||||
DAA1757C19D86BE70044227B = {
|
||||
CreatedOnToolsVersion = 6.0;
|
||||
DevelopmentTeam = HL3Q45LX9N;
|
||||
};
|
||||
DAB7AE3D1F3D464A00C856B1 = {
|
||||
@@ -3699,7 +3715,6 @@
|
||||
files = (
|
||||
DAFE4A5A1503982E003ABA7C /* Pearl.strings in Resources */,
|
||||
DA0CC53B1EB57B5C009A8ED9 /* Fabric.plist in Resources */,
|
||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
|
||||
DA32D04F19D2F59B004F3F0E /* meter_fuel@2x.png in Resources */,
|
||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||
DA45224C190628B2008F650A /* icon_gear@2x.png in Resources */,
|
||||
@@ -3869,7 +3884,6 @@
|
||||
DA8495311A93049300B3053D /* icon_down.png in Resources */,
|
||||
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
|
||||
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
|
||||
DA38D6A318CCB5BF009AEB3E /* Storyboard.storyboard in Resources */,
|
||||
DA5A09DF171A70E4005284AB /* play.png in Resources */,
|
||||
DA24EBEC19DAD6EE00FF010B /* Icon-Small@3x.png in Resources */,
|
||||
DA5A09E0171A70E4005284AB /* play@2x.png in Resources */,
|
||||
@@ -3970,7 +3984,7 @@
|
||||
DABD3C151711E2DC00CF925C /* MPiOSAppDelegate.m in Sources */,
|
||||
DA0CC5941EB6B030009A8ED9 /* MPSiteEntity+CoreDataClass.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 */,
|
||||
DABD3C1F1711E2DC00CF925C /* MPTypeViewController.m in Sources */,
|
||||
DABD3C211711E2DC00CF925C /* MPiOSConfig.m in Sources */,
|
||||
@@ -3988,8 +4002,7 @@
|
||||
DA0CC58E1EB6B030009A8ED9 /* MPSiteQuestionEntity+CoreDataClass.m in Sources */,
|
||||
93D39A5FF670957C0AF8298D /* MPSiteCell.m in Sources */,
|
||||
93D398ECD7D1A0DEDDADF516 /* MPEmergencyViewController.m in Sources */,
|
||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshall-util.c in Sources */,
|
||||
DA95B50F1C4776F00067F5EF /* NSMutableSet+Pearl.m in Sources */,
|
||||
DAB7AE991F3DDEE000C856B1 /* mpw-marshal-util.c in Sources */,
|
||||
93D394B5036C882B33C71872 /* MPSitesSegue.m in Sources */,
|
||||
DA0CC5911EB6B030009A8ED9 /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
||||
93D39673DDC085BE72C34D7C /* MPPopdownSegue.m in Sources */,
|
||||
@@ -3998,12 +4011,12 @@
|
||||
93D396D8B67DA6522CDBA142 /* MPCoachmarkViewController.m in Sources */,
|
||||
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */,
|
||||
DA0CC54E1EB6AD0E009A8ED9 /* MasterPassword.xcdatamodeld in Sources */,
|
||||
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */,
|
||||
93D39EAA4D064193074D3021 /* MPFixable.m in Sources */,
|
||||
93D394982CBD25D46692DD7C /* MPWebViewController.m in Sources */,
|
||||
93D39D8F78978196D6ABDEDE /* MPNavigationController.m in Sources */,
|
||||
93D3939661CE37180AF7CD6A /* MPStoreViewController.m in Sources */,
|
||||
93D390C1B93F9D3AE37DD0A5 /* MPAnswersViewController.m in Sources */,
|
||||
DA45711D1F572F1E00D54152 /* PearlCryptUtils.m in Sources */,
|
||||
93D399D7E08A142776A74CB8 /* MPOverlayViewController.m in Sources */,
|
||||
93D39A27F2506C6FEEF9C588 /* MPAlgorithmV2.m in Sources */,
|
||||
93D39B429C67A62E29DC02DA /* MPRootSegue.m in Sources */,
|
||||
@@ -4100,24 +4113,28 @@
|
||||
93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */,
|
||||
DAF4EF50190A81E400023C90 /* NSManagedObject+Pearl.m in Sources */,
|
||||
93D39262A8A97DB748213309 /* PearlEMail.m in Sources */,
|
||||
DAB4FBD9202FDE48002768FB /* UIView+PearlSize.m in Sources */,
|
||||
DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */,
|
||||
DAB4FBDA202FDE48002768FB /* WTFViews.m in Sources */,
|
||||
DAB4FBC7202FDDEF002768FB /* NSMutableSet+Pearl.m in Sources */,
|
||||
93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */,
|
||||
DA32D01A19D046E1004F3F0E /* PearlFixedTableView.m in Sources */,
|
||||
93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */,
|
||||
93D397952F5635C793C24DF1 /* NSError+PearlFullDescription.m in Sources */,
|
||||
DA2CA4DF18D28859007798F8 /* NSTimer+PearlBlock.m in Sources */,
|
||||
93D3954E96236384AFA00453 /* UIScrollView+PearlAdjustInsets.m in Sources */,
|
||||
DAB4FBCA202FDE13002768FB /* PearlCryptUtils.m in Sources */,
|
||||
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
|
||||
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
|
||||
DAA141201922FF020032B392 /* PearlTween.m in Sources */,
|
||||
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */,
|
||||
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
|
||||
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */,
|
||||
93D39E34FD28D24FE3442C48 /* UITextView+PearlAttributes.m in Sources */,
|
||||
93D39D47FC623E91FC39D20C /* UICollectionView+PearlReloadItems.m in Sources */,
|
||||
93D3928D629EA563F9EC4909 /* NSPersistentStore+PearlMigration.m in Sources */,
|
||||
93D392A33CCE85431E910C7B /* NSOrderedSetOrArray.m in Sources */,
|
||||
93D393AA69A1193401160418 /* UIView+AlphaScale.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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -4215,11 +4232,19 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
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_STRCPY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
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_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -4230,19 +4255,25 @@
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = 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_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@@ -4253,6 +4284,10 @@
|
||||
"NDEBUG=1",
|
||||
"NS_BLOCK_ASSERTIONS=1",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_UIKIT,
|
||||
PEARL_CRYPTO,
|
||||
PEARL_WITH_MESSAGEUI,
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
@@ -4275,7 +4310,7 @@
|
||||
GCC_WARN_SIGN_COMPARE = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
@@ -4288,6 +4323,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||
@@ -4295,6 +4331,7 @@
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
STRIP_SWIFT_SYMBOLS = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||
@@ -4310,16 +4347,17 @@
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = NO;
|
||||
CODE_SIGN_ENTITLEMENTS = Source/iOS/MasterPassword.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
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",
|
||||
@@ -4332,7 +4370,10 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lyndir.lhunath.MasterPassword;
|
||||
SKIP_INSTALL = NO;
|
||||
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;
|
||||
};
|
||||
@@ -4340,11 +4381,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
||||
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
"$(inherited)",
|
||||
);
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Test;
|
||||
};
|
||||
@@ -4403,10 +4446,18 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
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_STRCPY = 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_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -4417,19 +4468,26 @@
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = 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_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@@ -4440,6 +4498,10 @@
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_UIKIT,
|
||||
PEARL_CRYPTO,
|
||||
PEARL_WITH_MESSAGEUI,
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
@@ -4476,6 +4538,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
@@ -4483,6 +4546,8 @@
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
STRIP_SWIFT_SYMBOLS = NO;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||
};
|
||||
@@ -4493,11 +4558,19 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
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_STRCPY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
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_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -4508,19 +4581,25 @@
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = 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_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEVELOPMENT_TEAM = HL3Q45LX9N;
|
||||
DSTROOT = "/tmp/${PRODUCT_NAME}.dst";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
@@ -4531,6 +4610,10 @@
|
||||
"NDEBUG=1",
|
||||
"NS_BLOCK_ASSERTIONS=1",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_UIKIT,
|
||||
PEARL_CRYPTO,
|
||||
PEARL_WITH_MESSAGEUI,
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
@@ -4553,7 +4636,7 @@
|
||||
GCC_WARN_SIGN_COMPARE = NO;
|
||||
GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
@@ -4566,6 +4649,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||
@@ -4573,6 +4657,7 @@
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
STRIP_SWIFT_SYMBOLS = NO;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WARNING_CFLAGS = "-Wno-float-conversion";
|
||||
@@ -4592,44 +4677,12 @@
|
||||
"$(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;
|
||||
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;
|
||||
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;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/External/libsodium/libsodium-ios/lib",
|
||||
@@ -4642,6 +4695,49 @@
|
||||
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 = "-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;
|
||||
};
|
||||
name = Release;
|
||||
@@ -4820,11 +4916,13 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
||||
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
"$(inherited)",
|
||||
);
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "External/Pearl/Pearl-Bridging-Header.h";
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -4832,7 +4930,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
GCC_PREFIX_HEADER = "Source/Pearl/Pearl-Prefix.pch";
|
||||
GCC_PREFIX_HEADER = "External/Pearl/Pearl-Prefix.pch";
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
"$(inherited)",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
DA16B342170661E0000A0EAB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC632871486D95D0075AEA5 /* Security.framework */; };
|
||||
DA16B344170661EE000A0EAB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA16B343170661EE000A0EAB /* Cocoa.framework */; };
|
||||
DA16B345170661F2000A0EAB /* libPearl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC77CAD148291A600BCF976 /* libPearl.a */; };
|
||||
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -64,8 +64,6 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D115722EE500A68B4C /* Pearl-Crypto.m */; };
|
||||
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 */; };
|
||||
DA3B8456190FC89700246EEA /* MPFixable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3B8454190FC89700246EEA /* MPFixable.m */; };
|
||||
DA3BCFCD19BD09E0006B2681 /* SourceCodePro-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = DA3BCFCC19BD09E0006B2681 /* SourceCodePro-Regular.otf */; };
|
||||
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DA45711E1F572F3200D54152 /* PearlCryptUtils.m */; };
|
||||
DA4DA1D91564471A00F6F596 /* libjrswizzle.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6326C148680650075AEA5 /* libjrswizzle.a */; };
|
||||
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE921A7D8117003E5423 /* MPAlgorithmV3.m */; };
|
||||
DA4DAE951A7D8117003E5423 /* MPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4DAE931A7D8117003E5423 /* MPTypes.m */; };
|
||||
@@ -110,8 +107,8 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
DA7471A61F2B71B9005F3468 /* 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-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 */; };
|
||||
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */ = {isa = PBXBuildFile; fileRef = DA89D4EB1A51EABD00AC64D7 /* Pearl-Cocoa.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 */; };
|
||||
DA9261541BE1A88900369DE5 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261531BE1A88900369DE5 /* libc++.tbd */; };
|
||||
DA9261561BE1A89600369DE5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9261551BE1A89600369DE5 /* libz.tbd */; };
|
||||
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshall.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */; };
|
||||
DAA449D51EEC4B6B00E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */; };
|
||||
DAAA81B0195A8D1300FA30D9 /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = DAAA81AF195A8D1300FA30D9 /* gradient.png */; };
|
||||
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3E19FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h */; };
|
||||
DAADCC4819FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAADCC3F19FAFFAD00987B1D /* NSPersistentStore+PearlMigration.h */; };
|
||||
@@ -130,6 +127,20 @@
|
||||
DAADCC6919FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m in Sources */ = {isa = PBXBuildFile; fileRef = DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */; };
|
||||
DAADCC6A19FB00B500987B1D /* libKCOrderedAccessorFix.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAADCC5019FB006500987B1D /* libKCOrderedAccessorFix.a */; };
|
||||
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */ = {isa = PBXBuildFile; fileRef = DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -177,11 +188,9 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
DACA298D1705E2BD002C6C22 /* JRSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA29771705E2BD002C6C22 /* JRSwizzle.h */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -480,8 +489,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -950,8 +957,8 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall-util.h"; sourceTree = "<group>"; };
|
||||
DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; 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>"; };
|
||||
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>"; };
|
||||
@@ -966,8 +973,8 @@
|
||||
DA9261501BE1A86700369DE5 /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = "<group>"; };
|
||||
DA9261531BE1A88900369DE5 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
DA9261551BE1A89600369DE5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshall.c"; sourceTree = "<group>"; };
|
||||
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshall.h"; sourceTree = "<group>"; };
|
||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; 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>"; };
|
||||
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>"; };
|
||||
@@ -977,6 +984,15 @@
|
||||
DAADCC6719FB007F00987B1D /* NSManagedObjectModel+KCOrderedAccessorFix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSManagedObjectModel+KCOrderedAccessorFix.m"; sourceTree = "<group>"; };
|
||||
DAAF16631F5897EA0013B8AE /* mpw-cli-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-cli-util.c"; sourceTree = "<group>"; };
|
||||
DAAF16641F5897EA0013B8AE /* mpw-cli-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-cli-util.h"; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -1003,7 +1019,6 @@
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -1046,7 +1061,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@@ -1878,6 +1892,8 @@
|
||||
DA6773291A4746AF004F356A /* C */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAB07C9E1F7725D400CC6D43 /* aes.c */,
|
||||
DAB07C9F1F7725D400CC6D43 /* aes.h */,
|
||||
DA5B0B381F36467300B663F0 /* base64.c */,
|
||||
DA5B0B391F36467300B663F0 /* base64.h */,
|
||||
DA1C7AB71F1A8F6E009A3551 /* cli */,
|
||||
@@ -1887,10 +1903,10 @@
|
||||
DA831A2A1A6E1146000AC234 /* mpw-algorithm_v3.c */,
|
||||
DA6773BB1A4746AF004F356A /* mpw-algorithm.c */,
|
||||
DA6773BC1A4746AF004F356A /* mpw-algorithm.h */,
|
||||
DA7471A01F2B71A9005F3468 /* mpw-marshall-util.c */,
|
||||
DA7471A11F2B71A9005F3468 /* mpw-marshall-util.h */,
|
||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshall.c */,
|
||||
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshall.h */,
|
||||
DA7471A01F2B71A9005F3468 /* mpw-marshal-util.c */,
|
||||
DA7471A11F2B71A9005F3468 /* mpw-marshal-util.h */,
|
||||
DAA449D31EEC4B6B00E7BDD5 /* mpw-marshal.c */,
|
||||
DAA449D41EEC4B6B00E7BDD5 /* mpw-marshal.h */,
|
||||
DA6773C21A4746AF004F356A /* mpw-types.c */,
|
||||
DA6773C31A4746AF004F356A /* mpw-types.h */,
|
||||
DA6773C51A4746AF004F356A /* mpw-util.c */,
|
||||
@@ -1987,7 +2003,7 @@
|
||||
DAFE45D715039823003ABA7C /* Pearl */,
|
||||
DA89D4E51A51E53100AC64D7 /* Pearl-Cocoa */,
|
||||
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
|
||||
DAB4FBB3202FD60A002768FB /* Pearl-Prefix.pch */,
|
||||
);
|
||||
path = Pearl;
|
||||
sourceTree = "<group>";
|
||||
@@ -2095,7 +2111,6 @@
|
||||
DACA29701705E1A8002C6C22 /* Data */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DACA29711705E1A8002C6C22 /* ciphers.plist */,
|
||||
DACA29721705E1A8002C6C22 /* dictionary.lst */,
|
||||
);
|
||||
path = Data;
|
||||
@@ -2147,6 +2162,12 @@
|
||||
DAFE45D715039823003ABA7C /* Pearl */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DAB4FBDF202FF93D002768FB /* NSInvocation+Pearl.h */,
|
||||
DAB4FBE0202FF93D002768FB /* NSInvocation+Pearl.m */,
|
||||
DAB4FBE1202FF93D002768FB /* NSOrderedSetOrArray.h */,
|
||||
DAB4FBE2202FF93D002768FB /* NSOrderedSetOrArray.m */,
|
||||
DAB4FBDD202FF93D002768FB /* PearlHangDetector.h */,
|
||||
DAB4FBDE202FF93D002768FB /* PearlHangDetector.m */,
|
||||
DA8ED893192906920099B726 /* include */,
|
||||
93D396D04E57792A54D437AC /* NSArray+Indexing.h */,
|
||||
93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */,
|
||||
@@ -2173,8 +2194,6 @@
|
||||
DAFE45DB15039823003ABA7C /* NSString+PearlNSArrayFormat.m */,
|
||||
DAFE45DC15039823003ABA7C /* NSString+PearlSEL.h */,
|
||||
DAFE45DD15039823003ABA7C /* NSString+PearlSEL.m */,
|
||||
DA2CA4EC18D323D3007798F8 /* NSTimer+PearlBlock.h */,
|
||||
DA2CA4EB18D323D3007798F8 /* NSTimer+PearlBlock.m */,
|
||||
DAFE45DE15039823003ABA7C /* Pearl.h */,
|
||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */,
|
||||
DAFE45DF15039823003ABA7C /* PearlAbstractStrings.h */,
|
||||
@@ -2250,15 +2269,16 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA89D4EC1A51EABD00AC64D7 /* Pearl-Cocoa.h in Headers */,
|
||||
DA2CA4F218D323D3007798F8 /* NSTimer+PearlBlock.h in Headers */,
|
||||
DAFE4A1315039824003ABA7C /* NSObject+PearlExport.h in Headers */,
|
||||
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
|
||||
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
|
||||
DA3B8453190FC86F00246EEA /* NSManagedObject+Pearl.h in Headers */,
|
||||
DA8ED897192906920099B726 /* map-macro.h in Headers */,
|
||||
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
|
||||
DAB4FBE9202FF94C002768FB /* NSMutableSet+Pearl.h in Headers */,
|
||||
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
|
||||
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
|
||||
DAB4FBE3202FF93E002768FB /* PearlHangDetector.h in Headers */,
|
||||
DAFE4A2015039824003ABA7C /* PearlConfig.h in Headers */,
|
||||
DAFE4A2215039824003ABA7C /* PearlDeviceUtils.h in Headers */,
|
||||
DA8ED896192906920099B726 /* PearlTween.h in Headers */,
|
||||
@@ -2266,13 +2286,16 @@
|
||||
DAFE4A2615039824003ABA7C /* PearlLogger.h in Headers */,
|
||||
DA2CA4F018D323D3007798F8 /* NSArray+Pearl.h in Headers */,
|
||||
DAFE4A2815039824003ABA7C /* PearlMathUtils.h in Headers */,
|
||||
DAB4FBE7202FF93E002768FB /* NSOrderedSetOrArray.h in Headers */,
|
||||
DAFE4A2A15039824003ABA7C /* PearlObjectUtils.h in Headers */,
|
||||
DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */,
|
||||
DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */,
|
||||
DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */,
|
||||
DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */,
|
||||
DAB4FBEB202FF975002768FB /* PearlCryptUtils.h in Headers */,
|
||||
DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */,
|
||||
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */,
|
||||
DAB4FBE5202FF93E002768FB /* NSInvocation+Pearl.h in Headers */,
|
||||
DAADCC4719FAFFAD00987B1D /* NSNotificationCenter+PearlEasyCleanup.h in Headers */,
|
||||
DAFE4A63150399FF003ABA88 /* NSObject+PearlKVO.h in Headers */,
|
||||
DAFE4A63150399FF003ABA94 /* NSDateFormatter+RFC3339.h in Headers */,
|
||||
@@ -2606,7 +2629,6 @@
|
||||
DACA27381705DF81002C6C22 /* menu-icon.png in Resources */,
|
||||
DACA29671705DF81002C6C22 /* SourceCodePro-ExtraLight.otf in Resources */,
|
||||
DACA29681705DF81002C6C22 /* SourceCodePro-Black.otf in Resources */,
|
||||
DACA29731705E1A8002C6C22 /* ciphers.plist in Resources */,
|
||||
DACA29741705E1A8002C6C22 /* dictionary.lst in Resources */,
|
||||
DA5E5D081724A667003798D8 /* MasterPassword.entitlements in Resources */,
|
||||
DA5E5D0A1724A667003798D8 /* InfoPlist.strings in Resources */,
|
||||
@@ -2670,13 +2692,14 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA1C7AAA1F1A8F24009A3551 /* mpw-marshall.c in Sources */,
|
||||
DA1C7AAA1F1A8F24009A3551 /* mpw-marshal.c in Sources */,
|
||||
DA1C7AAB1F1A8F24009A3551 /* mpw-types.c in Sources */,
|
||||
DA5B0B3D1F36467900B663F0 /* base64.c in Sources */,
|
||||
DAB07CA31F77261400CC6D43 /* aes.c in Sources */,
|
||||
DAAF16661F5CA3240013B8AE /* mpw-cli-util.c in Sources */,
|
||||
DA1C7AAC1F1A8F24009A3551 /* mpw-util.c in Sources */,
|
||||
DA1C7AC31F1A8FBA009A3551 /* mpw-cli.c in Sources */,
|
||||
DA7471A31F2B71AE005F3468 /* mpw-marshall-util.c in Sources */,
|
||||
DA7471A31F2B71AE005F3468 /* mpw-marshal-util.c in Sources */,
|
||||
DA1C7AAD1F1A8F24009A3551 /* mpw-algorithm.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -2688,6 +2711,7 @@
|
||||
DA5B0B3C1F36467900B663F0 /* base64.c in Sources */,
|
||||
DA1C7ACA1F1A8FD8009A3551 /* mpw-types.c in Sources */,
|
||||
DA1C7ACB1F1A8FD8009A3551 /* mpw-util.c in Sources */,
|
||||
DAB07CA61F77262400CC6D43 /* aes.c in Sources */,
|
||||
DA1C7AD71F1A8FE6009A3551 /* mpw-bench.c in Sources */,
|
||||
DA1C7ACD1F1A8FD8009A3551 /* mpw-algorithm.c in Sources */,
|
||||
);
|
||||
@@ -2701,13 +2725,12 @@
|
||||
DA5E5CF61724A667003798D8 /* MPAlgorithm.m in Sources */,
|
||||
DA2686201EBFD7A40001E37E /* MPSiteEntity+CoreDataProperties.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 */,
|
||||
DA5E5CF81724A667003798D8 /* MPAlgorithmV1.m in Sources */,
|
||||
DA2686231EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataClass.m in Sources */,
|
||||
DA2686221EBFD7A40001E37E /* MPSiteQuestionEntity+CoreDataProperties.m in Sources */,
|
||||
DA4571201F572F3200D54152 /* PearlCryptUtils.m in Sources */,
|
||||
DACBFCDF1C59B22E007EF90F /* NSMutableSet+Pearl.m in Sources */,
|
||||
DAB07CA01F7725D400CC6D43 /* aes.c in Sources */,
|
||||
DA2686241EBFD7A40001E37E /* MPStoredSiteEntity+CoreDataProperties.m in Sources */,
|
||||
DA6774311A4746AF004F356A /* mpw-util.c in Sources */,
|
||||
DA5E5CF91724A667003798D8 /* MPAppDelegate_Key.m in Sources */,
|
||||
@@ -2738,7 +2761,7 @@
|
||||
DA4DAE941A7D8117003E5423 /* MPAlgorithmV3.m in Sources */,
|
||||
DA4DAE951A7D8117003E5423 /* MPTypes.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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -2749,6 +2772,7 @@
|
||||
files = (
|
||||
DA1C7AD81F1A8FF4009A3551 /* mpw-tests-util.c in Sources */,
|
||||
DA6774451A474A3B004F356A /* mpw-types.c in Sources */,
|
||||
DAB07CA51F77261C00CC6D43 /* aes.c in Sources */,
|
||||
DA6774461A474A3B004F356A /* mpw-util.c in Sources */,
|
||||
DA1C7AD91F1A8FF4009A3551 /* mpw-tests.c in Sources */,
|
||||
DA5B0B3B1F36467800B663F0 /* base64.c in Sources */,
|
||||
@@ -2778,6 +2802,7 @@
|
||||
files = (
|
||||
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
|
||||
DAADCC4919FAFFAD00987B1D /* NSPersistentStore+PearlMigration.m in Sources */,
|
||||
DAB4FBE8202FF93E002768FB /* NSOrderedSetOrArray.m in Sources */,
|
||||
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
|
||||
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
|
||||
DA2CA4ED18D323D3007798F8 /* NSError+PearlFullDescription.m in Sources */,
|
||||
@@ -2785,6 +2810,7 @@
|
||||
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
|
||||
DAFE4A2115039824003ABA7C /* PearlConfig.m in Sources */,
|
||||
DAFE4A2315039824003ABA7C /* PearlDeviceUtils.m in Sources */,
|
||||
DAB4FBE6202FF93E002768FB /* NSInvocation+Pearl.m in Sources */,
|
||||
DAFE4A2515039824003ABA7C /* PearlInfoPlist.m in Sources */,
|
||||
DAFE4A2715039824003ABA7C /* PearlLogger.m in Sources */,
|
||||
DA2C3D691BD9665B001137B3 /* PearlProfiler.m in Sources */,
|
||||
@@ -2795,12 +2821,14 @@
|
||||
DA89D4ED1A51EABD00AC64D7 /* Pearl-Cocoa.m in Sources */,
|
||||
DAFE4A3715039824003ABA7C /* PearlKeyChain.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 */,
|
||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */,
|
||||
DA30E9D215722EE500A68B4C /* Pearl-Crypto.m in Sources */,
|
||||
DA2CA4EF18D323D3007798F8 /* NSArray+Pearl.m in Sources */,
|
||||
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */,
|
||||
DAB4FBEA202FF951002768FB /* NSMutableSet+Pearl.m in Sources */,
|
||||
DAFE4A63150399FF003ABA86 /* NSObject+PearlKVO.m in Sources */,
|
||||
DAFE4A63150399FF003ABA92 /* NSDateFormatter+RFC3339.m in Sources */,
|
||||
93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */,
|
||||
@@ -2888,10 +2916,15 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = 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_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -2899,16 +2932,21 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = 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_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_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -2926,6 +2964,9 @@
|
||||
"NDEBUG=1",
|
||||
"NS_BLOCK_ASSERTIONS=1",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_COCOA,
|
||||
PEARL_CRYPTO,
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_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_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
@@ -3012,7 +3053,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
@@ -3048,7 +3089,7 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||
"/usr/include//libxml2",
|
||||
/usr/include/libxml2,
|
||||
"$(inherited)",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@@ -3231,10 +3272,14 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = 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_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -3242,16 +3287,21 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = 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_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_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -3268,6 +3318,10 @@
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_COCOA,
|
||||
PEARL_CRYPTO,
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
@@ -3289,12 +3343,12 @@
|
||||
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
@@ -3315,6 +3369,7 @@
|
||||
PUBLIC_HEADERS_FOLDER_PATH = include;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -3324,10 +3379,15 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = 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_CXX0X_EXTENSIONS = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
@@ -3335,16 +3395,21 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = 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_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_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_RECEIVER_WEAK = NO;
|
||||
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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
@@ -3362,6 +3427,9 @@
|
||||
"NDEBUG=1",
|
||||
"NS_BLOCK_ASSERTIONS=1",
|
||||
"CRASHLYTICS=1",
|
||||
PEARL,
|
||||
PEARL_COCOA,
|
||||
PEARL_CRYPTO,
|
||||
);
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_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_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
@@ -3482,7 +3550,7 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||
"/usr/include//libxml2",
|
||||
/usr/include/libxml2,
|
||||
"$(inherited)",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@@ -3502,7 +3570,7 @@
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/$(PLATFORM_NAME)/include\"",
|
||||
"/usr/include//libxml2",
|
||||
/usr/include/libxml2,
|
||||
"$(inherited)",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
@@ -3621,7 +3689,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
@@ -3634,7 +3702,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
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;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/External/Pearl/Pearl-Crypto/lib\"",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
LastUpgradeVersion = "0920"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@@ -45,6 +46,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "YES"
|
||||
customWorkingDirectory = "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/platform-independent/cli-c"
|
||||
|
||||
@@ -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>@&%?,=[]_:-+*$#!'^~;()/.</string>
|
||||
<key>x</key>
|
||||
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()</string>
|
||||
<key> </key>
|
||||
<string> </string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,11 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
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"
|
||||
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||
[[ -e "${prefix=$PWD/libjson-c-ios}/lib/libjson-c.a" ]] && exit
|
||||
|
||||
# Prepare
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||
rm -rf "${prefix=$PWD/libjson-c-ios}"
|
||||
mkdir -p "$prefix/lib" \
|
||||
"${prefix_i386=$prefix/tmp/i386}" \
|
||||
@@ -17,8 +22,8 @@ mkdir -p "$prefix/lib" \
|
||||
# Targets
|
||||
(
|
||||
## ARCH: i386
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
@@ -28,8 +33,8 @@ mkdir -p "$prefix/lib" \
|
||||
)
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
@@ -39,8 +44,8 @@ mkdir -p "$prefix/lib" \
|
||||
)
|
||||
(
|
||||
## ARCH: armv7
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
@@ -50,8 +55,8 @@ mkdir -p "$prefix/lib" \
|
||||
)
|
||||
(
|
||||
## ARCH: armv7s
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
@@ -61,8 +66,8 @@ mkdir -p "$prefix/lib" \
|
||||
)
|
||||
(
|
||||
## ARCH: arm64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
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"
|
||||
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||
[[ -e "${prefix=$PWD/libjson-c-osx}/lib/libjson-c.a" ]] && exit
|
||||
|
||||
# Prepare
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
autoreconf -Iautoconf-archive/m4 --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||
rm -rf "${prefix=$PWD/libjson-c-osx}"
|
||||
mkdir -p "$prefix"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g $CFLAGS" # -flto
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS" # -flto
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
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"
|
||||
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||
[[ -e "${prefix=$PWD/libsodium-ios}/lib/libsodium.a" ]] && exit
|
||||
|
||||
# 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}"
|
||||
mkdir -p "$prefix/lib" \
|
||||
"${prefix_i386=$prefix/tmp/i386}" \
|
||||
@@ -17,57 +22,57 @@ mkdir -p "$prefix/lib" \
|
||||
# Targets
|
||||
(
|
||||
## ARCH: i386
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch i386 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=i686-apple --disable-shared --prefix="$prefix_i386"
|
||||
./configure --host=i686-apple --disable-shared --enable-minimal --prefix="$prefix_i386"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --disable-shared --prefix="$prefix_x86_64"
|
||||
./configure --host=x86_64-apple --disable-shared --enable-minimal --prefix="$prefix_x86_64"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7"
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: armv7s
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch armv7s -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_armv7s"
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_armv7s"
|
||||
make -j3 install
|
||||
)
|
||||
(
|
||||
## ARCH: arm64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
|
||||
export CFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-mthumb -arch arm64 -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --prefix="$prefix_arm64"
|
||||
./configure --host=x86_64-apple --target=arm-apple --disable-shared --enable-minimal --prefix="$prefix_arm64"
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
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"
|
||||
[[ $1 = clean ]] && { [[ ! -e Makefile ]] || make -s distclean; exit; }
|
||||
[[ -e "${prefix=$PWD/libsodium-osx}/lib/libsodium.a" ]] && exit
|
||||
|
||||
# Inspired by libsodium/dist-build/osx.sh
|
||||
# Prepare
|
||||
autoreconf --verbose --install --symlink 2>&1 | sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /'
|
||||
autoreconf --verbose --install --symlink 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
|
||||
rm -rf "${prefix=$PWD/libsodium-osx}"
|
||||
mkdir -p "$prefix"
|
||||
|
||||
# Targets
|
||||
(
|
||||
## ARCH: x86_64
|
||||
export SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
|
||||
PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
|
||||
export CFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -O2 -g -flto $CFLAGS"
|
||||
export LDFLAGS="-arch x86_64 -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} -flto $LDFLAGS"
|
||||
export CPPFLAGS="$CFLAGS $CPPFLAGS"
|
||||
[[ -e Makefile ]] && make -s distclean
|
||||
./configure --disable-shared --prefix="$prefix"
|
||||
./configure --disable-shared --enable-minimal --prefix="$prefix"
|
||||
make -j3 check
|
||||
make -j3 install
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
+ (BOOL)managedObjectContextForMainThreadPerformBlockAndWait:(void ( ^ )(NSManagedObjectContext *mainContext))mocBlock;
|
||||
+ (BOOL)managedObjectContextPerformBlock:(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;
|
||||
- (void)deleteAndResetStore;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#import "MPAppDelegate_Store.h"
|
||||
#import "mpw-marshall.h"
|
||||
#import "mpw-marshal.h"
|
||||
#import "mpw-util.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
@@ -133,12 +133,11 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
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)
|
||||
return nil;
|
||||
|
||||
return PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, privateManagedObjectContextIfReady, nil,
|
||||
^(id host, NSNotification *note) {
|
||||
NSMutableDictionary *affectedObjects = [NSMutableDictionary new];
|
||||
@@ -217,7 +216,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
|
||||
self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||
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;
|
||||
else
|
||||
// When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext.
|
||||
@@ -566,10 +565,10 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
saveInContext:(NSManagedObjectContext *)context {
|
||||
|
||||
// Read metadata for the import file.
|
||||
MPMarshallInfo *info = mpw_marshall_read_info( importData.UTF8String );
|
||||
if (info->format == MPMarshallFormatNone)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
||||
@"type" : @(MPMarshallErrorFormat),
|
||||
MPMarshalInfo *info = mpw_marshal_read_info( importData.UTF8String );
|
||||
if (info->format == MPMarshalFormatNone)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(MPMarshalErrorFormat),
|
||||
NSLocalizedDescriptionKey: @"This is not a Master Password import file.",
|
||||
}]), @"While importing sites." );
|
||||
|
||||
@@ -589,13 +588,13 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
caseInsensitiveCompare:@(info->keyID)] != NSOrderedSame);
|
||||
|
||||
// Parse import data.
|
||||
MPMarshallError importError = { .type = MPMarshallSuccess };
|
||||
MPMarshalledUser *importUser = mpw_marshall_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
||||
MPMarshalError importError = { .type = MPMarshalSuccess };
|
||||
MPMarshalledUser *importUser = mpw_marshal_read( importData.UTF8String, info->format, importMasterPassword.UTF8String, &importError );
|
||||
mpw_marshal_info_free( &info );
|
||||
|
||||
@try {
|
||||
if (!importUser || importError.type != MPMarshallSuccess)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
||||
if (!importUser || importError.type != MPMarshalSuccess)
|
||||
return MPError( ([NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(importError.type),
|
||||
NSLocalizedDescriptionKey: @(importError.description),
|
||||
}]), @"While importing sites." );
|
||||
@@ -707,7 +706,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
NSString *masterPassword = askImportPassword( user.name );
|
||||
|
||||
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->avatar = (unsigned int)user.avatar;
|
||||
exportUser->defaultType = user.defaultType;
|
||||
@@ -721,7 +720,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
? [site.algorithm exportPasswordForSite: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 );
|
||||
exportSite->content = content.UTF8String;
|
||||
exportSite->loginContent = site.loginName.UTF8String;
|
||||
@@ -735,15 +734,15 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted );
|
||||
}
|
||||
|
||||
char *export = NULL;
|
||||
MPMarshallError exportError = (MPMarshallError){ .type= MPMarshallSuccess };
|
||||
mpw_marshall_write( &export, MPMarshallFormatFlat, exportUser, &exportError );
|
||||
MPMarshalError exportError = (MPMarshalError){ .type= MPMarshalSuccess };
|
||||
mpw_marshal_write( &export, MPMarshalFormatFlat, exportUser, &exportError );
|
||||
NSString *mpsites = nil;
|
||||
if (export && exportError.type == MPMarshallSuccess)
|
||||
if (export && exportError.type == MPMarshalSuccess)
|
||||
mpsites = [NSString stringWithCString:export encoding:NSUTF8StringEncoding];
|
||||
mpw_free_string( &export );
|
||||
|
||||
resultBlock( mpsites, exportError.type == MPMarshallSuccess? nil:
|
||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshallCode userInfo:@{
|
||||
resultBlock( mpsites, exportError.type == MPMarshalSuccess? nil:
|
||||
[NSError errorWithDomain:MPErrorDomain code:MPErrorMarshalCode userInfo:@{
|
||||
@"type" : @(exportError.type),
|
||||
NSLocalizedDescriptionKey: @(exportError.description),
|
||||
}] );
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
__BEGIN_DECLS
|
||||
extern NSString *const MPErrorDomain;
|
||||
extern NSInteger const MPErrorHangCode;
|
||||
extern NSInteger const MPErrorMarshallCode;
|
||||
extern NSInteger const MPErrorMarshalCode;
|
||||
|
||||
extern NSString *const MPSignedInNotification;
|
||||
extern NSString *const MPSignedOutNotification;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
NSString *const MPErrorDomain = @"MPErrorDomain";
|
||||
NSInteger const MPErrorHangCode = 1;
|
||||
NSInteger const MPErrorMarshallCode = 1;
|
||||
NSInteger const MPErrorMarshalCode = 1;
|
||||
|
||||
NSString *const MPSignedInNotification = @"MPSignedInNotification";
|
||||
NSString *const MPSignedOutNotification = @"MPSignedOutNotification";
|
||||
|
||||
@@ -166,41 +166,66 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
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_CXX0X_EXTENSIONS = 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_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = 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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_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_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = 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_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
@@ -231,17 +256,31 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
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_CXX0X_EXTENSIONS = 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_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = 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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
@@ -259,20 +298,30 @@
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_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_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = 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_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = NO;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@@ -292,41 +341,66 @@
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
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_CXX0X_EXTENSIONS = 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_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = 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_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_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_ABOUT_DEPRECATED_FUNCTIONS = YES;
|
||||
GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = 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_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||
GCC_WARN_MISSING_PARENTHESES = 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_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNKNOWN_PRAGMAS = NO;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_LABEL = YES;
|
||||
GCC_WARN_UNUSED_VALUE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_NAME = "${TARGET_NAME}";
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
#import <objc/NSObjCRuntime.h>
|
||||
#import <stdlib.h>
|
||||
|
||||
#define log(level, format, ...) \
|
||||
#define mpw_log(level, format, ...) \
|
||||
do { \
|
||||
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
|
||||
char *_msg = NULL; \
|
||||
@@ -64,11 +64,11 @@
|
||||
CFRelease( msgStr ); \
|
||||
} while (0)
|
||||
|
||||
#define trc(format, ...) log( 0, format, ##__VA_ARGS__ );
|
||||
#define dbg(format, ...) log( 1, format, ##__VA_ARGS__ );
|
||||
#define inf(format, ...) log( 2, format, ##__VA_ARGS__ );
|
||||
#define wrn(format, ...) log( 3, format, ##__VA_ARGS__ );
|
||||
#define err(format, ...) log( 4, format, ##__VA_ARGS__ );
|
||||
#define ftl(format, ...) log( 5, format, ##__VA_ARGS__ );
|
||||
#define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );
|
||||
#define dbg(format, ...) mpw_log( 1, format, ##__VA_ARGS__ );
|
||||
#define inf(format, ...) mpw_log( 2, format, ##__VA_ARGS__ );
|
||||
#define wrn(format, ...) mpw_log( 3, format, ##__VA_ARGS__ );
|
||||
#define err(format, ...) mpw_log( 4, format, ##__VA_ARGS__ );
|
||||
#define ftl(format, ...) mpw_log( 5, format, ##__VA_ARGS__ );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
@@ -225,7 +225,7 @@
|
||||
- (void)copyAnswer:(NSString *)answer {
|
||||
|
||||
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
||||
if ([pasteboard respondsToSelector:@selector( setItems:options: )]) {
|
||||
if (@available(iOS 10.0, *)) {
|
||||
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
|
||||
options:@{
|
||||
UIPasteboardOptionLocalOnly : @NO,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user