2
0

Compare commits

..

411 Commits

Author SHA1 Message Date
Maarten Billemont
5ca81b4aa7 Don't use daemon when setting release passwords in environment. 2018-08-25 11:57:36 -04:00
Maarten Billemont
3cbb063926 Refactor Native to try and load other architectures. 2018-08-24 16:33:14 -04:00
Maarten Billemont
d5551c8c8c Key calculator and access to the full algorithm. 2018-08-24 13:48:53 -04:00
Maarten Billemont
9a40e52d53 2.7-java-5 2018-08-19 16:13:39 -04:00
Maarten Billemont
6f0d768e69 Saving custom passwords and logins. 2018-08-19 16:11:43 -04:00
Maarten Billemont
40fdc8d248 Fix initialization dependency cycle & load files on init. 2018-08-18 13:43:41 -04:00
Maarten Billemont
6b9e1b8cb8 Standard label font & fix warnings. 2018-08-14 12:06:04 -04:00
Maarten Billemont
f41cdb8742 Site security questions and copy login name. 2018-08-13 17:53:31 -04:00
Maarten Billemont
10c6d203b8 Implement security answers & immediate site lookup. 2018-08-07 00:07:16 -04:00
Maarten Billemont
7d1aa9c9f4 Release 2.7.4 2018-08-02 12:34:24 -04:00
Maarten Billemont
c26281e3b7 2.7-java-4 2018-08-02 12:20:45 -04:00
Maarten Billemont
f0b1f0c9e0 Build for older glibc. 2018-08-02 12:19:49 -04:00
Maarten Billemont
9682efc7c9 Release masterpassword-gui-2.7.3 2018-08-02 01:44:50 -04:00
Maarten Billemont
1264cad377 2.7-java-3 2018-08-02 01:37:37 -04:00
Maarten Billemont
d185a0af14 Add mpw native binary for windows 32-bit. 2018-08-02 01:37:10 -04:00
Maarten Billemont
4275a6cc61 Fix build on Windows. 2018-08-02 01:32:55 -04:00
Maarten Billemont
c94ff429e8 Switch linux build of libmpw to debian for glibc instead of musl libc. 2018-08-01 20:13:42 -04:00
Maarten Billemont
00744cb264 Statically link the mpw library. 2018-08-01 14:20:47 -04:00
Maarten Billemont
7202fe6d1d Bump site for release of masterpassword-gui-2.7.2.jar 2018-07-31 15:35:57 -04:00
Maarten Billemont
63b4d9cd2e 2.7-java-2 2018-07-31 15:32:13 -04:00
Maarten Billemont
36a7c7f423 Clean up iconifying on copy. 2018-07-31 15:31:47 -04:00
Maarten Billemont
c2c4fb18bf Help improvements. 2018-07-31 15:16:33 -04:00
Maarten Billemont
3fc8acba70 Global hotkey, iconifying and application activation, help text. 2018-07-31 14:55:19 -04:00
Maarten Billemont
f5c0c4d787 Fix offsetting local time back to UTC. 2018-07-31 12:44:49 -04:00
Maarten Billemont
86775f1c75 Standardize epoch time calculation. 2018-07-31 09:27:41 -04:00
Maarten Billemont
2bb190f49a Bump site for masterpassword-gui-2.7.1 release. 2018-07-29 15:38:54 -04:00
Maarten Billemont
77c4a2af46 2.7-java-1 2018-07-29 15:29:19 -04:00
Maarten Billemont
3da82d30b1 Add support for creating incognito users. 2018-07-29 15:26:48 -04:00
Maarten Billemont
97532fdce6 Print UI dates in current time zone. 2018-07-29 15:18:54 -04:00
Maarten Billemont
fe63a2756a Fix default type for new sites & site UI updating. 2018-07-29 15:10:45 -04:00
Maarten Billemont
928b617ed0 Import & export users + improved user state tracking. 2018-07-29 14:01:07 -04:00
Maarten Billemont
18ecc41b39 Fix issues with UnsignedIntegerModel in a spinner. 2018-07-29 01:38:58 -04:00
Maarten Billemont
a6e9e89ace Update UI instead of resetting when site is updated. 2018-07-29 01:38:15 -04:00
Maarten Billemont
0b7494ecbf We use JDK9 APIs now. 2018-07-29 00:19:05 -04:00
Maarten Billemont
8377c9c615 JDK9 platform-independent way of managing application events. 2018-07-29 00:08:09 -04:00
Maarten Billemont
37a7cfa530 Support resetting user's master password. 2018-07-28 21:53:08 -04:00
Maarten Billemont
978b758079 New user fixes. 2018-07-28 19:56:20 -04:00
Maarten Billemont
38f09021b3 Button tooltips and improvements. 2018-07-28 18:11:36 -04:00
Maarten Billemont
7455fba55e Adding and deleting users and sites. 2018-07-28 17:52:43 -04:00
Maarten Billemont
8cd9755616 Update GradientPanel's opaque properly. 2018-07-28 14:30:36 -04:00
Maarten Billemont
46d301df94 Site settings & add sites. 2018-07-28 14:03:49 -04:00
Maarten Billemont
e639137304 Avatar configuration & move preferences into user panel. 2018-07-26 15:07:37 -04:00
Maarten Billemont
7c83a62f91 Support for building with JDK 10. 2018-07-26 15:07:17 -04:00
Maarten Billemont
513840e2c4 Read in site questions from json & don't serialize incomplete MPFileUser 2018-07-23 23:59:11 -04:00
Maarten Billemont
8f7faa9e4e User preferences. 2018-07-23 23:34:32 -04:00
Maarten Billemont
16cdcda94b Identicon support and UI improvements. 2018-07-23 11:23:26 -04:00
Maarten Billemont
400ebe59db Implement sites list and copy result. 2018-07-19 13:56:26 -04:00
Maarten Billemont
476a4046e7 Use standard control highlight color for password. 2018-07-18 17:02:51 -04:00
Maarten Billemont
3403449ca2 Cleanup and fix some warnings. 2018-07-18 15:46:06 -04:00
Maarten Billemont
596ace51ea WIP - new Java UI. 2018-07-18 12:27:19 -04:00
Maarten Billemont
80b5fcd785 Refactor model, improved isolation & access unauthenticated file metadata. 2018-07-18 12:23:53 -04:00
Maarten Billemont
a16bc9a318 Don't save changes made to model while it's being read from file. 2018-07-10 00:54:11 -04:00
Maarten Billemont
462dd4e89b Prepare for 2.7 release. 2018-07-10 00:39:52 -04:00
Maarten Billemont
e5ff374a9c Better way of checking implementation-version. 2018-07-10 00:39:35 -04:00
Maarten Billemont
954c4f8d63 Java improvements.
UI threading improvements.
Save user/site changes to file.
Ordering of user / site fixes.
Add questions to JSON output.
Bring JSON output format in line with C.
2018-07-09 01:13:25 -04:00
Maarten Billemont
529f1feace Omit empty _mpw_ext & unneeded escaping. 2018-07-09 01:12:28 -04:00
Maarten Billemont
5cdff6f155 Some fixes to search paths. 2018-07-08 20:50:32 -04:00
Maarten Billemont
81358c16f9 Omit questions if none present and fix parsing sites with no questions. 2018-07-08 20:49:42 -04:00
Maarten Billemont
4a555748cd UTC times were parsed in as local time by mktime. 2018-07-08 20:49:31 -04:00
Maarten Billemont
698566a914 Update stale GitHub references with new GitLab home. 2018-07-05 17:14:50 -04:00
Maarten Billemont
64a69856ac Fix libsodium include paths. 2018-07-04 14:14:49 -04:00
Maarten Billemont
f76de9520c Merge branch 'master' of gitlab.com:MasterPassword/MasterPassword 2018-07-04 12:17:04 -04:00
Maarten Billemont
4b3662bbe9 Support for x86 Linux. 2018-07-04 12:16:37 -04:00
Maarten Billemont
b25130f4d2 Tweak include paths & add clean support to android libs. 2018-07-03 11:21:48 -04:00
Maarten Billemont
d6617563fc Clean libs when cleaning build. 2018-07-01 21:20:56 -04:00
Maarten Billemont
8d24ec3250 Merge branch 'patch-1' into 'master'
Update README.md Fix broken link

See merge request MasterPassword/MasterPassword!249
2018-07-01 20:31:14 +00:00
Jakob Kukla
bbcc250a5c Update README.md
Fix broken link to native CLI instructions
2018-07-01 18:04:19 +00:00
Maarten Billemont
4abb50ad9b Fix lipo regression in build script. 2018-06-30 23:54:35 -04:00
Maarten Billemont
30dac64d5d Support for building on Linux. 2018-06-30 23:35:29 -04:00
Maarten Billemont
e4e2aaad95 Ensure GitLab CI does clean builds. 2018-06-30 20:53:29 -04:00
Maarten Billemont
835acf45eb Improve check for platform-specific GUI support & url access for CF needs user-agent. 2018-06-30 15:24:58 -04:00
Maarten Billemont
c3f6796833 Pre-built library files for different platforms. 2018-06-30 12:35:40 -04:00
Maarten Billemont
86f4e8ec06 Fix gradle build. 2018-06-30 11:57:36 -04:00
Maarten Billemont
0dddcef28e libsodium and masterpassword-core must be linked statically + windows build configuration fixes. 2018-06-27 02:54:31 -04:00
Maarten Billemont
cc583c789d Merge branch 'master' of gitlab.com:MasterPassword/MasterPassword 2018-06-25 13:22:36 -04:00
Maarten Billemont
42d78da74e Fix some bugs in the new mpw_strings & mpw_strncasecmp. 2018-06-25 13:19:26 -04:00
Maarten Billemont
b5040a7786 Harmonize standardized platform naming between Native class and gradle. 2018-06-25 12:25:38 -04:00
Maarten Billemont
b1698ee339 C type fixes. 2018-06-25 12:25:17 -04:00
Maarten Billemont
8ffc0ae350 Execute gradle scripts with bash. 2018-06-25 10:34:56 -04:00
Maarten Billemont
8276d2f4e5 Build dependencies with a task & all windows archs. 2018-06-25 02:02:51 -04:00
Maarten Billemont
11cf86bc73 Use brew version of libtoolize. 2018-06-24 16:48:22 -04:00
Maarten Billemont
5084511404 Merge branch 'master' of gitlab.com:MasterPassword/MasterPassword 2018-06-24 16:31:22 -04:00
Maarten Billemont
fffec56d4e Build support for Microsoft Windows. 2018-06-24 16:20:42 -04:00
Maarten Billemont
9a0828c1eb Bump site for Android release. 2018-06-21 10:31:10 -04:00
Maarten Billemont
db967a1a16 Prepare 2.7-android-1 2018-06-19 17:15:42 -04:00
Maarten Billemont
f83896d89d Ignore build files. 2018-06-19 01:59:28 -04:00
Maarten Billemont
683c0165e6 Reset Android counter on long-touch. 2018-06-19 01:54:20 -04:00
Maarten Billemont
3853b6f180 Move Homebrew dependencies to a Brewfile. 2018-06-19 01:52:53 -04:00
Maarten Billemont
bff3577ada Also need automake installed. 2018-06-19 01:42:59 -04:00
Maarten Billemont
4c48bfb1af Rename native lib to libmpw & native library loading for eg. Android. 2018-06-19 01:32:07 -04:00
Maarten Billemont
a8263b276c Fix handling of nullable parameters in native code. 2018-06-19 01:31:52 -04:00
Maarten Billemont
11e32abb90 Install autoconf in GitLab CI. 2018-06-17 07:57:50 -04:00
Maarten Billemont
b6e6dce9f0 Added some missing build files. 2018-06-17 01:48:36 -04:00
Maarten Billemont
ada1c7f6ae Fix json-c remote back to upstream. 2018-06-17 01:24:41 -04:00
Maarten Billemont
1cbb584011 Android support for new native masterpassword-core. 2018-06-17 01:11:16 -04:00
Maarten Billemont
f9289a3e9e Standardize TRUE to true. 2018-06-17 00:36:31 -04:00
Maarten Billemont
9a37253461 Make dependencies private since they're only used by the implementation. 2018-06-16 19:47:53 -04:00
Maarten Billemont
5a4456bf46 Ensure all source files are treated as UTF-8. 2018-06-11 00:09:59 -04:00
Maarten Billemont
1d06dd65ed Ensure maven.lyndir.com is accessed securely. 2018-06-10 19:11:22 -04:00
Maarten Billemont
ed6c32811c !232 Fix value reset on logout. 2018-06-10 15:31:20 -04:00
Maarten Billemont
9a564ff35e JDK 8 support for Android platform. 2018-06-10 15:22:37 -04:00
Maarten Billemont
4909479b0f Merge branch 'master' of gitlab.com:MasterPassword/MasterPassword 2018-06-10 13:26:26 -04:00
Maarten Billemont
434a7cc280 Docker availability. 2018-06-06 01:49:45 +00:00
Maarten Billemont
50a48ae092 Migrate docker from ubuntu to alpine. 2018-06-05 21:25:38 -04:00
Maarten Billemont
c3017069b1 Remove __unused since it's non-standard.
1. It breaks compilers without support for __attribute__
2. It breaks system headers that declare variables named __unused (eg. musl libc).
2018-06-05 21:22:40 -04:00
Maarten Billemont
c7425be681 Misc Xcode files. 2018-06-05 20:26:44 -04:00
Maarten Billemont
249a1975cd Update path for mpw-jni.h. 2018-06-05 20:22:46 -04:00
Maarten Billemont
190a241a25 Java relocation. 2018-06-05 20:19:10 -04:00
Maarten Billemont
aef8422102 Update dependent paths to new core source location. 2018-06-05 20:09:13 -04:00
Maarten Billemont
c2aafd8602 Reorganize core source and add Docker support to CLI. 2018-06-05 20:04:43 -04:00
Maarten Billemont
8e41cba7ac Badges moved to the project's settings. 2018-06-05 20:48:21 +00:00
Maarten Billemont
9d29775b14 Remove some obsolete variables. 2018-06-05 16:17:19 -04:00
Maarten Billemont
55bd9382bc Fix a syntax error in genassets. 2018-06-05 15:36:27 -04:00
Maarten Billemont
687923da32 Don't fail stopProgress if there is no active logSpinner. 2018-06-05 15:24:45 -04:00
Maarten Billemont
66e893fd83 Drill down on what genassets command is failing. 2018-06-05 15:09:11 -04:00
Maarten Billemont
cc5c45e3aa Trace subshell errors. 2018-06-05 14:44:54 -04:00
Maarten Billemont
d472d975ce Small bashlib tweaks. 2018-06-05 14:19:12 -04:00
Maarten Billemont
7a97a0b0c8 Better exit status preservation on error. 2018-06-05 14:12:10 -04:00
Maarten Billemont
02aed778bc Output errors on stderr. 2018-06-05 14:06:55 -04:00
Maarten Billemont
b748e607ad Do we need SHLVL=0? 2018-06-05 13:32:08 -04:00
Maarten Billemont
c801ff546a Initialize TERM if not set. 2018-06-05 13:18:54 -04:00
Maarten Billemont
17185391ce Debug genassets failure. 2018-06-05 13:05:07 -04:00
Maarten Billemont
4579095afc Tweak GitLab CI requisites. 2018-06-05 12:58:00 -04:00
Maarten Billemont
788d85178d Scripts update to visualize errors better. 2018-06-05 12:49:03 -04:00
Maarten Billemont
af4d7c4bc9 Remove xcpretty from GitLab CI builds, has issues and doesn't handle external build output. 2018-06-05 12:23:27 -04:00
Maarten Billemont
a4bbfdf850 Retain xcodebuild's exit status in GitLab CI builds. 2018-06-05 12:11:23 -04:00
Maarten Billemont
cef3d470bd Configure GitLab CI to check out submodules. 2018-06-05 11:41:23 -04:00
Maarten Billemont
0d37c45dbe Remove rbenv-bundler from GitLab Pages config. 2018-06-05 11:37:31 -04:00
Maarten Billemont
e568b5a9da Fix GitLab Pages stage. 2018-06-05 11:33:29 -04:00
Maarten Billemont
e7ac8661f9 Begin setting up GitLab CI. 2018-06-05 11:30:19 -04:00
Maarten Billemont
882de547d0 Fully replace Java mpw algorithm implementation with proxy to standard C implementation. 2018-06-04 01:43:46 -04:00
Maarten Billemont
6957d46ef9 Fix Java algorithm type inconsistency. 2018-06-04 01:43:02 -04:00
Maarten Billemont
3a9a518cb1 Fixed bad AES PKCS7 block rounding. 2018-06-03 23:47:16 -04:00
Maarten Billemont
0900aff93a Fix disappeared link library. 2018-06-03 20:43:12 -04:00
Maarten Billemont
3974b70a83 Fix include paths. 2018-06-03 20:42:09 -04:00
Maarten Billemont
498b7caecb C core code moved into src/ 2018-06-03 19:46:35 -04:00
Maarten Billemont
0b26260124 Build platform libsodium dependency for Travis. 2018-06-03 18:45:30 -04:00
Maarten Billemont
bc0ffbd552 Fix JNI write-back, bad V3 api usage, duplicate length passing. 2018-06-03 17:58:24 -04:00
Maarten Billemont
c08d3a0e8b Fix format type. 2018-06-03 17:09:33 -04:00
Maarten Billemont
5501f1f97d Allow filtering Java test cases. 2018-06-03 16:50:19 -04:00
Maarten Billemont
073ef4f439 Update to masterpassword.app domain. 2018-06-03 16:26:08 -04:00
Maarten Billemont
a7f82d3148 Allow verbose and scoped tests output. 2018-06-03 16:19:14 -04:00
Maarten Billemont
831b475b28 Remove deprecated build configuration and libscrypt references. 2018-06-03 15:08:02 -04:00
Maarten Billemont
728a4486d3 Initial integration of JNI with C implementation. 2018-05-28 23:00:05 -04:00
Maarten Billemont
5035c52846 Fix library resolution. 2018-05-28 22:15:09 -04:00
Maarten Billemont
a0447298d3 Fix inter-project dependency and including libs into algorithm jar. 2018-05-27 23:43:35 -04:00
Maarten Billemont
0b044ab9a4 Archive and initial cross-compile support. 2018-05-26 01:22:41 -04:00
Maarten Billemont
3b24e1d1b8 Move native implementation build into masterpassword-core 2018-05-25 13:08:05 -04:00
Maarten Billemont
cc82e52c33 Initial native interface for scrypt. 2018-05-22 01:00:14 -04:00
Maarten Billemont
faf59875bf Support for building libsodium for Android. 2018-05-21 17:39:06 -04:00
Maarten Billemont
e12e14ef03 Move library builds into /lib so they can be shared.
Also made the library build script more generic.
2018-05-20 15:04:32 -04:00
Maarten Billemont
f41f07f0ae Replace lambdaworks:scrypt with libsodium-jni to match C implementation, remove dependency on opal-crypto and its providers. 2018-05-19 19:58:37 -04:00
Maarten Billemont
1cfc199541 Reorder some methods. 2018-05-19 12:47:27 -04:00
Maarten Billemont
c43cc73ad5 Sign masterpassword-gui under Gradle. 2018-05-19 11:45:57 -04:00
Maarten Billemont
1bd61759bf Wipe masterPassword on authentication & misc improvements. 2018-05-19 11:45:18 -04:00
Maarten Billemont
cbf277c493 Bump opal to stable. 2018-05-17 13:03:28 -04:00
Maarten Billemont
87b7afd587 Reformat. 2018-05-16 19:22:19 -04:00
Maarten Billemont
2db0bb35d5 Resolve warnings and inspections. 2018-05-16 12:30:28 -04:00
Maarten Billemont
c51262ccc2 Complete security questions model. 2018-05-16 12:00:42 -04:00
Maarten Billemont
1b703515dd Refactor code. 2018-05-16 00:16:06 -04:00
Maarten Billemont
0aa7baf59e Refactoring masterpassword-algorithm. 2018-05-16 00:12:31 -04:00
Maarten Billemont
8bdf1755b7 Migrating to JDK 1.8 2018-05-15 17:12:42 -04:00
Maarten Billemont
bda1ac3bd4 Refactor masterpassword-model 2018-05-15 13:53:27 -04:00
Maarten Billemont
8d7c351912 Initial implementation of questions support. 2018-05-14 12:24:15 -04:00
Maarten Billemont
38a357cb28 Transition to Jackson so we can retain unrecognized properties in the source JSON. 2018-05-14 11:27:49 -04:00
Maarten Billemont
f0d523fb35 Initial Java JSON serialization/deserialization. 2018-05-08 22:40:48 -04:00
Maarten Billemont
1cb720da32 Remove ssl prefix from masterpasswordapp.com URL. 2018-05-03 13:51:00 +02:00
Maarten Billemont
1031414ba2 WIP - JSON mpsites serialization. 2018-05-03 13:49:34 +02:00
Maarten Billemont
cb74b1f3fc Fix warnings and inspections. 2018-04-27 11:36:01 -04:00
Maarten Billemont
82e2d0b5ac Replace Version API with MPAlgorithm, make configuration instance-specific. 2018-04-26 15:56:12 -04:00
Maarten Billemont
33f2e0edda Optimize imports. 2018-04-26 13:26:16 -04:00
Maarten Billemont
9c8566b537 Reformat to code style. 2018-04-26 13:05:45 -04:00
Maarten Billemont
10698284d2 Format-specific marshalling. 2018-04-26 12:49:44 -04:00
Maarten Billemont
11185725d1 Make default counter algorithm-scoped, format-specific unmarshalling. 2018-04-26 12:45:29 -04:00
Maarten Billemont
71f1b3c130 Better exception logging to avoid hiding class initialization exceptions. 2018-04-26 12:45:02 -04:00
Maarten Billemont
dc19806e02 Improve rendering of user name. 2018-04-25 22:50:12 -04:00
Maarten Billemont
94ac8b1460 Fixed upstream revision check. 2018-04-25 22:02:41 -04:00
Maarten Billemont
40a807c6af Better scope preferences to the algorithm & clean up. 2018-04-25 21:50:17 -04:00
Maarten Billemont
c115e9149c Merge branch 'master' of github.com:Lyndir/MasterPassword 2018-04-25 17:51:48 -04:00
Maarten Billemont
7123e97ef9 Update site URLs. 2018-04-25 17:51:17 -04:00
Maarten Billemont
37fb672133 Publish masterpassword-android-2.5.1.apk 2018-04-24 16:52:27 -04:00
Maarten Billemont
2771125eb5 2.5-android-1 2018-04-24 16:18:32 -04:00
Maarten Billemont
a16cb19311 Describe how to create a Java release. 2018-04-24 16:14:36 -04:00
Maarten Billemont
8f8920b91f Gradle update. 2018-04-24 16:06:02 -04:00
Maarten Billemont
1d913b7f78 Sort Basic under Short per defined order. 2018-04-24 15:37:41 -04:00
Maarten Billemont
5fe9106f6d Merge pull request #191 from MidnightWonderer/bug/protocol-relative-css
fix protocol relative css import
2018-04-24 09:36:45 -04:00
Maarten Billemont
8d9a3e0ab0 Site updated. 2018-04-22 09:41:25 -04:00
Maarten Billemont
344771dbdf Make site available under public/site 2018-04-22 09:33:16 -04:00
Maarten Billemont
d38dba7272 Site has moved to gh-pages. 2018-04-21 16:14:56 -04:00
Maarten Billemont
409f005eec Be a bit more specific about password storage. 2018-04-20 09:10:52 -04:00
Maarten Billemont
df7903e146 Add in video and resources. 2018-04-20 00:24:44 -04:00
Maarten Billemont
49edaef79d Some clean-up. 2018-04-19 23:34:42 -04:00
Maarten Billemont
fcbed9ef01 Improve wording. 2018-04-19 23:28:59 -04:00
Maarten Billemont
3edb414d23 Fix paroller issues. 2018-04-19 23:17:08 -04:00
Maarten Billemont
d779c21cc1 WIP - parallax hero image. 2018-04-19 15:49:04 -04:00
Maarten Billemont
8d32bc56ae Small print in footer. 2018-04-19 15:48:29 -04:00
Maarten Billemont
9d03ed06c3 Footer. 2018-04-18 12:18:58 -04:00
Maarten Billemont
ee290e5c14 Extensive content and style update. 2018-04-18 11:54:30 -04:00
Maarten Billemont
789761b177 Updates to new site layout. 2018-04-16 17:17:16 -04:00
Maarten Billemont
cd0876d58a project.lyndir.com is no longer in use, migrated to github. 2018-04-16 10:02:27 -04:00
Maarten Billemont
bfae4da56c Update to latest Xcode warnings. 2018-04-03 09:53:40 -04:00
Maarten Billemont
f342ed5940 Only define loggers if not yet provided. 2018-04-03 09:10:15 -04:00
Maarten Billemont
c7373fee28 Improve output alignment. 2018-04-03 08:50:45 -04:00
Maarten Billemont
44b2955652 Ignore cmake files. 2018-04-03 08:50:25 -04:00
Maarten Billemont
8a4af69008 Fix mpw_log override for iOS/macOS. 2018-03-24 16:49:55 -04:00
Maarten Billemont
6650382e19 Fix overriding of ftl behaviour for tests. 2018-03-24 15:27:13 -04:00
Maarten Billemont
a1f5e0ba1c Harmonize log methods by removing trailing \n. 2018-03-24 15:27:04 -04:00
Maarten Billemont
035bb6b285 Swift-compatible typing. 2018-03-24 15:25:43 -04:00
Maarten Billemont
c0107fb90e Move mpw_identicon into mpw-algorithm.h & define colors. 2018-03-24 15:25:32 -04:00
Maarten Billemont
138be9d14c Respect the user's default type when creating new sites. 2018-03-05 08:14:11 -05:00
Maarten Billemont
61f474217b Update Travis Xcode. 2018-02-18 23:59:15 -05:00
Maarten Billemont
d31c5eed0a Merge branch 'master' of github.com:Lyndir/MasterPassword 2018-02-18 23:47:35 -05:00
Maarten Billemont
5060de689b Match template character to source. 2018-02-18 23:47:23 -05:00
Maarten Billemont
b95424ddf3 Update macOS project configuration. 2018-02-10 23:43:42 -05:00
Maarten Billemont
e40a442a30 Build fixes, improvements and project cleanup. 2018-02-10 23:29:55 -05:00
Maarten Billemont
b5134a9faf Updates to project configuration. 2018-02-10 21:07:00 -05:00
Maarten Billemont
a791d449ce Updated info.plist syntax. 2018-02-10 20:52:30 -05:00
Maarten Billemont
43e1a9d539 Improved checks for external build scripts. 2018-02-10 20:51:50 -05:00
Maarten Billemont
e91f80d10e Remove externals. 2018-02-08 12:31:31 -05:00
Maarten Billemont
9db855c7fb Add documentation PDFs. 2018-01-06 15:44:20 -05:00
Maarten Billemont
2dc3636b26 Support empty site names. 2018-01-06 15:42:26 -05:00
Maarten Billemont
4d9df012f6 Fix check for whether there is a directory in the path. 2017-11-21 22:33:42 -05:00
Maarten Billemont
ff9d0d75ef Make additional libraries optional. 2017-11-06 21:58:51 -05:00
Maarten Billemont
4e160b3b33 libcurses is sometimes split off from libtinfo. 2017-11-06 18:41:18 -05:00
Maarten Billemont
5048acc9f9 cmake's find_package is case sensitive & be smarter about git. 2017-11-06 18:38:36 -05:00
Maarten Billemont
1841541bc4 --broken is new and not really needed. 2017-11-06 15:38:30 -05:00
Maarten Billemont
11d9af3844 Fix generation of valid random passwords for state test. 2017-11-06 14:14:37 -05:00
Maarten Billemont
e30b618241 Allow cmake to look up the mpw version from git. 2017-11-06 12:50:15 -05:00
Maarten Billemont
966327571d Fix cmake when VERSION doesn't exist. 2017-11-06 12:22:13 -05:00
Maarten Billemont
303d50c197 Use FindCurses.cmake to discover the right way to build with libcurses. 2017-11-06 12:07:13 -05:00
Maarten Billemont
bcdfdec211 Notify builds on Matrix channel #masterpassword:lyndir.com 2017-10-06 15:32:33 -04:00
Maarten Billemont
fb769d2ac5 Release mpw-2.6-cli-4. 2017-10-06 15:21:07 -04:00
Maarten Billemont
f8043ae16d Fix chdir test & make curses work when stdout is redirected. 2017-10-06 14:59:29 -04:00
Maarten Billemont
7150f2f5c5 Fix test to match context against question keyword. 2017-10-06 14:58:42 -04:00
Maarten Billemont
81bd2e3065 Make mpw_mkpw symlinkable. 2017-10-06 13:33:08 -04:00
Maarten Billemont
78c9618807 Test chdir. 2017-09-26 11:07:02 -04:00
Maarten Billemont
bed8939b8a Debug issue in testSiteState 2017-09-25 18:35:57 -04:00
Maarten Billemont
9443d93500 Remove MPW_COLOR from core, safer decryption, more standard password input & curses dialog. 2017-09-25 18:34:12 -04:00
Maarten Billemont
877eba66be strdup also isn't standard. 2017-09-25 10:51:14 -04:00
Maarten Billemont
3af8aba40c Make source more standard C11 w/POSIX:2008 CLI. 2017-09-25 10:33:31 -04:00
Maarten Billemont
7ece02c73d Remove stale 2.6-cli-3 2017-09-25 03:05:38 -04:00
Maarten Billemont
ebbd2b3ac4 Re-distribute 2.6-cli-3 with standard build fixes. 2017-09-25 03:01:24 -04:00
Maarten Billemont
a85eff4277 Include semi-standard getline. 2017-09-25 02:59:09 -04:00
Maarten Billemont
98f1c776be Fix some warnings. 2017-09-25 02:56:37 -04:00
Maarten Billemont
6b554c67ed More standard memset_s 2017-09-25 02:53:34 -04:00
Maarten Billemont
f2ae35080d mpw-2.6-cli-3 release. 2017-09-24 15:40:19 -04:00
Maarten Billemont
0ff6c93a95 Document default key size. 2017-09-24 13:18:33 -04:00
Maarten Billemont
9147600b97 Travis cache doesn't need to be disabled anymore. 2017-09-24 13:14:58 -04:00
Maarten Billemont
fafe56166e bzero is nonstandard. Replace with memset_s. 2017-09-24 13:14:16 -04:00
Maarten Billemont
0a024b2594 AES-CBC needs PKCS#7 padding. 2017-09-24 13:06:19 -04:00
Maarten Billemont
b4c2a393f1 Clean up aes state, default to 512 key size, improve log output. 2017-09-24 12:00:38 -04:00
Maarten Billemont
39dcef46d2 Show in Travis log why tests fail. 2017-09-24 00:26:58 -04:00
Maarten Billemont
d6a88583f5 AES needs to be CBC, not CTR. 2017-09-23 20:14:53 -04:00
Maarten Billemont
1c17b84dcf Some tweaks for Travis. 2017-09-23 19:24:06 -04:00
Maarten Billemont
cecaf1b5cc Log fixes, test improvements and some refactoring. 2017-09-23 19:11:06 -04:00
Maarten Billemont
888338e107 Fix siteKey algorithm for siteState. 2017-09-23 19:09:19 -04:00
Maarten Billemont
32055abf29 ciphers.plist is no longer needed. 2017-09-22 20:08:46 -04:00
Maarten Billemont
0f72dffaf1 Updated keyID in test case. 2017-09-22 19:05:59 -04:00
Maarten Billemont
5d1be43b65 Deep Java refactoring to match the C API logic and clean up some OO oddities. 2017-09-22 19:03:50 -04:00
Maarten Billemont
dc7089c38c mpw-tests was not checking mpw_tests.xml's keyID. 2017-09-22 18:23:08 -04:00
Maarten Billemont
34540f0844 Finish rename Marshall -> Marshal. 2017-09-22 15:20:14 -04:00
Maarten Billemont
e818713484 Fix filenames in build 2017-09-22 14:21:31 -04:00
Maarten Billemont
6e2289994c Fix gradle build with missing local.properties. 2017-09-21 10:32:38 -04:00
Maarten Billemont
05a9ba46d0 Marshal refactoring to prepare for new format. 2017-09-20 17:45:49 -04:00
Maarten Billemont
70bb30ba0c Skip masterpassword-android if not set up to build it. 2017-09-20 16:52:20 -04:00
Maarten Billemont
444d7e9b35 Source fix-ups: single l marshal, copyright, .travis. 2017-09-20 12:43:03 -04:00
Maarten Billemont
47164c7a92 Marshal has only one l. 2017-09-20 10:48:04 -04:00
Maarten Billemont
ad00ceb4ce Harmonize C/Java code more, WIP crypt/derive in Java. 2017-09-19 14:52:43 -04:00
Maarten Billemont
473e3ca11f Run gradle test in Travis. 2017-09-19 13:46:27 -04:00
Maarten Billemont
35c0431cec Update Java to match C's internal changes. 2017-09-19 13:45:51 -04:00
Maarten Billemont
70c784db83 Update MP_FULLNAME in mpw.bashrc. 2017-09-15 13:24:45 -04:00
Maarten Billemont
d448099a2d -s is -P now. 2017-09-14 23:14:00 -04:00
Maarten Billemont
e3a7ea57e0 Type key is K, subkey context is not bound by BYTES_MIN/MAX. 2017-09-14 23:03:39 -04:00
Maarten Billemont
fa6133200e Added bashlib. 2017-09-14 16:44:32 -04:00
Maarten Billemont
dfa67bdca9 Added some scripts to do math on password strength and generate random dictionary passphrases. 2017-09-14 16:31:11 -04:00
Maarten Billemont
8c9c4ef7b2 Describe how to use the cmake alternative build system. 2017-09-10 14:17:06 -04:00
Maarten Billemont
1adb18a7e7 Fixed #206 - 'p' trigger for phrase was missing. 2017-09-10 14:03:56 -04:00
Maarten Billemont
f50fdb7777 Some build tool updates, primarily cmake. 2017-09-10 13:57:14 -04:00
Maarten Billemont
33bf2c93d0 Some fixes to the CSS for videos. 2017-09-08 11:19:10 -04:00
Maarten Billemont
f2abcc9e43 A few fixes to the about video. 2017-09-08 10:31:43 -04:00
Maarten Billemont
5ef69aa045 Make bcrypt code more standard. 2017-09-07 00:05:55 -04:00
Maarten Billemont
1c0f274868 Include for waitpid. 2017-09-06 23:54:52 -04:00
Maarten Billemont
1f592f50a9 Release 2.6-cli-2 2017-09-06 00:34:09 -04:00
Maarten Billemont
30fdb54e94 Fix support for building without MPW_JSON enabled. 2017-09-06 00:32:57 -04:00
Maarten Billemont
4f552be5a9 Update cmake for source and improve feature checking in ./build 2017-09-06 00:31:49 -04:00
Maarten Billemont
1439df9f9a Add license headers to cli source files. 2017-09-04 19:37:36 -04:00
Maarten Billemont
e676a0e258 Release 2.6-cli-1. 2017-09-04 14:50:57 -04:00
Maarten Billemont
895df6377d Only distribute release tags, include TAG and VERSION. 2017-09-04 14:48:40 -04:00
Maarten Billemont
3d46f60ff4 Add VERSION to distribution archive. 2017-09-04 14:38:08 -04:00
Maarten Billemont
44d8ab6e53 Remove some pointless local's. 2017-09-04 14:29:25 -04:00
Maarten Billemont
cd70009c2c Move instructions into cli-c for distribution. 2017-09-04 14:17:20 -04:00
Maarten Billemont
4261160902 Some more refactoring. 2017-09-03 17:00:35 -04:00
Maarten Billemont
ced7aef5d7 Fix target assignment of mpw-cli-util.c 2017-09-03 16:53:14 -04:00
Maarten Billemont
63100913c5 libjson-c's upstream still has build issues, switch back to our fork. 2017-09-03 15:48:43 -04:00
Maarten Billemont
6904d4c427 purposeResult is not an owned reference. 2017-09-03 15:46:38 -04:00
Maarten Billemont
4271d77225 Remove debugging code. 2017-09-03 15:43:22 -04:00
Maarten Billemont
6811773e54 Refactor CLI code to make the flow more clear and the free'ing more reliable. 2017-09-03 15:41:12 -04:00
Maarten Billemont
060ce61030 Fix ./build's targets interpretation & other improvements. 2017-09-01 11:16:09 -04:00
Maarten Billemont
9a5e9ced31 More consistent spacing in usage output. 2017-08-31 15:32:58 -04:00
Maarten Billemont
568401a612 Extract cli utilities into mpw-cli-util to keep things cleaner. 2017-08-31 15:30:42 -04:00
Maarten Billemont
92a3a0ccbd Switch libjson-c back to upstream and fix some build issues with it. 2017-08-31 15:14:08 -04:00
Maarten Billemont
ba24c2be34 Rename env vars to make it clear they are for the mpw binary, add PATH support for askpass. 2017-08-31 13:42:03 -04:00
Maarten Billemont
019cefd3fb Add support for askpass program for reading answers from the user. 2017-08-31 13:37:28 -04:00
Maarten Billemont
eef82f7ed4 Don't infinite loop when prompting if no terminal is available. 2017-08-31 11:49:36 -04:00
Maarten Billemont
2dfe0f78b0 Build & link all sources at once to allow link-time optimization. 2017-08-31 11:48:34 -04:00
Maarten Billemont
627144b583 Make MPW_JSON optional as documented. 2017-08-31 11:48:10 -04:00
Maarten Billemont
fad0f5e5dd Add PearlCryptUtils back since PearlKeyChain uses it. 2017-08-30 19:05:42 -04:00
Maarten Billemont
8562338b62 Support for reading master password from an FD. 2017-08-30 19:05:21 -04:00
Maarten Billemont
17de69834e Declare __unused if not declared by compiler. 2017-08-30 13:27:59 -04:00
Maarten Billemont
aeeab7dbf6 Improve build script documentation and targets variable. 2017-08-30 10:18:23 -04:00
Maarten Billemont
ce60ba6c9f External libs configuration no longer used. 2017-08-30 09:58:01 -04:00
Maarten Billemont
d22f93e564 Format code. 2017-08-30 09:57:15 -04:00
Maarten Billemont
6f4f6b8d1e Copy TOTP counter support to v2 override. 2017-08-30 09:54:16 -04:00
Maarten Billemont
6fa8ee53cd Currently unused implementation of HOTP. 2017-08-30 09:40:51 -04:00
Maarten Billemont
23af56c150 Slight clean-up of types, includes and warnings. 2017-08-30 09:39:35 -04:00
Maarten Billemont
91828cbad7 Test script for CLI. 2017-08-30 09:38:23 -04:00
Maarten Billemont
40d2788ae0 Implement OTP counter feature for counter values of 0. 2017-08-30 09:35:55 -04:00
Maarten Billemont
21a3a28980 Copy args so we can re-use it. 2017-08-29 12:06:40 -04:00
Maarten Billemont
f5c7bee58f Remove unused Pearl-Crypto. 2017-08-29 01:01:38 -04:00
Maarten Billemont
e364f5159b Fix build warnings. 2017-08-28 23:48:24 -04:00
Maarten Billemont
74f9f1ca00 Fix up objc code to match new C API. 2017-08-28 19:37:51 -04:00
Maarten Billemont
328d38ac19 Remove PearlLayout. 2017-08-28 19:34:22 -04:00
Maarten Billemont
7735d82c7b Silence unused variable warnings for compiler check variables. 2017-08-28 19:25:51 -04:00
Maarten Billemont
1e7c200865 Remove non-standard asprintf from mpw-cli. 2017-08-28 18:25:58 -04:00
Maarten Billemont
724b357dd8 Create path for mpw.d sites files if it doesn't exist yet. 2017-08-28 17:58:57 -04:00
Maarten Billemont
a85efc5736 Remove all build-time external dependency fetching/building logic. 2017-08-27 11:17:45 -04:00
Maarten Billemont
9eb58119ea Remove dependency on external bcrypt. 2017-08-27 10:47:39 -04:00
Maarten Billemont
77b4ed2cfd Remove dependency on asprintf. 2017-08-27 09:25:53 -04:00
Maarten Billemont
011416690a Some warning cleanup. 2017-08-27 09:04:18 -04:00
Maarten Billemont
53eb5c8a73 Refactoring and fix up mpw_color. 2017-08-27 08:53:58 -04:00
Maarten Billemont
2f99855cd4 Remove non-standard host-endian functions. 2017-08-27 07:46:34 -04:00
Maarten Billemont
18eaeec1de Fix some rewrite bugs. 2017-08-23 00:53:14 -04:00
Maarten Billemont
5ee700c9b9 Small fix. 2017-08-23 00:05:50 -04:00
Maarten Billemont
a8949ca07e NULL out free'ed references. 2017-08-23 00:01:23 -04:00
Maarten Billemont
0a42579d9e Improved free'ing on error conditions. 2017-08-22 18:38:36 -04:00
Maarten Billemont
f2f8747126 Support for persisting login/question type & stateful types, null checking, cleanup and rewrite of CLI state. 2017-08-22 18:18:24 -04:00
Maarten Billemont
f83cdacab8 Document -M, -P, allow saving login name. 2017-08-22 11:38:04 -04:00
Sarun Rattanasiri
4f708809e5 fix protocol relative css import 2017-08-14 22:50:07 +07:00
Maarten Billemont
98aeb02d32 Forgot to merge in i386 2017-08-13 19:06:06 -04:00
Maarten Billemont
2bbaeccd05 Forgot to merge in i386 2017-08-13 18:32:03 -04:00
Maarten Billemont
91e0a04e66 Add support for i386 in libjson-c and libsodium builds. 2017-08-13 16:53:18 -04:00
Maarten Billemont
661fc523ad Don't pass nil error to crashlytics. 2017-08-13 16:49:56 -04:00
Maarten Billemont
b9cbaf7343 Cross-compile fixes for iOS. 2017-08-13 15:52:08 -04:00
Maarten Billemont
e451308fdc Refactoring regression, use right algorithm version for siteKey. 2017-08-13 11:35:15 -04:00
Maarten Billemont
1b51c5efa4 Build script update. 2017-08-13 11:02:05 -04:00
Maarten Billemont
a8776eec58 Fix C cli API. 2017-08-13 08:50:16 -04:00
Maarten Billemont
d9cdb7ef83 Fix error name collision. 2017-08-13 01:00:03 -04:00
Maarten Billemont
28c7a64bd2 Fork json-c temporarily to fix some code issues. 2017-08-13 00:30:25 -04:00
Maarten Billemont
d7193f7753 Adapt macOS for new APIs. 2017-08-12 22:26:48 -04:00
Maarten Billemont
f5c7d11f0e Add marshalling metadata lookup & adapt iOS for new APIs. 2017-08-12 21:57:47 -04:00
Maarten Billemont
c0ba96daa2 Update Darwin platform project with solid support for linking libsodium & libjson-c 2017-08-11 01:42:03 -04:00
Maarten Billemont
b374d9e04a Some type fixes. 2017-08-10 21:29:59 -04:00
Maarten Billemont
2033ebdc72 Documentation improvements. 2017-08-10 12:48:04 -04:00
Maarten Billemont
c3bb896f40 Limit subkeys to 128-512 bit. 2017-08-10 12:45:25 -04:00
Maarten Billemont
4f7c28563d passwordType -> resultType, add derived class and key type. 2017-08-10 12:30:42 -04:00
Maarten Billemont
b1985a2bf2 Added version into compiled binary. 2017-08-08 00:00:14 -04:00
Maarten Billemont
ee50a4d025 Define type for siteCounter, add support for saving hybrid passwords. 2017-08-07 20:35:31 -04:00
Maarten Billemont
b26f5a82d7 Allow migration of redacted state & show URL. 2017-08-07 18:57:10 -04:00
Maarten Billemont
c044ae79cd Support updating the mpw, showing loginName, adding new sites & questions, fix password memory leak. 2017-08-07 17:42:38 -04:00
Maarten Billemont
a261538602 Slight adjustment in printf declarations. 2017-08-06 19:09:13 -04:00
Maarten Billemont
18daef7808 Fix some build warnings. 2017-08-06 18:56:37 -04:00
Maarten Billemont
68d1ab58b7 De-duplicate algorithm implementations and improve trace output. 2017-08-06 11:40:10 -04:00
Maarten Billemont
2b660adf00 Fix a NUL termination issue with aes decryption & add standard trace debugging. 2017-08-05 23:42:47 -04:00
Maarten Billemont
e15d01882f Update the mpsites file after the operation and memory cleanup. 2017-08-05 23:19:24 -04:00
Maarten Billemont
23491faccc Fix up and clean up base64 & aes code. 2017-08-05 21:52:00 -04:00
Maarten Billemont
5f2e1611f1 Fix mpw_tests.xml after purpose rename. 2017-08-05 19:14:25 -04:00
Maarten Billemont
9abacaf905 mpw_realloc solves some issues with the realloc API that can lead to leaks. 2017-08-05 19:04:42 -04:00
Maarten Billemont
322e056661 Implement algorithm support for hybrid personal passwords. 2017-08-05 17:33:45 -04:00
Maarten Billemont
228f8e4ed1 C API for hybrid passwords. 2017-08-04 10:43:46 -04:00
Maarten Billemont
d6415277d0 Wrap up error handling overhaul. 2017-08-04 09:36:03 -04:00
Maarten Billemont
db41a6635f Standardize C CLI exit codes. 2017-08-03 11:05:37 -04:00
Maarten Billemont
096919637f Abort CLI if master password doesn't match. 2017-08-03 01:13:15 -04:00
Maarten Billemont
434d70ebff Improve error handling for marshalling. 2017-08-03 01:07:19 -04:00
Maarten Billemont
bb8829b66f Fix mpw_push_buf regression. 2017-08-02 23:13:51 -04:00
Maarten Billemont
10f2c107c6 More improvements to error handling. 2017-08-02 14:26:41 -04:00
Maarten Billemont
03080b9ccd Render error messages as strings instead of internal codes. 2017-08-01 17:35:13 -04:00
Maarten Billemont
b00ad53e42 Some more error handling. 2017-08-01 17:13:30 -04:00
Maarten Billemont
99e286456e Better ftl failure handling. 2017-08-01 16:50:50 -04:00
Maarten Billemont
46cdf56944 Expose standard names for password type and purpose, and log them in the cli. 2017-08-01 14:34:15 -04:00
Maarten Billemont
9d5105a9e5 Rename identifiers to align better with their meaning (siteVariant -> keyPurpose, siteContext -> keyContext, siteType -> passwordType). 2017-08-01 13:45:54 -04:00
Maarten Billemont
3c5cb1673a Split the API into the three distinct phases of the mpw algorithm. 2017-08-01 08:31:39 -04:00
Maarten Billemont
13107063df Refactor marshall utilities out, some clean-up, and prepare iOS/macOS project for libjson-c 2017-07-28 09:50:26 -04:00
Maarten Billemont
8a73baa6bc Improved error detection and handling. 2017-07-23 17:05:49 -04:00
Maarten Billemont
b65fedf40d WIP - parsing JSON format. 2017-07-23 09:57:48 -04:00
Maarten Billemont
04ab276d93 Memory fixes to JSON export. 2017-07-23 00:48:38 -04:00
Maarten Billemont
6d88d6bde0 Refactor a bit. 2017-07-22 23:58:22 -04:00
Maarten Billemont
4103c6e659 Replace ftl by err. 2017-07-22 23:46:53 -04:00
Maarten Billemont
16004f2ffe Memory fixes & handle masterPassword verification, masterKey site algorithm scoping, etc. 2017-07-22 23:45:54 -04:00
Maarten Billemont
37c0d323d9 Complete parsing of mpsites for CLI defaults. 2017-07-22 21:38:53 -04:00
Maarten Billemont
560cb1a266 WIP performing marshalling of sites in C. 2017-07-15 21:13:49 -04:00
Maarten Billemont
738ad197b2 Fix the main thread lock-up detector across background events. 2017-06-06 22:10:02 -04:00
Maarten Billemont
cfcc5287db Fix bad assumption that there is always a zero'th group. 2017-06-04 09:46:41 -04:00
Maarten Billemont
0b5502b673 WIP site. 2017-06-04 09:35:27 -04:00
Maarten Billemont
d3e3c9d720 Fixes #174 - Login name copy button was made inoperative when hint was hidden. 2017-06-03 11:57:41 -04:00
Maarten Billemont
3c3f88d820 Initial work on a new web design. 2017-05-28 15:34:07 -04:00
Maarten Billemont
2e2c654ec9 Fix for fetchedResultsController getter, haslib() and ability to turn off libsodium. 2017-05-28 15:32:50 -04:00
Maarten Billemont
d361ae2381 Assist the user with store setup and allow continuing anyway. 2017-05-08 14:58:46 -04:00
Maarten Billemont
fcbb93762a Cleanup, renaming restructuring, etc. 2017-05-07 18:44:09 -04:00
Maarten Billemont
f86210f5da Ability to handle versions without suffix after platform. 2017-05-04 14:30:50 -04:00
Maarten Billemont
e96f678236 Introduce a main thread lockup test feature. 2017-05-04 13:57:12 -04:00
Maarten Billemont
8b9067ab4b Merge tag '2.5-ios-4'
2.5-ios-4
2017-05-01 18:44:08 -04:00
Maarten Billemont
5af383235a Fix issue causing site list to appear empty on login. 2017-05-01 18:43:16 -04:00
Maarten Billemont
25b13dfb22 Rollback temporary storyboard hack. 2017-05-01 18:41:55 -04:00
Maarten Billemont
635692ef09 Fix issue causing site list to appear empty on login. 2017-05-01 18:40:51 -04:00
Maarten Billemont
e6bab4e504 Support for associating a URL to sites. 2017-05-01 18:32:52 -04:00
Maarten Billemont
cd6b7e6051 Settle on a method of making the password cells visible in storyboard. 2017-04-30 19:08:34 -04:00
Maarten Billemont
b180202e07 Dismiss keyboard when dropping down preferences or app deactivates. 2017-04-30 18:54:07 -04:00
Maarten Billemont
f83f2af529 Fix store product images and http URL links. 2017-04-30 18:45:08 -04:00
Maarten Billemont
cf2c30cfe6 Convert store into template cells for products. 2017-04-30 17:48:03 -04:00
Maarten Billemont
834e94ebd5 Fix usage of dubious objectID in global context. 2017-04-29 23:52:57 -04:00
Maarten Billemont
6d9be3fdfe Add support for Answers and improved Fabric integration. 2017-04-29 23:03:50 -04:00
723 changed files with 42920 additions and 32074 deletions

28
.dockerignore Normal file
View File

@@ -0,0 +1,28 @@
# OS-Specific junk.
.DS_Store
Thumbs.db
# IntelliJ
.idea
*.iml
*.ipr
*.iws
# Xcode IDE
xcuserdata/
DerivedData/
# Generated
/platform-darwin/Resources/Media/Images.xcassets/
/platform-darwin/Podfile.lock
/platform-darwin/Pods/
# Gradle
build
.gradle
local.properties
/gradle/builds
/platform-android/.externalNativeBuild
# Git
.git

31
.gitignore vendored
View File

@@ -7,41 +7,20 @@ Thumbs.db
*.iml
*.ipr
*.iws
out
# Xcode IDE
xcuserdata/
DerivedData/
# Generated
/platform-independent/cli-c/VERSION
/platform-independent/cli-c/mpw-*.tar.gz
/platform-darwin/Resources/Media/Images.xcassets/
# Media
public/Press/Background.png
public/Press/Front-Page.png
public/Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
/platform-darwin/Podfile.lock
/platform-darwin/Pods/
# Gradle
build
!/build
.gradle
local.properties
# Maven
target
dependency-reduced-pom.xml
# C
core/c/*.o
core/c/lib/*/.unpacked
core/c/lib/*/.patched
core/c/lib/*/src
core/c/lib/include
platform-independent/cli-c/cli/*.o
platform-independent/cli-c/mpw-*.tar.gz
platform-independent/cli-c/mpw-*.tar.gz.sig
platform-independent/cli-c/mpw
platform-independent/cli-c/mpw-bench
platform-independent/cli-c/mpw-tests
platform-independent/cli-c/VERSION
/gradle/builds
/platform-android/.externalNativeBuild

18
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,18 @@
variables:
GIT_DEPTH: 3
GIT_SUBMODULE_STRATEGY: recursive
build_project:
stage: build
script:
- "( brew bundle )"
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
- "( ./lib/bin/build_libjson-c-macos clean && ./lib/bin/build_libjson-c-macos )"
- "( cd ./platform-independent/c/cli && ./clean && targets=all ./build && ./mpw-tests && ./mpw-cli-tests )"
- "( cd ./gradle && ./gradlew --stacktrace clean test )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Test' -scheme 'MasterPassword macOS' clean build )"
tags:
- brew
- java_9
- xcode_9

15
.gitmodules vendored
View File

@@ -17,8 +17,17 @@
path = platform-darwin/External/jrswizzle
url = git://github.com/jonmarimba/jrswizzle.git
[submodule "MasterPassword/Web/js/mpw-js"]
path = platform-independent/web-js/js/mpw-js
path = platform-independent/web/js/mpw-js
url = https://github.com/tmthrgd/mpw-js.git
[submodule "platform-darwin/External/libsodium"]
path = platform-darwin/External/libsodium
[submodule "lib/libsodium"]
path = lib/libsodium
url = https://github.com/jedisct1/libsodium.git
[submodule "lib/libjson-c"]
path = lib/libjson-c
url = https://github.com/json-c/json-c.git
[submodule "public/site"]
path = public/site
url = https://github.com/Lyndir/MasterPassword.git
branch = gh-pages
shallow = true
update = none

View File

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

6
Brewfile Normal file
View File

@@ -0,0 +1,6 @@
brew "libsodium"
brew "json-c"
brew "libtool"
brew "automake"
brew "autoconf"

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM debian:stable-slim
# For i386
#FROM i386/debian:stable-slim
#ENTRYPOINT ["linux32", "--"]
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN mkdir -p /usr/share/man/man1
RUN apt-get update && apt-get install -y default-jdk-headless git-core bash libtool automake autoconf make g++
RUN git clone --depth=3 $(: --shallow-submodules) --recurse-submodules https://gitlab.com/MasterPassword/MasterPassword.git /mpw
RUN cd /mpw/gradle && ./gradlew -i clean build

View File

@@ -1,11 +1,4 @@
[![Travis CI](http://img.shields.io/travis-ci/Lyndir/MasterPassword.png)](https://travis-ci.org/Lyndir/MasterPassword)
[![Join the chat at https://gitter.im/lyndir/MasterPassword](https://badges.gitter.im/lyndir/MasterPassword.svg)](https://gitter.im/lyndir/MasterPassword?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![license](https://img.shields.io/github/license/lyndir/masterpassword.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)
# [Master Password •••|](http://masterpasswordapp.com)
# [Master Password •••|](http://masterpassword.app)
Master Password is a completely new way of thinking about passwords.
@@ -13,9 +6,9 @@ It consists of an algorithm that implements the core idea and applications for v
To skip the intro and go straight to the information on how to use the code, [click here](#source-code).
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://ssl.masterpasswordapp.com/masterpassword-mac.zip), [📲 Android](https://ssl.masterpasswordapp.com/masterpassword-android.apk), [🖥 Desktop](https://ssl.masterpasswordapp.com/masterpassword-gui.jar), and [⌨ Console](https://ssl.masterpasswordapp.com/masterpassword-cli.tar.gz).
Master Password is available for [📲 iOS](https://itunes.apple.com/app/id510296984), [🖥 macOS](https://masterpassword.app/masterpassword-mac.zip), [📲 Android](https://masterpassword.app/masterpassword-android.apk), [🖥 Desktop](https://masterpassword.app/masterpassword-gui.jar), and [⌨ Console](https://masterpassword.app/masterpassword-cli.tar.gz).
Master Password is also available from the following package managers: [macOS: Homebrew](https://brew.sh/) (`brew install mpw`).
Master Password is also available from: [macOS: Homebrew](https://brew.sh/) (`brew install mpw`) and [Docker](https://www.docker.com/) (`docker run -ti registry.gitlab.com/masterpassword/masterpassword`).
Get in touch if you are interested in adding Master Password to any other package managers.
There are many reasons for using Master Password instead of an ordinary password manager, read below for the details, but if you want my personal favourites, they would be:
@@ -90,7 +83,7 @@ Master Password is *not* a password manager. It does not store your website pas
## How does it work?
The details of how Master Password works [are available here](http://masterpasswordapp.com/algorithm.html).
The details of how Master Password works [are available here](https://masterpassword.app/masterpassword-algorithm.pdf).
In short:
@@ -129,14 +122,14 @@ The `master-password` on the other hand, is only a simple phrase, which means it
5. I have another question.
Please don't hesitate to [get in touch](#support), we're more than happy to answer all your Master Password questions. Any problems or suggestions can be reported [as GitHub issues](https://github.com/Lyndir/MasterPassword/issues).
Please don't hesitate to [get in touch](#support), we're more than happy to answer all your Master Password questions. Any problems or suggestions can be reported [as GitLab issues](https://gitlab.com/MasterPassword/MasterPassword/issues/).
# Source Code
Master Password's algorithm is [documented](http://masterpasswordapp.com/algorithm.html) and its implementation is Free Software (GPLv3).
Master Password's algorithm is [documented](https://masterpassword.app/masterpassword-algorithm.pdf) and its implementation is [Free Software (GPLv3)](LICENSE).
@@ -194,49 +187,7 @@ Note that in order to build the Android application, you will need to have the A
Go into the `platform-independent/cli-c` directory and run `./build`. The native command-line client will then be built.
When the build completes, you will have an `mpw` binary you can use. You can copy it into your `PATH` or use the `./install` script to help you do so.
For example:
./build && sudo ./install
mpw -h
Normally, this is all you need to do, however note that there are a few dependencies that need to be met, depending on which targets you are building (by default, only the `mpw` target is built):
- `mpw`
The C implementation depends either on `libsodium` or Tarsnap's `scrypt` and `openssl-dev`.
We recommend you install `libsodium`. If `libsodium` is not installed when `./build` is executed, the script will try to download and statically link Tarsnap's `scrypt` instead. Tarsnap's `scrypt` depends on you having `openssl-dev` installed.
If you have `mpw_color` enabled (it is enabled by default), the build also depends on `ncurses-dev` to communicate with the terminal.
- `mpw-bench`
This tool compares the performance of a few cryptographic algorithms, including bcrypt. The `./build` script will try to automatically download and statically link `bcrypt`.
- `mpw-tests`
This tool runs a suite of tests to ensure the correct passwords are being generated by the algorithm under various circumstances. The test suite is declared in `mpw-tests.xml` which needs to exist in the current working directory when running the tool. In addition, `libxml2` is used to parse the file, so this target depends on you having it installed when running `./build`.
Finally, there are a few different ways you can modify the build process.
To build additional targets, set the `targets` environment variable:
targets='mpw mpw-tests' ./build
To pass additional compiler arguments, eg. add a library search path, pass them as arguments to the script:
./build -L/usr/local/lib
There are a few toggleable features, to change them, pass them as environment variables:
mpw_color=0 ./build
Currently, there is only one toggleable feature:
- `mpw_color`: [default: 1] Colorized Identicon, depends on `ncurses-dev`.
For detailed instructions, see [the native CLI instructions](platform-independent/c/README.md).
## Support

View File

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

View File

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

View File

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

View File

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

View File

@@ -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/>.
//==============================================================================
#include "mpw-algorithm.h"
#include "mpw-algorithm_v0.c"
#include "mpw-algorithm_v1.c"
#include "mpw-algorithm_v2.c"
#include "mpw-algorithm_v3.c"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_hash PearlHashSHA256
const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
if (!fullName || !masterPassword)
return NULL;
switch (algorithmVersion) {
case MPAlgorithmVersion0:
return mpw_masterKeyForUser_v0( fullName, masterPassword );
case MPAlgorithmVersion1:
return mpw_masterKeyForUser_v1( fullName, masterPassword );
case MPAlgorithmVersion2:
return mpw_masterKeyForUser_v2( fullName, masterPassword );
case MPAlgorithmVersion3:
return mpw_masterKeyForUser_v3( fullName, masterPassword );
default:
ftl( "Unsupported version: %d", algorithmVersion );
return NULL;
}
}
const char *mpw_passwordForSite(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion) {
if (!masterKey || !siteName)
return NULL;
switch (algorithmVersion) {
case MPAlgorithmVersion0:
return mpw_passwordForSite_v0( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext );
case MPAlgorithmVersion1:
return mpw_passwordForSite_v1( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext );
case MPAlgorithmVersion2:
return mpw_passwordForSite_v2( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext );
case MPAlgorithmVersion3:
return mpw_passwordForSite_v3( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext );
default:
ftl( "Unsupported version: %d", algorithmVersion );
return NULL;
}
}

View File

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

View File

@@ -1,140 +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/>.
//==============================================================================
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_hash PearlHashSHA256
static const char *mpw_templateForType_v0(MPSiteType type, uint16_t seedByte) {
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );
char const *template = count? templates[seedByte % count]: NULL;
free( templates );
return template;
}
static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedByte) {
const char *classCharacters = mpw_charactersInClass( characterClass );
return classCharacters[seedByte % strlen( classCharacters )];
}
static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 0 );
trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope );
// Calculate the master key salt.
// masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno );
return NULL;
}
trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey;
}
static const char *mpw_passwordForSite_v0(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
trc( "algorithm: v%d\n", 0 );
trc( "siteName: %s\n", siteName );
trc( "siteCounter: %d\n", siteCounter );
trc( "siteVariant: %d\n", siteVariant );
trc( "siteType: %d\n", siteType );
trc( "site scope: %s, context: %s\n", siteScope, siteContext? "<empty>": siteContext );
trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
siteScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
mpw_hex_l( htonl( siteCounter ) ),
mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
// Calculate the site seed.
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL;
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteName ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) {
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteContext ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
}
if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno );
return NULL;
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const char *sitePasswordSeed = (const char *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );
return NULL;
}
trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template.
const char *template = mpw_templateForType_v0( siteType, htons( sitePasswordSeed[0] ) );
trc( "type %d, template: %s\n", siteType, template );
if (strlen( template ) > 32) {
ftl( "Template too long for password seed: %lu", strlen( template ) );
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return NULL;
}
// Encode the password from the seed using the template.
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass_v0( template[c], htons( sitePasswordSeed[c + 1] ) );
trc( "class %c, index %u (0x%02X) -> character: %c\n",
template[c], htons( sitePasswordSeed[c + 1] ), htons( sitePasswordSeed[c + 1] ), sitePassword[c] );
}
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return sitePassword;
}

View File

@@ -1,125 +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/>.
//==============================================================================
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 1 );
trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope );
// Calculate the master key salt.
// masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno );
return NULL;
}
trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey;
}
static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
trc( "algorithm: v%d\n", 1 );
trc( "siteName: %s\n", siteName );
trc( "siteCounter: %d\n", siteCounter );
trc( "siteVariant: %d\n", siteVariant );
trc( "siteType: %d\n", siteType );
trc( "site scope: %s, context: %s\n", siteScope, siteContext? "<empty>": siteContext );
trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
siteScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
mpw_hex_l( htonl( siteCounter ) ),
mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
// Calculate the site seed.
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL;
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteName ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) {
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteContext ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
}
if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno );
return NULL;
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );
return NULL;
}
trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );
trc( "type %d, template: %s\n", siteType, template );
if (strlen( template ) > 32) {
ftl( "Template too long for password seed: %lu", strlen( template ) );
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return NULL;
}
// Encode the password from the seed using the template.
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass( template[c], sitePasswordSeed[c + 1] );
trc( "class %c, index %u (0x%02X) -> character: %c\n", template[c], sitePasswordSeed[c + 1], sitePasswordSeed[c + 1],
sitePassword[c] );
}
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return sitePassword;
}

View File

@@ -1,125 +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/>.
//==============================================================================
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 2 );
trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope );
// Calculate the master key salt.
// masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno );
return NULL;
}
trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey;
}
static const char *mpw_passwordForSite_v2(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
trc( "algorithm: v%d\n", 2 );
trc( "siteName: %s\n", siteName );
trc( "siteCounter: %d\n", siteCounter );
trc( "siteVariant: %d\n", siteVariant );
trc( "siteType: %d\n", siteType );
trc( "site scope: %s, context: %s\n", siteScope, siteContext? "<empty>": siteContext );
trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
siteScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
mpw_hex_l( htonl( siteCounter ) ),
mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
// Calculate the site seed.
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL;
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) {
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
}
if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno );
return NULL;
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );
return NULL;
}
trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );
trc( "type %d, template: %s\n", siteType, template );
if (strlen( template ) > 32) {
ftl( "Template too long for password seed: %lu", strlen( template ) );
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return NULL;
}
// Encode the password from the seed using the template.
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass( template[c], sitePasswordSeed[c + 1] );
trc( "class %c, index %u (0x%02X) -> character: %c\n", template[c], sitePasswordSeed[c + 1], sitePasswordSeed[c + 1],
sitePassword[c] );
}
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return sitePassword;
}

View File

@@ -1,125 +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/>.
//==============================================================================
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h"
#include "mpw-util.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_hash PearlHashSHA256
static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *masterPassword) {
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 3 );
trc( "fullName: %s (%zu)\n", fullName, strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope );
// Calculate the master key salt.
// masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL;
mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( strlen( fullName ) ) );
mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno );
return NULL;
}
trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt )
const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p );
mpw_free( masterKeySalt, masterKeySaltSize );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
return NULL;
}
trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey;
}
static const char *mpw_passwordForSite_v3(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext) {
const char *siteScope = mpw_scopeForVariant( siteVariant );
trc( "algorithm: v%d\n", 3 );
trc( "siteName: %s\n", siteName );
trc( "siteCounter: %d\n", siteCounter );
trc( "siteVariant: %d\n", siteVariant );
trc( "siteType: %d\n", siteType );
trc( "site scope: %s, context: %s\n", siteScope, siteContext? "<empty>": siteContext );
trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
siteScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
mpw_hex_l( htonl( siteCounter ) ),
mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
// Calculate the site seed.
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL;
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) {
mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
}
if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno );
return NULL;
}
trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize );
if (!sitePasswordSeed) {
ftl( "Could not allocate site seed: %d\n", errno );
return NULL;
}
trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );
trc( "type %d, template: %s\n", siteType, template );
if (strlen( template ) > 32) {
ftl( "Template too long for password seed: %lu", strlen( template ) );
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return NULL;
}
// Encode the password from the seed using the template.
char *const sitePassword = calloc( strlen( template ) + 1, sizeof( char ) );
for (size_t c = 0; c < strlen( template ); ++c) {
sitePassword[c] = mpw_characterFromClass( template[c], sitePasswordSeed[c + 1] );
trc( "class %c, index %u (0x%02X) -> character: %c\n", template[c], sitePasswordSeed[c + 1], sitePasswordSeed[c + 1],
sitePassword[c] );
}
mpw_free( sitePasswordSeed, sizeof( sitePasswordSeed ) );
return sitePassword;
}

View File

@@ -1,203 +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/>.
//==============================================================================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef COLOR
#include <curses.h>
#include <term.h>
#endif
#include "mpw-types.h"
#include "mpw-util.h"
const MPSiteType mpw_typeWithName(const char *typeName) {
// Lower-case and trim optionally leading "Generated" string from typeName to standardize it.
size_t stdTypeNameOffset = 0;
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[stdTypeNameSize] = '\0';
// Find what site type is represented by the type name.
if (0 == strcmp( stdTypeName, "x" ) || 0 == strcmp( stdTypeName, "max" ) || 0 == strcmp( stdTypeName, "maximum" ))
return MPSiteTypeGeneratedMaximum;
if (0 == strcmp( stdTypeName, "l" ) || 0 == strcmp( stdTypeName, "long" ))
return MPSiteTypeGeneratedLong;
if (0 == strcmp( stdTypeName, "m" ) || 0 == strcmp( stdTypeName, "med" ) || 0 == strcmp( stdTypeName, "medium" ))
return MPSiteTypeGeneratedMedium;
if (0 == strcmp( stdTypeName, "b" ) || 0 == strcmp( stdTypeName, "basic" ))
return MPSiteTypeGeneratedBasic;
if (0 == strcmp( stdTypeName, "s" ) || 0 == strcmp( stdTypeName, "short" ))
return MPSiteTypeGeneratedShort;
if (0 == strcmp( stdTypeName, "i" ) || 0 == strcmp( stdTypeName, "pin" ))
return MPSiteTypeGeneratedPIN;
if (0 == strcmp( stdTypeName, "n" ) || 0 == strcmp( stdTypeName, "name" ))
return MPSiteTypeGeneratedName;
if (0 == strcmp( stdTypeName, "p" ) || 0 == strcmp( stdTypeName, "phrase" ))
return MPSiteTypeGeneratedPhrase;
ftl( "Not a generated type name: %s", stdTypeName );
return MPSiteTypeGeneratedLong;
}
const char **mpw_templatesForType(MPSiteType type, size_t *count) {
if (!(type & MPSiteTypeClassGenerated)) {
ftl( "Not a generated type: %d", type );
*count = 0;
return NULL;
}
switch (type) {
case MPSiteTypeGeneratedMaximum: {
return mpw_alloc_array( *count, const char *,
"anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" );
}
case MPSiteTypeGeneratedLong: {
return mpw_alloc_array( *count, const char *,
"CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno",
"CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno",
"CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno",
"CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno",
"CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno",
"CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno",
"CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" );
}
case MPSiteTypeGeneratedMedium: {
return mpw_alloc_array( *count, const char *,
"CvcnoCvc", "CvcCvcno" );
}
case MPSiteTypeGeneratedBasic: {
return mpw_alloc_array( *count, const char *,
"aaanaaan", "aannaaan", "aaannaaa" );
}
case MPSiteTypeGeneratedShort: {
return mpw_alloc_array( *count, const char *,
"Cvcn" );
}
case MPSiteTypeGeneratedPIN: {
return mpw_alloc_array( *count, const char *,
"nnnn" );
}
case MPSiteTypeGeneratedName: {
return mpw_alloc_array( *count, const char *,
"cvccvcvcv" );
}
case MPSiteTypeGeneratedPhrase: {
return mpw_alloc_array( *count, const char *,
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
}
default: {
ftl( "Unknown generated type: %d", type );
*count = 0;
return NULL;
}
}
}
const char *mpw_templateForType(MPSiteType type, uint8_t seedByte) {
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );
char const *template = count? templates[seedByte % count]: NULL;
free( templates );
return template;
}
const MPSiteVariant mpw_variantWithName(const char *variantName) {
// Lower-case and trim optionally leading "generated" string from typeName to standardize it.
size_t stdVariantNameSize = strlen( variantName );
char stdVariantName[stdVariantNameSize + 1];
for (size_t c = 0; c < stdVariantNameSize; ++c)
stdVariantName[c] = (char)tolower( variantName[c] );
stdVariantName[stdVariantNameSize] = '\0';
if (0 == strcmp( stdVariantName, "p" ) || 0 == strcmp( stdVariantName, "password" ))
return MPSiteVariantPassword;
if (0 == strcmp( stdVariantName, "l" ) || 0 == strcmp( stdVariantName, "login" ))
return MPSiteVariantLogin;
if (0 == strcmp( stdVariantName, "a" ) || 0 == strcmp( stdVariantName, "answer" ))
return MPSiteVariantAnswer;
fprintf( stderr, "Not a variant name: %s", stdVariantName );
abort();
}
const char *mpw_scopeForVariant(MPSiteVariant variant) {
switch (variant) {
case MPSiteVariantPassword: {
return "com.lyndir.masterpassword";
}
case MPSiteVariantLogin: {
return "com.lyndir.masterpassword.login";
}
case MPSiteVariantAnswer: {
return "com.lyndir.masterpassword.answer";
}
default: {
fprintf( stderr, "Unknown variant: %d", variant );
abort();
}
}
}
const char *mpw_charactersInClass(char characterClass) {
switch (characterClass) {
case 'V':
return "AEIOU";
case 'C':
return "BCDFGHJKLMNPQRSTVWXYZ";
case 'v':
return "aeiou";
case 'c':
return "bcdfghjklmnpqrstvwxyz";
case 'A':
return "AEIOUBCDFGHJKLMNPQRSTVWXYZ";
case 'a':
return "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
case 'n':
return "0123456789";
case 'o':
return "@&%?,=[]_:-+*$#!'^~;()/.";
case 'x':
return "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()";
case ' ':
return " ";
default: {
fprintf( stderr, "Unknown character class: %c", characterClass );
abort();
}
}
}
const char mpw_characterFromClass(char characterClass, uint8_t seedByte) {
const char *classCharacters = mpw_charactersInClass( characterClass );
return classCharacters[seedByte % strlen( classCharacters )];
}

View File

@@ -1,109 +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/>.
//==============================================================================
#ifndef _MPW_TYPES_H
#define _MPW_TYPES_H
#include <stdlib.h>
#include <stdint.h>
#ifdef NS_ENUM
#define enum(_type, _name) NS_ENUM(_type, _name)
#else
#define enum(_type, _name) _type _name; enum
#endif
#define MP_dkLen 64
//// Types.
typedef enum( unsigned int, MPSiteVariant ) {
/** Generate a key for authentication. */
MPSiteVariantPassword,
/** Generate a name for identification. */
MPSiteVariantLogin,
/** Generate an answer to a security question. */
MPSiteVariantAnswer,
};
typedef enum( unsigned int, MPSiteTypeClass ) {
/** Generate the password. */
MPSiteTypeClassGenerated = 1 << 4,
/** Store the password. */
MPSiteTypeClassStored = 1 << 5,
};
typedef enum( unsigned int, MPSiteFeature ) {
/** Export the key-protected content data. */
MPSiteFeatureExportContent = 1 << 10,
/** Never export content. */
MPSiteFeatureDevicePrivate = 1 << 11,
};
typedef enum( unsigned int, MPSiteType) {
MPSiteTypeGeneratedMaximum = 0x0 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedLong = 0x1 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedMedium = 0x2 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedBasic = 0x4 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedShort = 0x3 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedPIN = 0x5 | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedName = 0xE | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeGeneratedPhrase = 0xF | MPSiteTypeClassGenerated | 0x0,
MPSiteTypeStoredPersonal = 0x0 | MPSiteTypeClassStored | MPSiteFeatureExportContent,
MPSiteTypeStoredDevicePrivate = 0x1 | MPSiteTypeClassStored | MPSiteFeatureDevicePrivate,
};
//// Type utilities.
/**
* @return The variant represented by the given name.
*/
const MPSiteVariant mpw_variantWithName(const char *variantName);
/**
* @return An internal string containing the scope identifier to apply when encoding for the given variant.
*/
const char *mpw_scopeForVariant(MPSiteVariant variant);
/**
* @return The type represented by the given name.
*/
const MPSiteType mpw_typeWithName(const char *typeName);
/**
* @return A newly allocated array of internal strings that express the templates to use for the given type.
* The amount of elements in the array is stored in count.
* If an unsupported type is given, count will be 0 and will return NULL.
* The array needs to be free'ed, the strings themselves must not be free'ed or modified.
*/
const char **mpw_templatesForType(MPSiteType type, size_t *count);
/**
* @return An internal string that contains the password encoding template of the given type
* for a seed that starts with the given byte.
*/
const char *mpw_templateForType(MPSiteType type, uint8_t seedByte);
/**
* @return An internal string that contains all the characters that occur in the given character class.
*/
const char *mpw_charactersInClass(char characterClass);
/**
* @return A character from given character class that encodes the given byte.
*/
const char mpw_characterFromClass(char characterClass, uint8_t seedByte);
#endif // _MPW_TYPES_H

View File

@@ -1,282 +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/>.
//==============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if COLOR
#include <unistd.h>
#include <curses.h>
#include <term.h>
#endif
#if HAS_CPERCIVA
#include <scrypt/crypto_scrypt.h>
#include <scrypt/sha256.h>
#elif HAS_SODIUM
#include "sodium.h"
#endif
#ifndef trc
int mpw_verbosity;
#endif
#include "mpw-util.h"
void mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
if (*bufferSize == (size_t)-1)
// The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content.
return;
*bufferSize += pushSize;
uint8_t *resizedBuffer = realloc( *buffer, *bufferSize );
if (!resizedBuffer) {
// realloc failed, we can't push. Mark the buffer as broken.
mpw_free( *buffer, *bufferSize - pushSize );
*bufferSize = (size_t)-1;
*buffer = NULL;
return;
}
*buffer = resizedBuffer;
uint8_t *pushDst = *buffer + *bufferSize - pushSize;
memcpy( pushDst, pushBuffer, pushSize );
}
void mpw_push_string(uint8_t **buffer, size_t *const bufferSize, const char *pushString) {
mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
}
void mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
}
void mpw_free(const void *buffer, const size_t bufferSize) {
if (buffer) {
memset( (void *)buffer, 0, bufferSize );
free( (void *)buffer );
}
}
void mpw_free_string(const char *string) {
mpw_free( string, strlen( string ) );
}
uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize,
uint64_t N, uint32_t r, uint32_t p) {
if (!secret || !salt)
return NULL;
uint8_t *key = malloc( keySize );
if (!key)
return NULL;
#if HAS_CPERCIVA
if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) {
mpw_free( key, keySize );
return NULL;
}
#elif HAS_SODIUM
if (crypto_pwhash_scryptsalsa208sha256_ll( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize) != 0 ) {
mpw_free( key, keySize );
return NULL;
}
#endif
return key;
}
uint8_t const *mpw_hmac_sha256(const uint8_t *key, const size_t keySize, const uint8_t *salt, const size_t saltSize) {
#if HAS_CPERCIVA
uint8_t *const buffer = malloc( 32 );
if (!buffer)
return NULL;
HMAC_SHA256_Buf( key, keySize, salt, saltSize, buffer );
return buffer;
#elif HAS_SODIUM
uint8_t *const buffer = malloc( crypto_auth_hmacsha256_BYTES );
if (!buffer)
return NULL;
crypto_auth_hmacsha256_state state;
if (crypto_auth_hmacsha256_init( &state, key, keySize ) != 0 ||
crypto_auth_hmacsha256_update( &state, salt, saltSize ) != 0 ||
crypto_auth_hmacsha256_final( &state, buffer ) != 0) {
mpw_free( buffer, crypto_auth_hmacsha256_BYTES );
return NULL;
}
return buffer;
#endif
return NULL;
}
const char *mpw_id_buf(const void *buf, size_t length) {
#if HAS_CPERCIVA
uint8_t hash[32];
SHA256_Buf( buf, length, hash );
return mpw_hex( hash, 32 );
#elif HAS_SODIUM
uint8_t hash[crypto_hash_sha256_BYTES];
crypto_hash_sha256( hash, buf, length );
return mpw_hex( hash, crypto_hash_sha256_BYTES );
#endif
}
static char **mpw_hex_buf = NULL;
static unsigned int mpw_hex_buf_i = 0;
const char *mpw_hex(const void *buf, size_t length) {
// FIXME
if (!mpw_hex_buf) {
mpw_hex_buf = malloc( 10 * sizeof( char * ) );
for (uint8_t i = 0; i < 10; ++i)
mpw_hex_buf[i] = NULL;
}
mpw_hex_buf_i = (mpw_hex_buf_i + 1) % 10;
mpw_hex_buf[mpw_hex_buf_i] = realloc( mpw_hex_buf[mpw_hex_buf_i], length * 2 + 1 );
for (size_t kH = 0; kH < length; kH++)
sprintf( &(mpw_hex_buf[mpw_hex_buf_i][kH * 2]), "%02X", ((const uint8_t *)buf)[kH] );
return mpw_hex_buf[mpw_hex_buf_i];
}
const char *mpw_hex_l(uint32_t number) {
return mpw_hex( &number, sizeof( number ) );
}
#ifdef COLOR
static int putvari;
static char *putvarc = NULL;
static int termsetup;
static int initputvar() {
if (!isatty(STDERR_FILENO))
return 0;
if (putvarc)
free( putvarc );
if (!termsetup) {
int status;
if (! (termsetup = (setupterm( NULL, STDERR_FILENO, &status ) == 0 && status == 1))) {
wrn( "Terminal doesn't support color (setupterm errno %d).\n", status );
return 0;
}
}
putvarc=(char *)calloc(256, sizeof(char));
putvari=0;
return 1;
}
static int putvar(int c) {
putvarc[putvari++]=c;
return 0;
}
#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_hmac_sha256( (const uint8_t *)masterPassword, strlen( masterPassword ), (const uint8_t *)fullName, strlen( fullName ) );
if (!identiconSeed)
return NULL;
char *colorString, *resetString;
#ifdef COLOR
if (initputvar()) {
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
tputs(tparm(tgetstr("AF", NULL), colorIdentifier), 1, putvar);
colorString = calloc(strlen(putvarc) + 1, sizeof(char));
strcpy(colorString, putvarc);
tputs(tgetstr("me", NULL), 1, putvar);
resetString = calloc(strlen(putvarc) + 1, sizeof(char));
strcpy(resetString, putvarc);
} else
#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 );
free( colorString );
free( resetString );
return identicon;
}
/**
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
*/
static int mpw_utf8_sizeof(unsigned char utf8Byte) {
if (!utf8Byte)
return 0;
if ((utf8Byte & 0x80) == 0)
return 1;
if ((utf8Byte & 0xC0) != 0xC0)
return 0;
if ((utf8Byte & 0xE0) == 0xC0)
return 2;
if ((utf8Byte & 0xF0) == 0xE0)
return 3;
if ((utf8Byte & 0xF8) == 0xF0)
return 4;
return 0;
}
const size_t mpw_utf8_strlen(const char *utf8String) {
size_t charlen = 0;
char *remainingString = (char *)utf8String;
for (int charByteSize; (charByteSize = mpw_utf8_sizeof( (unsigned char)*remainingString )); remainingString += charByteSize)
++charlen;
return charlen;
}

View File

@@ -1,119 +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/>.
//==============================================================================
#include <stdio.h>
#include <stdint.h>
//// Logging.
#ifndef trc
extern int mpw_verbosity;
#define trc_level 3
#define trc(...) \
if (mpw_verbosity >= 3) \
fprintf( stderr, __VA_ARGS__ )
#endif
#ifndef dbg
#define dbg_level 2
#define dbg(...) \
if (mpw_verbosity >= 2) \
fprintf( stderr, __VA_ARGS__ )
#endif
#ifndef inf
#define inf_level 1
#define inf(...) \
if (mpw_verbosity >= 1) \
fprintf( stderr, __VA_ARGS__ )
#endif
#ifndef wrn
#define wrn_level 0
#define wrn(...) \
if (mpw_verbosity >= 0) \
fprintf( stderr, __VA_ARGS__ )
#endif
#ifndef err
#define err_level -1
#define err(...) \
if (mpw_verbosity >= -1) \
fprintf( stderr, __VA_ARGS__ )
#endif
#ifndef ftl
#define ftl_level -2
#define ftl(...) \
do { \
if (mpw_verbosity >= -2) \
fprintf( stderr, __VA_ARGS__ ); \
exit( 2 ); \
} while (0)
#endif
//// Buffers and memory.
#define mpw_alloc_array(_count, _type, ...) ({ \
_type stackElements[] = { __VA_ARGS__ }; \
_count = sizeof( stackElements ) / sizeof( _type ); \
_type *allocElements = malloc( sizeof( stackElements ) ); \
memcpy( allocElements, stackElements, sizeof( stackElements ) ); \
allocElements; \
})
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
void mpw_push_buf(
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize);
/** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
void mpw_push_string(
uint8_t **buffer, size_t *const bufferSize, const char *pushString);
/** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
void mpw_push_int(
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
/** Free a buffer after zero'ing its contents. */
void mpw_free(
const void *buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents. */
void mpw_free_string(
const char *string);
//// Cryptographic functions.
/** Perform a scrypt-based key derivation on the given key using the given salt and scrypt parameters.
* @return A new keySize-size allocated buffer. */
uint8_t const *mpw_scrypt(
const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize,
uint64_t N, uint32_t r, uint32_t p);
/** Calculate a SHA256-based HMAC by encrypting the given salt with the given key.
* @return A new 32-byte allocated buffer. */
uint8_t const *mpw_hmac_sha256(
const uint8_t *key, const size_t keySize, const uint8_t *salt, const size_t saltSize);
//// Visualizers.
/** Encode a buffer as a string of hexadecimal characters.
* @return A C-string in a reused buffer, do not free or store it. */
const char *mpw_hex(const void *buf, size_t length);
const char *mpw_hex_l(uint32_t number);
/** Encode a fingerprint for a buffer.
* @return A C-string in a reused buffer, do not free or store it. */
const char *mpw_id_buf(const void *buf, size_t length);
/** 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);

View File

@@ -1,15 +0,0 @@
plugins {
id 'java'
}
description = 'Master Password Algorithm Implementation'
dependencies {
compile (group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.6-p10') {
exclude( module: 'joda-time' )
}
compile group: 'com.lambdaworks', name: 'scrypt', version: '1.4.0'
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
}

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Algorithm Implementation</name>
<description>The implementation of the Master Password algorithm</description>
<artifactId>masterpassword-algorithm</artifactId>
<packaging>jar</packaging>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-system</artifactId>
<version>1.6-p9</version>
<exclusions>
<exclusion>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -1,99 +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.Charsets;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.MessageDigests;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
/**
* @author lhunath, 2016-10-29
*/
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";
/**
* mpw: permit automatic update checks.
*/
public static final String env_checkUpdates = "MP_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;
}

View File

@@ -1,236 +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.google.common.collect.ImmutableSet;
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;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPSiteType {
GeneratedMaximum( "Max", "20 characters, contains symbols.", //
ImmutableList.of( "x", "max", "maximum" ), // NON-NLS
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPSiteTypeClass.Generated, 0x0 ),
GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( "l", "long" ), // NON-NLS
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
new MPTemplate( "CvcvnoCvccCvcv" ), new MPTemplate( "CvcvCvccnoCvcv" ),
new MPTemplate( "CvcvCvccCvcvno" ), new MPTemplate( "CvcvnoCvcvCvcc" ),
new MPTemplate( "CvcvCvcvnoCvcc" ), new MPTemplate( "CvcvCvcvCvccno" ),
new MPTemplate( "CvccnoCvccCvcv" ), new MPTemplate( "CvccCvccnoCvcv" ),
new MPTemplate( "CvccCvccCvcvno" ), new MPTemplate( "CvcvnoCvccCvcc" ),
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
new MPTemplate( "CvccCvcvCvccno" ) ), //
MPSiteTypeClass.Generated, 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 ),
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 ),
GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( "s", "short" ), // NON-NLS
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPSiteTypeClass.Generated, 0x4 ),
GeneratedPIN( "PIN", "4 numbers.", //
ImmutableList.of( "i", "pin" ), // NON-NLS
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPSiteTypeClass.Generated, 0x5 ),
GeneratedName( "Name", "9 letter name.", //
ImmutableList.of( "n", "name" ), // NON-NLS
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPSiteTypeClass.Generated, 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" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
MPSiteTypeClass.Generated, 0xF ),
StoredPersonal( "Personal", "AES-encrypted, exportable.", //
ImmutableList.of( "personal" ), // NON-NLS
ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
ImmutableList.of( "device" ), // NON-NLS
ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
static final Logger logger = Logger.get( MPSiteType.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 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) {
this.shortName = shortName;
this.description = description;
this.options = options;
this.templates = templates;
this.typeClass = typeClass;
this.typeIndex = typeIndex;
ImmutableSet.Builder<MPSiteFeature> typeFeaturesBuilder = ImmutableSet.builder();
for (final MPSiteFeature typeFeature : typeFeatures) {
typeFeaturesBuilder.add( typeFeature );
}
this.typeFeatures = typeFeaturesBuilder.build();
}
public String getShortName() {
return shortName;
}
public String getDescription() {
return description;
}
public List<String> getOptions() {
return options;
}
public MPSiteTypeClass getTypeClass() {
return typeClass;
}
public Set<MPSiteFeature> getTypeFeatures() {
return typeFeatures;
}
public int getType() {
int mask = typeIndex | typeClass.getMask();
for (final MPSiteFeature typeFeature : typeFeatures)
mask |= typeFeature.getMask();
return mask;
}
/**
* @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.
*
* @return The type registered with the given name.
*/
@Contract("!null -> !null")
public static MPSiteType forName(@Nullable final String name) {
if (name == null)
return null;
for (final MPSiteType type : values())
if (type.name().equalsIgnoreCase( name ))
return type;
throw logger.bug( "No type for name: %s", name );
}
/**
* @param typeClass The class for which we look up types.
*
* @return All types that support the given class.
*/
public static ImmutableList<MPSiteType> forClass(final MPSiteTypeClass typeClass) {
ImmutableList.Builder<MPSiteType> types = ImmutableList.builder();
for (final MPSiteType type : values())
if (type.getTypeClass() == typeClass)
types.add( type );
return types.build();
}
/**
* @param type The type for which we look up types.
*
* @return The type registered with the given type.
*/
public static MPSiteType forType(final int type) {
for (final MPSiteType siteType : values())
if (siteType.getType() == type)
return siteType;
throw logger.bug( "No type: %s", type );
}
/**
* @param mask The mask for which we look up types.
*
* @return All types that support the given mask.
*/
public static ImmutableList<MPSiteType> 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 );
return types.build();
}
public MPTemplate getTemplateAtRollingIndex(final int templateIndex) {
return templates.get( templateIndex % templates.size() );
}
}

View File

@@ -1,103 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/**
* @author lhunath, 14-12-02
*/
public enum MPSiteVariant {
Password( "Generate a key for authentication.", "Doesn't currently use a context.", //
ImmutableList.of( "p", "password" ), "com.lyndir.masterpassword" ), // NON-NLS
Login( "Generate a name for identification.", "Doesn't currently use a context.", //
ImmutableList.of( "l", "login" ), "com.lyndir.masterpassword.login" ), // NON-NLS
Answer( "Generate an answer to a security question.", "Empty for a universal site answer or\nthe most significant word(s) of the question.", //
ImmutableList.of( "a", "answer" ), "com.lyndir.masterpassword.answer" ); // NON-NLS
static final Logger logger = Logger.get( MPSiteType.class );
private final String description;
private final String contextDescription;
private final List<String> options;
private final String scope;
MPSiteVariant(final String description, final String contextDescription, final List<String> options, @NonNls final String scope) {
this.contextDescription = contextDescription;
this.options = options;
this.description = description;
this.scope = scope;
}
public String getDescription() {
return description;
}
public String getContextDescription() {
return contextDescription;
}
public List<String> getOptions() {
return options;
}
public String getScope() {
return scope;
}
/**
* @param option The option to select a variant with. It is matched case insensitively.
*
* @return The variant registered for the given option.
*/
public static MPSiteVariant forOption(final String option) {
for (final MPSiteVariant variant : values())
if (variant.getOptions().contains( option.toLowerCase( Locale.ROOT ) ))
return variant;
throw logger.bug( "No variant for option: %s", option );
}
/**
* @param name The name fromInt the variant to look up. It is matched case insensitively.
*
* @return The variant registered with the given name.
*/
@Contract("!null -> !null")
public static MPSiteVariant forName(@Nullable final String name) {
if (name == null)
return null;
for (final MPSiteVariant type : values())
if (type.name().equalsIgnoreCase( name ))
return type;
throw logger.bug( "No variant for name: %s", name );
}
}

View File

@@ -1,219 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Arrays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-08-30
*/
public abstract class MasterKey {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKey.class );
private static boolean allowNativeByDefault = true;
@Nonnull
private final String fullName;
private boolean allowNative = allowNativeByDefault;
@Nullable
private byte[] masterKey;
@SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final String fullName, final char[] masterPassword) {
return create( Version.CURRENT, fullName, masterPassword );
}
@Nonnull
@SuppressWarnings("MethodCanBeVariableArityMethod")
public static MasterKey create(final Version version, final String fullName, final char[] masterPassword) {
switch (version) {
case V0:
return new MasterKeyV0( fullName ).revalidate( masterPassword );
case V1:
return new MasterKeyV1( fullName ).revalidate( masterPassword );
case V2:
return new MasterKeyV2( fullName ).revalidate( masterPassword );
case V3:
return new MasterKeyV3( fullName ).revalidate( masterPassword );
}
throw new UnsupportedOperationException( strf( "Unsupported version: %s", version ) );
}
public static boolean isAllowNativeByDefault() {
return allowNativeByDefault;
}
/**
* Native libraries are useful for speeding up the performance of cryptographical functions.
* Sometimes, however, we may prefer to use Java-only code.
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
* <p/>
* This setter affects the default setting for any newly created {@link MasterKey}s.
*
* @param allowNative false to disallow the use of native libraries.
*/
public static void setAllowNativeByDefault(final boolean allowNative) {
allowNativeByDefault = allowNative;
}
protected MasterKey(@Nonnull final String fullName) {
this.fullName = fullName;
logger.trc( "fullName: %s", fullName );
}
@Nullable
@SuppressWarnings("MethodCanBeVariableArityMethod")
protected abstract byte[] deriveKey(char[] masterPassword);
public abstract Version getAlgorithmVersion();
@Nonnull
public String getFullName() {
return fullName;
}
public boolean isAllowNative() {
return allowNative;
}
public MasterKey setAllowNative(final boolean allowNative) {
this.allowNative = allowNative;
return this;
}
@Nonnull
protected byte[] getKey() {
Preconditions.checkState( isValid() );
return Preconditions.checkNotNull( masterKey );
}
public byte[] getKeyID() {
return idForBytes( getKey() );
}
public abstract String encode(@Nonnull String siteName, MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
MPSiteVariant siteVariant, @Nullable String siteContext);
public boolean isValid() {
return masterKey != null;
}
public void invalidate() {
if (masterKey != null) {
Arrays.fill( masterKey, (byte) 0 );
masterKey = null;
}
}
@SuppressWarnings("MethodCanBeVariableArityMethod")
public MasterKey revalidate(final char[] masterPassword) {
invalidate();
logger.trc( "masterPassword: %s", new String( masterPassword ) );
long start = System.currentTimeMillis();
masterKey = deriveKey( masterPassword );
if (masterKey == null)
logger.dbg( "masterKey calculation failed after %.2fs.", (double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
else
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
(double)(System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
return this;
}
protected abstract byte[] bytesForInt(int number);
protected abstract byte[] bytesForInt(@Nonnull UnsignedInteger number);
protected abstract byte[] idForBytes(byte[] bytes);
public enum Version {
/**
* bugs:
* - does math with chars whose signedness was platform-dependent.
* - miscounted the byte-length fromInt multi-byte site names.
* - miscounted the byte-length fromInt multi-byte full names.
*/
V0,
/**
* bugs:
* - miscounted the byte-length fromInt multi-byte site names.
* - miscounted the byte-length fromInt multi-byte full names.
*/
V1,
/**
* bugs:
* - miscounted the byte-length fromInt multi-byte full names.
*/
V2,
/**
* bugs:
* - no known issues.
*/
V3;
public static final Version CURRENT = V3;
public static Version fromInt(final int algorithmVersion) {
return values()[algorithmVersion];
}
public int toInt() {
return ordinal();
}
public String toBundleVersion() {
switch (this) {
case V0:
return "1.0";
case V1:
return "2.0";
case V2:
return "2.1";
case V3:
return "2.2";
}
throw new UnsupportedOperationException( strf( "Unsupported version: %s", this ) );
}
}
}

View File

@@ -1,170 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
* - V1: miscounted the byte-length fromInt multi-byte site names.
* - V0: does math with chars whose signedness was platform-dependent.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV0 extends MasterKey {
private static final int MP_intLen = 32;
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV0.class );
public MasterKeyV0(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V0;
}
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
String fullName = getFullName();
byte[] fullNameBytes = fullName.getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
return scrypt( masterKeySalt, mpBytes );
}
@Nullable
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try {
if (isAllowNative())
return SCrypt.scrypt( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
else
return SCrypt.scryptJ( mpBytes, masterKeySalt, MPConstant.scrypt_N, MPConstant.scrypt_r, MPConstant.scrypt_p, MPConstant.mpw_dkLen );
}
catch (final GeneralSecurityException e) {
logger.bug( e );
return null;
}
finally {
Arrays.fill( mpBytes, (byte) 0 );
}
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeedBytes = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
Arrays.fill( buf.array(), (byte) ((sitePasswordSeedBytes[i] > 0)? 0x00: 0xFF) );
buf.position( 2 );
buf.put( sitePasswordSeedBytes[i] ).rewind();
sitePasswordSeed[i] = buf.getInt() & 0xFFFF;
}
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0];
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1];
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
@Override
protected byte[] bytesForInt(final int number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number ).array();
}
@Override
protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number.intValue() ).array();
}
@Override
protected byte[] idForBytes(final byte[] bytes) {
return MPConstant.mpw_hash.of( bytes );
}
}

View File

@@ -1,103 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
* - V1: miscounted the byte-length fromInt multi-byte site names.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV1 extends MasterKeyV0 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV1.class );
public MasterKeyV1(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V1;
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
}

View File

@@ -1,102 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* bugs:
* - V2: miscounted the byte-length fromInt multi-byte full names.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV2 extends MasterKeyV1 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV2.class );
public MasterKeyV2(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V2;
}
@Override
public String encode(@Nonnull final String siteName, final MPSiteType siteType, @Nonnull UnsignedInteger siteCounter,
final MPSiteVariant siteVariant, @Nullable final String siteContext) {
Preconditions.checkArgument( siteType.getTypeClass() == MPSiteTypeClass.Generated );
Preconditions.checkArgument( !siteName.isEmpty() );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %d", siteCounter.longValue() );
logger.trc( "siteVariant: %d (%s)", siteVariant.ordinal(), siteVariant );
logger.trc( "siteType: %d (%s)", siteType.ordinal(), siteType );
if (siteCounter.longValue() == 0)
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPConstant.mpw_counter_timeout * 1000)) * MPConstant.mpw_counter_timeout );
String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = ((siteContext == null) || siteContext.isEmpty())? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( (siteContextBytes == null)? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, (siteContextBytes == null)? "<empty>": siteContext );
logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
(siteContextBytes == null)? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 );
int templateIndex = sitePasswordSeed[0] & 0xFF; // Mask the integer's sign.
MPTemplate template = siteType.getTemplateAtRollingIndex( templateIndex );
logger.trc( "type %s, template: %s", siteType, template.getTemplateString() );
StringBuilder password = new StringBuilder( template.length() );
for (int i = 0; i < template.length(); ++i) {
int characterIndex = sitePasswordSeed[i + 1] & 0xFF; // Mask the integer's sign.
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
logger.trc( "class %c, index %d (0x%02X) -> character: %c", characterClass.getIdentifier(), characterIndex,
sitePasswordSeed[i + 1], passwordCharacter );
password.append( passwordCharacter );
}
return password.toString();
}
}

View File

@@ -1,69 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import com.google.common.primitives.Bytes;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Arrays;
import javax.annotation.Nullable;
/**
* bugs:
* - no known issues.
*
* @author lhunath, 2014-08-30
*/
public class MasterKeyV3 extends MasterKeyV2 {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV3.class );
public MasterKeyV3(final String fullName) {
super( fullName );
}
@Override
public Version getAlgorithmVersion() {
return Version.V3;
}
@Nullable
@Override
protected byte[] deriveKey(final char[] masterPassword) {
byte[] fullNameBytes = getFullName().getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
return scrypt( masterKeySalt, mpBytes );
}
}

View File

@@ -1,18 +0,0 @@
plugins {
id 'java'
id 'net.ltgt.apt' version '0.9'
}
description = 'Master Password Site Model'
dependencies {
compile project(':masterpassword-algorithm')
compile group: 'joda-time', name: 'joda-time', version:'2.4'
compileOnly group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
apt group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
testCompile group: 'org.testng', name: 'testng', version:'6.8.5'
testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
}
test.useTestNG()

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Site Model</name>
<description>A persistence model for Master Password sites.</description>
<artifactId>masterpassword-model</artifactId>
<packaging>jar</packaging>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.0-rc1</version>
<scope>provided</scope>
</dependency>
<!-- TESTING -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

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

View File

@@ -1,143 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
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
*/
public class MPSite {
public static final MPSiteType DEFAULT_TYPE = MPSiteType.GeneratedLong;
public static final UnsignedInteger DEFAULT_COUNTER = UnsignedInteger.valueOf( 1 );
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 MPSite(final MPUser user, final String siteName) {
this( user, siteName, DEFAULT_TYPE, DEFAULT_COUNTER );
}
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;
}
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;
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSite) && Objects.equals( siteName, ((MPSite) obj).siteName ));
}
@Override
public int hashCode() {
return Objects.hashCode( siteName );
}
@Override
public String toString() {
return strf( "{MPSite: %s}", siteName );
}
}

View File

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

View File

@@ -1,37 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import java.util.Objects;
/**
* @author lhunath, 14-12-07
*/
public class MPSiteResult {
private final MPSite site;
public MPSiteResult(final MPSite site) {
this.site = site;
}
public MPSite getSite() {
return site;
}
@Override
public boolean equals(final Object obj) {
return (this == obj) || ((obj instanceof MPSiteResult) && Objects.equals( site, ((MPSiteResult) obj).site ));
}
@Override
public int hashCode() {
return Objects.hashCode( site );
}
@Override
public String toString() {
return strf( "{MPSiteResult: %s}", site );
}
}

View File

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

View File

@@ -1,153 +0,0 @@
package com.lyndir.masterpassword.model;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.masterpassword.MPSiteType;
import com.lyndir.masterpassword.MasterKey;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.joda.time.*;
/**
* @author lhunath, 14-12-07
*/
public class MPUser implements Comparable<MPUser> {
private final String fullName;
private final Collection<MPSite> sites = Sets.newHashSet();
@Nullable
private byte[] keyID;
private final MasterKey.Version algorithmVersion;
private int avatar;
private MPSiteType defaultType;
private ReadableInstant lastUsed;
public MPUser(final String fullName) {
this( fullName, 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 int getAvatar() {
return avatar;
}
public void setAvatar(final int avatar) {
this.avatar = avatar;
}
public MPSiteType getDefaultType() {
return defaultType;
}
public void setDefaultType(final MPSiteType defaultType) {
this.defaultType = defaultType;
}
public ReadableInstant getLastUsed() {
return lastUsed;
}
public void updateLastUsed() {
lastUsed = new Instant();
}
public Iterable<MPSite> getSites() {
return sites;
}
@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 );
}
@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;
}
}

View File

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

View File

@@ -1,39 +0,0 @@
package com.lyndir.masterpassword.model;
import com.google.common.collect.*;
import java.util.*;
/**
* @author lhunath, 14-12-05
*/
public abstract class MPUserManager {
private final Map<String, MPUser> usersByName = Maps.newHashMap();
static MPUserManager instance;
public static MPUserManager get() {
return instance;
}
protected MPUserManager(final Iterable<MPUser> users) {
for (final MPUser user : users)
usersByName.put( user.getFullName(), user );
}
public SortedSet<MPUser> getUsers() {
return FluentIterable.from( usersByName.values() ).toSortedSet( Ordering.natural() );
}
public MPUser getUserNamed(final String fullName) {
return usersByName.get( fullName );
}
public void addUser(final MPUser user) {
usersByName.put( user.getFullName(), user );
}
public void deleteUser(final MPUser user) {
usersByName.remove( user.getFullName() );
}
}

View File

@@ -1,9 +0,0 @@
/**
*
* @author lhunath, 15-02-04
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword.model;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@@ -1,13 +0,0 @@
plugins {
id 'java'
}
description = 'Master Password Test Suite'
dependencies {
compile project(':masterpassword-algorithm')
testCompile group: 'org.testng', name: 'testng', version:'6.8.5'
testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2'
}
test.useTestNG()

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Test Suite</name>
<description>The standard test suite to ensure the Master Password algorithm is operating as it should</description>
<artifactId>masterpassword-tests</artifactId>
<packaging>jar</packaging>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<!-- TESTING -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,112 +0,0 @@
//==============================================================================
// This file is part of Master Password.
// Copyright (c) 2011-2017, Maarten Billemont.
//
// Master Password is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Master Password is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You can find a copy of the GNU General Public License in the
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
//==============================================================================
package com.lyndir.masterpassword;
import static org.testng.Assert.*;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.NNFunctionNN;
import javax.annotation.Nonnull;
import org.jetbrains.annotations.NonNls;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MasterKeyTest {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyTest.class );
@NonNls
private MPTestSuite testSuite;
@BeforeMethod
public void setUp()
throws Exception {
testSuite = new MPTestSuite();
}
@Test
public void testEncode()
throws Exception {
testSuite.forEach( "testEncode", new NNFunctionNN<MPTests.Case, Boolean>() {
@Nonnull
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getAlgorithm(), testCase.getFullName(), testCase.getMasterPassword() );
assertEquals(
masterKey.encode( testCase.getSiteName(), testCase.getSiteType(), testCase.getSiteCounter(),
testCase.getSiteVariant(), testCase.getSiteContext() ),
testCase.getResult(), "[testEncode] Failed test case: " + testCase );
return true;
}
} );
}
@Test
public void testGetUserName()
throws Exception {
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
assertEquals( MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() ).getFullName(),
defaultCase.getFullName(), "[testGetUserName] Failed test case: " + defaultCase );
}
@Test
public void testGetKeyID()
throws Exception {
testSuite.forEach( "testGetKeyID", new NNFunctionNN<MPTests.Case, Boolean>() {
@Nonnull
@Override
public Boolean apply(@Nonnull final MPTests.Case testCase) {
MasterKey masterKey = MasterKey.create( testCase.getFullName(), testCase.getMasterPassword() );
assertEquals( CodeUtils.encodeHex( masterKey.getKeyID() ),
testCase.getKeyID(), "[testGetKeyID] Failed test case: " + testCase );
return true;
}
} );
}
@Test
public void testInvalidate()
throws Exception {
try {
MPTests.Case defaultCase = testSuite.getTests().getDefaultCase();
MasterKey masterKey = MasterKey.create( defaultCase.getFullName(), defaultCase.getMasterPassword() );
masterKey.invalidate();
masterKey.encode( defaultCase.getSiteName(), defaultCase.getSiteType(), defaultCase.getSiteCounter(),
defaultCase.getSiteVariant(), defaultCase.getSiteContext() );
fail( "[testInvalidate] Master key should have been invalidated, but was still usable." );
}
catch (final IllegalStateException ignored) {
}
}
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value />
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Lhunath" />
</component>
</project>

View File

@@ -1,7 +0,0 @@
<component name="CopyrightManager">
<copyright>
<option name="keyword" value="Copyright|License|WARRANTY" />
<option name="myName" value="GPLv3" />
<option name="notice" value="This file is part of &amp;#36;project.name.&#10;Copyright (c) &amp;#36;today.year.&#10;&#10;&amp;#36;project.name is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;(at your option) any later version.&#10;&#10;&amp;#36;project.name is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#10;GNU General Public License for more details.&#10;&#10;You can find a copy of the GNU General Public License in the&#10;LICENSE file. Alternatively, see &lt;http://www.gnu.org/licenses/&gt;." />
</copyright>
</component>

View File

@@ -1,13 +0,0 @@
<component name="CopyrightManager">
<settings>
<module2copyright>
<element module="masterpassword" copyright="Master Password" />
</module2copyright>
<LanguageOptions name="__TEMPLATE__">
<option name="block" value="false" />
<option name="separateBefore" value="true" />
<option name="separateAfter" value="true" />
<option name="filler" value="=" />
</LanguageOptions>
</settings>
</component>

View File

@@ -1,9 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="projectProfile" value="Lhunath" />
<option name="useProjectProfile" value="false" />
<option name="PROJECT_PROFILE" value="Lhunath" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

29
gradle/.idea/misc.xml generated
View File

@@ -1,40 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/../../opal/pom.xml" />
</list>
</option>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="javax.annotation.Nullable" />
<option name="myDefaultNotNull" value="javax.annotation.Nonnull" />
<option name="myNullables">
<value>
<list size="4">
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="4" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="javax.validation.constraints.NotNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="10" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ThriftCompiler">
<compilers />
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@@ -1,30 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Android" type="AndroidRunConfigurationType" factoryName="Android App">
<module name="android" />
<option name="DEPLOY" value="true" />
<option name="ARTIFACT_NAME" value="" />
<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="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<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>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY_CLASS" value="" />
<method />
</configuration>
</component>

View File

@@ -1,16 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="GUI" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="com.lyndir.masterpassword.gui.GUI" />
<option name="VM_PARAMETERS" value="" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="ENABLE_SWING_INSPECTOR" value="false" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<module name="gui" />
<envs />
<method />
</configuration>
</component>

View File

@@ -1,29 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Tests" type="TestNG" factoryName="TestNG">
<module name="tests" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="SUITE_NAME" value="" />
<option name="PACKAGE_NAME" value="com.lyndir.masterpassword" />
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="GROUP_NAME" value="" />
<option name="TEST_OBJECT" value="PACKAGE" />
<option name="VM_PARAMETERS" value="-ea" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../core/java/tests" />
<option name="OUTPUT_DIRECTORY" value="" />
<option name="ANNOTATION_TYPE" />
<option name="ENV_VARIABLES" />
<option name="PASS_PARENT_ENVS" value="true" />
<option name="TEST_SEARCH_SCOPE">
<value defaultName="singleModule" />
</option>
<option name="USE_DEFAULT_REPORTERS" value="false" />
<option name="PROPERTIES_FILE" value="" />
<envs />
<properties />
<listeners />
<method />
</configuration>
</component>

View File

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

15
gradle/README.md Normal file
View File

@@ -0,0 +1,15 @@
To build a release distribution:
Desktop:
STORE_PW=$(mpw masterpassword.keystore) KEY_PW_DESKTOP=$(mpw masterpassword-desktop) gradle --no-daemon clean masterpassword-gui:shadowJar
Android:
STORE_PW=$(mpw masterpassword.keystore) KEY_PW_ANDROID=$(mpw masterpassword-android) gradle --no-daemon clean masterpassword-android:assembleRelease
Note:
- At the time of writing, Android does not build with JDK 9+. As such, the above command must be ran with JAVA_HOME pointing to JDK 7-8.
- The release keystores are not included in the repository. They are maintained by Maarten Billemont (lhunath@lyndir.com).

View File

@@ -1,34 +1,38 @@
allprojects {
//apply plugin: 'findbugs'
apply plugin: 'findbugs'
group = 'com.lyndir.masterpassword'
version = 'GIT-SNAPSHOT'
version = '2.7.5'
tasks.withType(JavaCompile) {
sourceCompatibility = '1.7'
targetCompatibility = '1.7'
tasks.withType( JavaCompile ) {
options.encoding = 'UTF-8'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
tasks.withType(FindBugs) {
tasks.withType( FindBugs ) {
reports {
xml.enabled false
html.enabled true
xml.enabled = false
html.enabled = true
}
}
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath group: 'com.android.tools.build', name: 'gradle', version: '2.2.3'
classpath group: 'com.android.tools.build', name: 'gradle', version: '3.1.0'
}
}
subprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'http://maven.lyndir.com' }
maven { url 'https://maven.lyndir.com' }
}
}

View File

@@ -1 +1,4 @@
org.gradle.daemon=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx1536M
android.enableD8.desugaring=true

Binary file not shown.

View File

@@ -1,6 +1,5 @@
#Sun Mar 26 09:11:08 EDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

6
gradle/gradlew vendored
View File

@@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
warn () {
echo "$*"
}
die ( ) {
die () {
echo
echo "$*"
echo
@@ -155,7 +155,7 @@ if $cygwin ; then
fi
# Escape application args
save ( ) {
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}

View File

@@ -1,31 +1,40 @@
class Mpw < Formula
homepage "http://masterpasswordapp.com"
url "https://ssl.masterpasswordapp.com/mpw-2.1-cli4-0-gf6b2287.tar.gz"
sha1 "036b3d8f4bd6f0676ae16e7e9c3de65f6030874f"
version "2.1-cli4"
desc "Stateless/deterministic password and identity manager"
homepage "https://masterpassword.app/"
url "https://masterpassword.app/mpw-2.6-cli-5-0-g344771db.tar.gz"
version "2.6-cli-5"
sha256 "954c07b1713ecc2b30a07bead9c11e6204dd774ca67b5bdf7d2d6ad1c4eec170"
revision 1
head "https://gitlab.com/MasterPassword/MasterPassword.git"
depends_on "automake" => :build
depends_on "autoconf" => :build
depends_on "openssl"
resource "libscrypt" do
url "http://masterpasswordapp.com/libscrypt-b12b554.tar.gz"
sha1 "ee871e0f93a786c4e3622561f34565337cfdb815"
bottle do
cellar :any
sha256 "46677cf8649983d5b77103d2ca56d9ad3697808ecc406f626a3462a089f932da" => :high_sierra
sha256 "19bf22915b3c534ad3ee6f1dfc20f142d53ae6c0c88757ae2632b7b1daa6667f" => :sierra
sha256 "7090c3d31289d2ac5529bd0a6bae2632a36ba7fcd4bb7974248bb36a15f67c7e" => :el_capitan
end
option "without-json-c", "Disable JSON configuration support"
option "without-ncurses", "Disable colorized identicon support"
depends_on "libsodium"
depends_on "json-c" => :recommended
depends_on "ncurses" => :recommended
def install
resource("libscrypt").stage buildpath/"lib/scrypt"
touch "lib/scrypt/.unpacked"
cd "platform-independent/cli-c" if build.head?
ENV["targets"] = "mpw"
ENV["mpw_json"] = build.with?("json-c") ? "1" : "0"
ENV["mpw_color"] = build.with?("ncurses") ? "1" : "0"
ENV["targets"] = "mpw mpw-tests"
system "./build"
system "./mpw-tests"
system "./mpw-cli-tests"
bin.install "mpw"
end
test do
assert_equal "Jejr5[RepuSosp",
shell_output("mpw -u 'Robert Lee Mitchell' -P 'banana colored duckling' masterpasswordapp.com").strip
shell_output("#{bin}/mpw -q -Fnone -u 'Robert Lee Mitchell' -M 'banana colored duckling' -tlong -c1 -a3 'masterpasswordapp.com'").strip
end
end

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath</groupId>
<artifactId>lyndir</artifactId>
<version>1.22</version>
</parent>
<name>Master Password</name>
<description>A Java implementation of the Master Password algorithm.</description>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>masterpassword-tests</module>
<module>masterpassword-algorithm</module>
<module>masterpassword-model</module>
<module>masterpassword-cli</module>
<module>masterpassword-gui</module>
</modules>
<profiles>
<profile>
<id>release</id>
<modules>
<module>masterpassword-android</module>
</modules>
</profile>
<profile>
<id>mod:android</id>
<modules>
<module>masterpassword-android</module>
</modules>
</profile>
</profiles>
<!-- REMOTE ARTIFACT REPOSITORIES -->
<repositories>
<repository>
<id>lyndir</id>
<name>Lyndir Repository</name>
<url>http://maven.lyndir.com</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
</repository>
</repositories>
</project>

View File

@@ -1,19 +1,27 @@
rootProject.name = 'masterpassword'
def local = new Properties()
def localFile = file( 'local.properties' )
localFile.exists() && local.load( localFile.newDataInputStream() )
include 'masterpassword-core'
project( ':masterpassword-core' ).projectDir = new File( '../platform-independent/c/core' )
include 'masterpassword-algorithm'
project(':masterpassword-algorithm').projectDir = new File( '../core/java/algorithm' )
project( ':masterpassword-algorithm' ).projectDir = new File( '../platform-independent/java/algorithm' )
include 'masterpassword-model'
project(':masterpassword-model').projectDir = new File( '../core/java/model' )
project( ':masterpassword-model' ).projectDir = new File( '../platform-independent/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' )
project( ':masterpassword-tests' ).projectDir = new File( '../platform-independent/java/tests' )
include 'masterpassword-gui'
project(':masterpassword-gui').projectDir = new File( '../platform-independent/gui-java' )
project( ':masterpassword-gui' ).projectDir = new File( '../platform-independent/java/gui' )
include 'masterpassword-android'
project(':masterpassword-android').projectDir = new File( '../platform-android' )
if (local.containsKey( 'sdk.dir' ) && file( local.getProperty( 'sdk.dir' ) ).exists()) {
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." )
}

379
lib/bin/build_lib Executable file
View File

@@ -0,0 +1,379 @@
#!/usr/bin/env bash
#
# Your build script should simply source this script, optionally override any build hooks and then invoke `build`.
# The build product should be available under `build-<platform>~/out`, under the library path.
#
# Hook lifecycle:
# - build
# - initialize
# - needs
# - clean & exit (only if script was ran with "clean" argument)
# - prepare
# - clean
# - config
# - target
# - prepare
# - configure
# - build
# - finalize
# - merge
# - clean
#
# You can override any of these hooks to provide a custom implementation or call their underscore variant to delegate to the default implementation.
# For example:
# target_prepare() { make -s distclean; }
# target_configure() { _target_configure "$@" --enable-minimal; }
set -e
PATH+=:/usr/local/bin
# needs <binary> ...
#
# Utility for ensuring all tools needed by the script are installed prior to starting.
needs() { _needs "$@"; }
_needs() {
local failed=0
for spec; do
IFS=: read pkg tools <<< "$spec"
IFS=, read -a tools <<< "${tools:-$pkg}"
for tool in "${tools[@]}"; do
hash "$tool" 2>/dev/null && continue 2
done
echo >&2 "Missing: $pkg. Please install this package."
(( failed++ ))
done
return $failed
}
# initialize <prefix> <platform>
#
# The build script invokes this once prior to all other actions if the user wants a clean slate.
initialize() { _initialize "$@"; }
_initialize() {
initialize_needs "$@"
}
# initialize_needs <prefix> <platform>
#
# Check if all tools needed for the default implementations are available.
#
# By default, this will check for `libtool` (for libtoolize), `automake` (for aclocal), `autoconf` (for autoreconf) and make.
initialize_needs() { _initialize_needs "$@"; }
_initialize_needs() {
if [[ $platform = windows ]]; then
needs cmd
export VSINSTALLDIR="${VSINSTALLDIR:-$(cd "$(cygpath -F 0x002a)/Microsoft Visual Studio"/*/*/Common7/.. && pwd)}"
[[ -e "$VSINSTALLDIR/Common7/Tools/VsMSBuildCmd.bat" ]] || { echo >&2 "Missing: msbuild. Please install 'Build Tools for Visual Studio'."; return 1; }
else
needs libtool:libtoolize,glibtoolize automake autoconf make
fi
}
# clean <prefix> <platform>
#
# Fully clean up the library code, restoring it to a pristine state.
#
# By default, this will wipe the prefix, run `make distclean` and `git clean -fdx`.
clean() { _clean "$@"; }
_clean() {
if [[ $platform = windows ]]; then
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Clean' > .clean.bat
cmd //c .clean.bat
rm -f .clean.bat
elif [[ -e Makefile ]] && make -s distclean; then :
elif [[ -e .git ]] && git clean -fdx; then :
fi
rm -rf "$prefix"
}
# prepare <prefix> <platform> [ <arch> ... ]
#
# Configure the library for building the <arch>s on this machine.
# The build script invokes this once prior to building each of its targets.
# The <prefix> has been newly created.
#
# By default, this will run `autoreconf`.
prepare() { _prepare "$@"; }
_prepare() {
prepare_clean "$@"
prepare_config "$@"
}
# prepare_clean <prefix> <platform> [ <arch> ... ]
#
# Perform any necessary clean-up of the library code prior to building.
#
# By default, this will wipe and re-create the prefix.
prepare_clean() { _prepare_clean "$@"; }
_prepare_clean() {
local prefix=$1 platform=$2; shift 2
rm -rf "$prefix"
install -d "$prefix/out"
}
# prepare_config <prefix> <platform> [ <arch> ... ]
#
# Configure the library for building the <arch>s on this machine.
#
# By default, this will run `autoreconf`.
prepare_config() { _prepare_config "$@"; }
_prepare_config() {
local prefix=$1 platform=$2; shift 2
[[ -e "$prefix/out/.prepared" ]] && return
if [[ $platform = windows ]]; then :
else
autoreconf --verbose --install --force 2> >(sed 's/^\([^:]*\):[0-9]\{1,\}: /\1: /')
fi
touch "$prefix/out/.prepared"
}
# target <prefix> <platform> <arch>
#
# Build the library for the given <arch> and <platform> into the given <prefix>.
# The build script invokes this function when it's ready to build the library's code.
# Generic platform-specific environment setup has been done.
target() { _target "$@"; }
_target() {
target_prepare "$@"
target_configure "$@"
target_build "$@"
}
# target_prepare <prefix> <platform> <arch>
#
# Prepare the library configuration for building the target.
#
# By default, this will run `make clean` if a Makefile is found.
target_prepare() { _target_prepare "$@"; }
_target_prepare() {
local prefix=$1 platform=$2 arch=$3; shift 3
if [[ $platform = windows ]]; then :
else
[[ ! -e Makefile ]] || make -s clean
fi
}
# target_configure <prefix> <platform> <arch> [ <args> ... ]
#
# Configure the library for building the target.
#
# By default, this will run `./configure --host=<host> --prefix=<prefix>/<arch> <args>`.
# By default, some platform-specific arguments will be passed in as well as
# --enable-pic --disable-pie to ensure the resulting library can be linked again.
target_configure() { _target_configure "$@"; }
_target_configure() {
local prefix=$1 platform=$2 arch=$3; shift 3
case "$platform" in
'windows')
return
;;
'android')
host=( "$SDKROOT"/*-android* ) host=${host##*/}
set -- --with-sysroot="$SDKROOT/sysroot" "$@"
;;
'ios')
[[ $arch = *arm* ]] && host=arm || host=$arch
host+=-apple
set -- --disable-shared "$@"
;;
esac
./configure ${host:+--host="$host"} --enable-pic --disable-pie --prefix="$prefix/$arch" "$@"
}
# target_build <prefix> <platform> <arch>
#
# Build the library code for the target.
#
# By default, this will run `make check install`.
target_build() { _target_build "$@"; }
_target_build() {
local prefix=$1 platform=$2 arch=$3; shift 3
if [[ $platform = windows ]]; then
# I cannot for the life of me figure out how to pass this command directly into cmd.
printf '"%%VSINSTALLDIR%%\Common7\Tools\VsMSBuildCmd.bat" && msbuild /t:Rebuild /p:Configuration=ReleaseDLL;Platform=%s;OutDir=%s' "$arch" "$(cygpath -w "${prefix##$PWD/}/$arch/")" > .build.bat
cmd //c .build.bat
rm -f .build.bat
else
local cores=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null ||:)
make -j"${cores:-3}" install
fi
}
# finalize <prefix> <platform> [ <arch> ... ]
#
# Prepare the final build product.
# The build script invokes this once after a successful build of all targets.
finalize() { _finalize "$@"; }
_finalize() {
finalize_merge "$@"
finalize_clean "$@"
}
# finalize_merge <prefix> <platform> [ <arch> ... ]
#
# Merge all targets into a product the application can use, available at `<prefix>/out`.
#
# By default, this will copy the headers to `<prefix>/out/include`, install libraries into `<prefix>/out/lib` and mark the output product as successful.
finalize_merge() { _finalize_merge "$@"; }
_finalize_merge() {
local prefix=$1 platform=$2; shift 2
local archs=( "$@" )
[[ -e "$prefix/$archs/include" ]] && mv -f -- "$prefix/$archs/include" "$prefix/out/"
install -d "$prefix/out/lib"
case "$platform" in
'linux')
for arch in "${archs[@]}"; do
install -d "$prefix/out/lib/$arch"
install -p "$prefix/$arch/lib/"*.a "$prefix/out/lib/$arch/"
done
;;
'windows')
for arch in "${archs[@]}"; do
install -d "$prefix/out/lib/$arch"
install -p "$prefix/$arch/"*.lib "$prefix/out/lib/$arch/"
done
;;
'macos'|'ios')
for lib in "$prefix/$archs/lib/"*; do
if lipo -info "$lib" >/dev/null 2>&1; then
local lib=("${lib##*/}") libs=("${archs[@]/#/$prefix/}") libs=("${libs[@]/%//lib/$lib}")
lipo -create "${libs[@]}" -output "$prefix/out/lib/$lib"
fi
done
;;
'android')
for arch in "${archs[@]}"; do
local abi=$arch
case "$arch" in
'arm') abi='armeabi-v7a' ;;
'arm64') abi='arm64-v8a' ;;
esac
install -d "$prefix/out/lib/$abi"
install -p "$prefix/$arch/lib/"*.so "$prefix/out/lib/$abi"
done
;;
esac
touch "$prefix/out/.success"
}
# finalize_clean <prefix> [ <arch> ... ]
#
# Clean up the library after a successful build (eg. housekeeping of temporary files).
#
# By default, this will run `make clean`.
finalize_clean() { _finalize_clean "$@"; }
_finalize_clean() {
[[ ! -e Makefile ]] || make -s clean
}
# build <name> [<platform>]
#
# Build the library <name> (found at ../<name>) for platform <platform> (or "host" if unspecified).
build() { _build "$@"; }
_build() {
local name=$1 platform=${2:-host}
local path="../$name"
[[ $path = /* ]] || path="${BASH_SOURCE%/*}/$path"
cd "$path"
if [[ $platform = host ]]; then
case "$(uname -s)" in
'Darwin') platform='macos' archs=( "$(uname -m)" ) ;;
esac
fi
if (( ! ${#archs[@]} )); then
case "$platform" in
'macos') archs=( 'x86_64' ) ;;
'ios') archs=( 'i386' 'x86_64' 'armv7' 'armv7s' 'arm64' ) ;;
'android') archs=( 'arm' 'arm64' 'x86' 'x86_64' ) ;;
'windows') archs=( 'Win32' 'x64' ) ;;
*) archs=( 'i386' 'x86_64' ) ;;
esac
fi
local prefix="$PWD/build-$platform~"
initialize "$prefix" "$platform"
# "clean" argument wipes the lib clean and exits. If .success exists in prefix output, skip build.
if [[ ${BASH_ARGV[@]:(-1)} = clean ]]; then
clean "$prefix" "$platform"
exit
elif [[ -e "$prefix"/out/.success ]]; then
echo >&2 "Skipping build for $platform: output product already built successfully."
exit
fi
# Prepare the output location and build configuration.
prepare "$prefix" "$platform" "${archs[@]}"
# Repeat the build for each individual architecture.
for arch in "${archs[@]}"; do (
# Set up a base environment for the platform.
case "$platform" in
'windows')
;;
'macos')
SDKROOT="$(xcrun --show-sdk-path --sdk macosx)"
export PATH="$(xcrun --show-sdk-platform-path --sdk macosx)/usr/bin:$PATH"
export CFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $CFLAGS"
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET:-10.8} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
;;
'ios')
case "$arch" in
*'arm'*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphoneos)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphoneos)/usr/bin:$PATH"
export CFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -O2 -g -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CFLAGS"
export LDFLAGS="-arch $arch -mthumb -fembed-bitcode -flto -isysroot $SDKROOT -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
;;
*)
SDKROOT="$(xcrun --show-sdk-path --sdk iphonesimulator)"
export PATH="$(xcrun --show-sdk-platform-path --sdk iphonesimulator)/usr/bin:$PATH"
export CFLAGS="-arch $arch -flto -O2 -g -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $CFLAGS"
export LDFLAGS="-arch $arch -flto -isysroot $SDKROOT -mios-simulator-version-min=${IPHONEOS_DEPLOYMENT_TARGET:-8.0} $LDFLAGS"
export CPPFLAGS="$CFLAGS $CPPFLAGS"
;;
esac
;;
'android')
[[ -x $ANDROID_NDK_HOME/build/ndk-build ]] || { echo >&2 "Android NDK not found. Please set ANDROID_NDK_HOME."; return 1; }
SDKROOT="$prefix/$arch/ndk"
# Platform 21 is lowest that supports x86_64
"$ANDROID_NDK_HOME/build/tools/make-standalone-toolchain.sh" --force --install-dir="$SDKROOT" --platform='android-21' --arch="$arch"
export PATH="$SDKROOT/bin:$PATH"
export CFLAGS="-O2 -g $CFLAGS"
export LDFLAGS="-avoid-version $LDFLAGS"
export CC='clang'
# For GCC:
# arm CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb" LDFLAGS="-Wl,--fix-cortex-a8"
# arm64 CFLAGS="-march=armv8-a"
# x86 CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32"
# x86_64 CFLAGS="-march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel"
;;
esac
target "$prefix" "$platform" "$arch"
); done
finalize "$prefix" "$platform" "${archs[@]}"
}

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
autoreconf() {
command autoreconf -Iautoconf-archive/m4 "$@"
}
build libjson-c android

8
lib/bin/build_libjson-c-ios Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
autoreconf() {
command autoreconf -Iautoconf-archive/m4 "$@"
}
build libjson-c ios

8
lib/bin/build_libjson-c-linux Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
autoreconf() {
command autoreconf -Iautoconf-archive/m4 "$@"
}
build libjson-c linux

8
lib/bin/build_libjson-c-macos Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
autoreconf() {
command autoreconf -Iautoconf-archive/m4 "$@"
}
build libjson-c macos

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
autoreconf() {
command autoreconf -Iautoconf-archive/m4 "$@"
}
build libjson-c windows

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
build libsodium android

4
lib/bin/build_libsodium-ios Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
build libsodium ios

4
lib/bin/build_libsodium-linux Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
build libsodium linux

4
lib/bin/build_libsodium-macos Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
build libsodium macos

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
source "${BASH_SOURCE%/*}/build_lib"
finalize_merge() {
local prefix=$1 platform=$2; shift 2
local archs=( "$@" )
cp -a "src/libsodium/include" "$prefix/out"
_finalize_merge "$prefix" "$platform" "${archs[@]}"
}
build libsodium windows

1
lib/libjson-c Submodule

Submodule lib/libjson-c added at 3df1f98b4a

1
lib/libsodium Submodule

Submodule lib/libsodium added at 850edc1175

View File

@@ -0,0 +1,24 @@
project( mpw-core C )
cmake_minimum_required( VERSION 3.0.0 )
add_library( mpw SHARED
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/base64.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/aes.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-types.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-util.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal-util.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-jni.c" )
add_library( sodium SHARED IMPORTED )
set_target_properties( sodium PROPERTIES IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../lib/libsodium/build-android~/out/lib/${ANDROID_ABI}/libsodium.so" )
target_include_directories( mpw PRIVATE "${PROJECT_SOURCE_DIR}/../lib/libsodium/build-android~/out/include" )
target_compile_definitions( mpw PRIVATE -DMPW_SODIUM=1 )
target_link_libraries( mpw PRIVATE sodium )
add_library( json-c SHARED IMPORTED )
set_target_properties( json-c PROPERTIES IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../lib/libjson-c/build-android~/out/lib/${ANDROID_ABI}/libjson-c.so" )
target_include_directories( mpw PRIVATE "${PROJECT_SOURCE_DIR}/../lib/libjson-c/build-android~/out/include" )
target_compile_definitions( mpw PRIVATE -DMPW_JSON=1 )
target_link_libraries( mpw PRIVATE json-c )

View File

@@ -1,13 +0,0 @@
To build this module, please ensure you've done the following setup:
1. Installed the Android SDK and fully downloaded the Android SDK platform 21 in it.
2. Set the environment variable ANDROID_HOME in your shell or in ~/.mavenrc to point to the root of your Android SDK install.
3. Installed the Android SDK into your Maven's local repository.
3a. Clone the maven-android-sdk-deployer available from here: https://github.com/mosabua/maven-android-sdk-deployer.git
3b. In the root of this project, run: mvn install -P 5.0
To build this module:
1. Build the parent, by going into 'MasterPassword/Java' and running: mvn clean install
2. Build this module, by going into 'MasterPassword/Java/masterpassword-android' and running: mvn clean install
3. You can then find the APK in: 'MasterPassword/Java/masterpassword-android/target'

View File

@@ -2,45 +2,76 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.0'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
buildToolsVersion '27.0.3'
defaultConfig {
applicationId 'com.lyndir.masterpassword'
minSdkVersion 19
targetSdkVersion 25
versionCode 20401
versionName '2.4.1'
versionCode 20701
versionName '2.7.1'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
sourceSets {
main {
jniLibs.srcDirs "$rootDir/../lib/libsodium/build-android~/out/lib",
"$rootDir/../lib/libjson-c/build-android~/out/lib"
}
}
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW=$(mpw masterpassword-android) gradle assembleRelease
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW_ANDROID=$(mpw masterpassword-android) gradle masterpassword-android:assembleRelease
signingConfigs {
release {
storeFile file( 'masterpassword.keystore' )
storePassword System.getenv( 'STORE_PW' )
keyAlias 'masterpassword-android'
keyPassword System.getenv( 'KEY_PW' )
keyPassword System.getenv( 'KEY_PW_ANDROID' )
}
}
buildTypes {
release {
if (System.getenv( 'STORE_PW' ) != null)
if (System.getenv( 'KEY_PW_ANDROID' ) != null)
signingConfig signingConfigs.release
}
}
}
dependencies {
compile project( ':masterpassword-algorithm' )
compile project( ':masterpassword-tests' )
api project( ':masterpassword-algorithm' )
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p2'
compile group: 'org.slf4j', name: 'slf4j-android', version:'1.7.13-underscore'
compile group: 'com.jakewharton', name: 'butterknife', version:'8.5.1'
annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version:'8.5.1'
compile files( 'libs/scrypt-1.4.0-native.jar' )
implementation group: 'org.slf4j', name: 'slf4j-android', version: '1.7.13-underscore'
implementation group: 'com.jakewharton', name: 'butterknife', version: '8.5.1'
annotationProcessor group: 'com.jakewharton', name: 'butterknife-compiler', version: '8.5.1'
}
preBuild {
dependsOn task( type: Exec, 'build_libsodium-android', {
commandLine 'bash', "$rootDir/../lib/bin/build_libsodium-android"
environment 'ANDROID_NDK_HOME', android.ndkDirectory
} )
dependsOn task( type: Exec, 'build_libjson-c-android', {
commandLine 'bash', "$rootDir/../lib/bin/build_libjson-c-android"
environment 'ANDROID_NDK_HOME', android.ndkDirectory
} )
}
clean {
dependsOn task( type: Exec, 'clean_libsodium-android', {
commandLine 'bash', "$rootDir/../lib/bin/build_libsodium-android", 'clean'
environment 'ANDROID_NDK_HOME', android.ndkDirectory
} )
dependsOn task( type: Exec, 'clean_libjson-c-android', {
commandLine 'bash', "$rootDir/../lib/bin/build_libjson-c-android", 'clean'
environment 'ANDROID_NDK_HOME', android.ndkDirectory
} )
}

View File

@@ -1,145 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Android</name>
<description>An Android application to the Master Password algorithm</description>
<artifactId>masterpassword-android</artifactId>
<packaging>apk</packaging>
<!-- BUILD CONFIGURATION -->
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<configuration>
<zipalign>
<verbose>true</verbose>
<skip>false</skip>
</zipalign>
<sdk>
<platform>21</platform>
</sdk>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<configuration>
<sign>
<debug>false</debug>
</sign>
</configuration>
<executions>
<execution>
<id>manifest-update</id>
<phase>process-resources</phase>
<goals>
<goal>manifest-update</goal>
</goals>
<configuration>
<manifestVersionCodeUpdateFromVersion>true</manifestVersionCodeUpdateFromVersion>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>signing</id>
<goals>
<goal>sign</goal>
</goals>
<phase>package</phase>
<inherited>true</inherited>
<configuration>
<archiveDirectory />
<includes>
<include>target/*.apk</include>
</includes>
<keystore>release.jks</keystore>
<storepass>${env.PASSWORD}</storepass>
<keypass>${env.PASSWORD}</keypass>
<alias>masterpassword-android</alias>
<arguments>
<argument>-sigalg</argument><argument>MD5withRSA</argument>
<argument>-digestalg</argument><argument>SHA1</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-tests</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->
<dependency>
<groupId>com.jakewharton</groupId>
<artifactId>butterknife</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
<version>1.7.13-underscore</version>
</dependency>
<dependency>
<groupId>android</groupId>
<artifactId>android</artifactId>
<version>5.0.1_r2</version>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.4.0-android</version>
<type>jar</type>
<classifier>native</classifier>
</dependency>
</dependencies>
</project>

View File

@@ -18,7 +18,7 @@
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import android.app.*;
import android.content.*;
@@ -33,14 +33,14 @@ 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.*;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.Executors;
import javax.annotation.Nullable;
@@ -50,14 +50,17 @@ public class EmergencyActivity extends Activity {
private static final Logger logger = Logger.get( EmergencyActivity.class );
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
private static final int PASSWORD_NOTIFICATION = 0;
public static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstant.MS_PER_S;
private static final int CLIPBOARD_CLEAR_DELAY = 20 /* s */ * MPConstants.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<MPAlgorithm.Version> allVersions = ImmutableList.copyOf( MPAlgorithm.Version.values() );
private ListenableFuture<MasterKey> masterKeyFuture;
@Nullable
private MPMasterKey masterKey;
@BindView(R.id.progressView)
ProgressBar progressView;
@@ -71,8 +74,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 +100,7 @@ public class EmergencyActivity extends Activity {
private int id_userName;
private int id_masterPassword;
private int id_version;
@Nullable
private String sitePassword;
public static void start(final Context context) {
@@ -127,19 +130,19 @@ public class EmergencyActivity extends Activity {
siteNameField.addTextChangedListener( new ValueChangedListener() {
@Override
void update() {
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
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();
}
} );
@@ -152,11 +155,22 @@ public class EmergencyActivity extends Activity {
updateSitePassword();
}
} );
siteCounterButton.setOnLongClickListener( new View.OnLongClickListener() {
@Override
public boolean onLongClick(final View v) {
if (UnsignedInteger.valueOf( siteCounterButton.getText().toString() ).equals( UnsignedInteger.ONE ))
return false;
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
updateSitePassword();
return true;
}
} );
siteVersionButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(final View v) {
@SuppressWarnings("SuspiciousMethodCalls")
MasterKey.Version siteVersion =
MPAlgorithm.Version siteVersion =
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
preferences.setDefaultVersion( siteVersion );
siteVersionButton.setTag( siteVersion );
@@ -175,13 +189,13 @@ public class EmergencyActivity extends Activity {
}
} );
fullNameField.setTypeface( Res.get( this ).exo_Thin );
fullNameField.setTypeface( Res.get( this ).exo_Thin() );
fullNameField.setPaintFlags( fullNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight );
masterPasswordField.setTypeface( Res.get( this ).sourceCodePro_ExtraLight() );
masterPasswordField.setPaintFlags( masterPasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setTypeface( Res.get( this ).exo_Regular );
siteNameField.setTypeface( Res.get( this ).exo_Regular() );
siteNameField.setPaintFlags( siteNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black );
sitePasswordField.setTypeface( Res.get( this ).sourceCodePro_Black() );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@@ -213,20 +227,20 @@ 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() );
MPAlgorithm.Version defaultVersion = preferences.getDefaultVersion();
siteVersionButton.setTag( defaultVersion );
siteVersionButton.setText( defaultVersion.name() );
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
siteCounterButton.setText( MessageFormat.format( "{0}", UnsignedInteger.ONE ) );
if (TextUtils.isEmpty( fullNameField.getText() ))
fullNameField.requestFocus();
@@ -241,10 +255,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( "" );
}
@@ -258,25 +270,19 @@ 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();
String fullName = fullNameField.getText().toString();
char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
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 +291,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 MPAlgorithm.Version version = (MPAlgorithm.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 +316,8 @@ public class EmergencyActivity extends Activity {
@Override
public void run() {
try {
sitePassword = masterKeyFuture.get().encode( siteName, type, counter, MPSiteVariant.Password, null );
sitePassword = masterKey.siteResult( siteName, version.getAlgorithm(), counter,
MPKeyPurpose.Authentication, null, type, null );
runOnUiThread( new Runnable() {
@Override
@@ -342,66 +327,59 @@ public class EmergencyActivity extends Activity {
}
} );
}
catch (final InterruptedException ignored) {
catch (final MPKeyUnavailableException ignored) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
}
catch (final ExecutionException e) {
catch (final MPAlgorithmException 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 );
logger.err( e, "While generating site password." );
throw e;
}
}
} );
}
public void integrityTests(final View view) {
if (masterKeyFuture != null) {
masterKeyFuture.cancel( true );
masterKeyFuture = null;
}
TestActivity.startNoSkip( this );
}
public void copySitePassword(final View view) {
final String currentSitePassword = sitePassword;
if (TextUtils.isEmpty( currentSitePassword ))
return;
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService( CLIPBOARD_SERVICE );
final NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
if (clipboardManager == null)
return;
String title = strf( "Password for %s", siteNameField.getText() );
String title = strf( "Password for %s", siteNameField.getText() );
ClipDescription description = new ClipDescription( title, new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
clipboardManager.setPrimaryClip( new ClipData( description, new ClipData.Item( currentSitePassword ) ) );
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
.setContentText( "Paste the password into your app." )
.setSmallIcon( R.drawable.icon )
.setAutoCancel( true );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
.setCategory( Notification.CATEGORY_RECOMMENDATION )
.setLocalOnly( true );
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
if (notificationManager != null) {
Notification.Builder notificationBuilder = new Notification.Builder( this ).setContentTitle( title )
.setContentText(
"Paste the password into your app." )
.setSmallIcon( R.drawable.icon )
.setAutoCancel( true );
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
notificationBuilder.setVisibility( Notification.VISIBILITY_SECRET )
.setCategory( Notification.CATEGORY_RECOMMENDATION )
.setLocalOnly( true );
notificationManager.notify( PASSWORD_NOTIFICATION, notificationBuilder.build() );
}
final Timer timer = new Timer();
timer.schedule( new TimerTask() {
@Override
public void run() {
ClipData clip = clipboardManager.getPrimaryClip();
for (int i = 0; i < clip.getItemCount(); ++i)
if (currentSitePassword.equals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
if (currentSitePassword.contentEquals( clip.getItemAt( i ).coerceToText( EmergencyActivity.this ) )) {
clipboardManager.setPrimaryClip( EMPTY_CLIP );
break;
}
notificationManager.cancel( PASSWORD_NOTIFICATION );
if (notificationManager != null)
notificationManager.cancel( PASSWORD_NOTIFICATION );
timer.cancel();
}
}, CLIPBOARD_CLEAR_DELAY );

View File

@@ -0,0 +1,27 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2018-06-10
*/
public class MPConstants {
public static final int MS_PER_S = 1000;
}

View File

@@ -22,8 +22,10 @@ import android.os.Handler;
import android.os.Looper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.*;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
import javax.annotation.Nonnull;
/**
@@ -33,7 +35,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
private final Handler mHandler = new Handler( Looper.getMainLooper() );
private final Set<Runnable> commands = Sets.newLinkedHashSet();
private boolean shutdown;
private boolean shutdown;
@Override
public void execute(final Runnable command) {
@@ -63,6 +65,7 @@ public class MainThreadExecutor extends AbstractExecutorService {
shutdown = true;
}
@Nonnull
@Override
public List<Runnable> shutdownNow() {
shutdown = true;

View File

@@ -32,15 +32,15 @@ import javax.annotation.Nullable;
*/
public final class Preferences {
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
private static final String PREF_NATIVE_KDF = "nativeKDF";
private static final String PREF_REMEMBER_FULL_NAME = "rememberFullName";
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_ALGORITHM_VERSION = "algorithmVersion";
private static Preferences instance;
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
private static final String PREF_NATIVE_KDF = "nativeKDF";
private static final String PREF_REMEMBER_FULL_NAME = "rememberFullName";
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_RESULT_TYPE = "resultType";
private static final String PREF_ALGORITHM_VERSION = "algorithmVersion";
private static Preferences instance;
private Context context;
@Nullable
@@ -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) {
@@ -86,7 +86,7 @@ public final class Preferences {
}
public Set<String> getTestsPassed() {
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() );
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.of() );
}
public boolean setRememberFullName(final boolean enabled) {
@@ -138,20 +138,21 @@ 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, getDefaultVersion().getAlgorithm().mpw_default_result_type().ordinal() )];
}
public boolean setDefaultVersion(@Nonnull final MasterKey.Version value) {
public boolean setDefaultVersion(final MPAlgorithm.Version value) {
if (getDefaultVersion() == value)
return false;
@@ -160,7 +161,8 @@ public final class Preferences {
}
@Nonnull
public MasterKey.Version getDefaultVersion() {
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )];
public MPAlgorithm.Version getDefaultVersion() {
return MPAlgorithm.Version.values()[
prefs().getInt( PREF_ALGORITHM_VERSION, MPAlgorithm.Version.CURRENT.ordinal() )];
}
}

View File

@@ -19,21 +19,21 @@
package com.lyndir.masterpassword;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
/**
* @author lhunath, 2014-08-25
*/
@SuppressWarnings("NewMethodNamingConvention")
public final class Res {
public final Typeface sourceCodePro_Black;
public final Typeface sourceCodePro_ExtraLight;
public final Typeface exo_Bold;
public final Typeface exo_ExtraBold;
public final Typeface exo_Regular;
public final Typeface exo_Thin;
private final Typeface sourceCodePro_Black;
private final Typeface sourceCodePro_ExtraLight;
private final Typeface exo_Bold;
private final Typeface exo_ExtraBold;
private final Typeface exo_Regular;
private final Typeface exo_Thin;
private static Res res;
@@ -54,4 +54,28 @@ public final class Res {
exo_Regular = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Regular.otf" );
exo_Thin = Typeface.createFromAsset( context.getResources().getAssets(), "Exo2.0-Thin.otf" );
}
public Typeface sourceCodePro_Black() {
return sourceCodePro_Black;
}
public Typeface sourceCodePro_ExtraLight() {
return sourceCodePro_ExtraLight;
}
public Typeface exo_Bold() {
return exo_Bold;
}
public Typeface exo_ExtraBold() {
return exo_ExtraBold;
}
public Typeface exo_Regular() {
return exo_Regular;
}
public Typeface exo_Thin() {
return exo_Thin;
}
}

View File

@@ -1,194 +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 android.app.*;
import android.content.Context;
import android.content.Intent;
import android.os.*;
import android.view.View;
import android.widget.*;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.concurrent.*;
import javax.annotation.Nullable;
public class TestActivity extends Activity implements MPTestSuite.Listener {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( TestActivity.class );
private final Preferences preferences = Preferences.get( this );
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
@BindView(R.id.progressView)
ProgressBar progressView;
@BindView(R.id.statusView)
TextView statusView;
@BindView(R.id.logView)
TextView logView;
@BindView(R.id.actionButton)
Button actionButton;
@BindView(R.id.nativeKDFField)
CheckBox nativeKDFField;
private MPTestSuite testSuite;
private ListenableFuture<Boolean> testFuture;
private Runnable action;
private ImmutableSet<String> testNames;
public static void startNoSkip(final Context context) {
context.startActivity( new Intent( context, TestActivity.class ) );
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_test );
ButterKnife.bind( this );
nativeKDFField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
preferences.setNativeKDFEnabled( isChecked );
MasterKey.setAllowNativeByDefault( isChecked );
}
} );
try {
setStatus( 0, 0, null );
testSuite = new MPTestSuite();
testSuite.setListener( this );
testNames = FluentIterable.from( testSuite.getTests().getCases() ).transform(
new Function<MPTests.Case, String>() {
@Nullable
@Override
public String apply(@Nullable final MPTests.Case input) {
return (input == null)? null: input.identifier;
}
} ).filter( Predicates.notNull() ).toSet();
}
catch (final MPTestSuite.UnavailableException e) {
logger.err( e, "While loading test suite" );
setStatus( R.string.tests_unavailable, R.string.tests_btn_unavailable, new Runnable() {
@Override
public void run() {
finish();
}
} );
}
}
@Override
protected void onResume() {
super.onResume();
nativeKDFField.setChecked( preferences.isAllowNativeKDF() );
if (testFuture == null)
startTestSuite();
}
private void startTestSuite() {
if (testFuture != null)
testFuture.cancel( true );
MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
@Override
public void onSuccess(@Nullable final Boolean result) {
if ((result != null) && result)
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
@Override
public void run() {
preferences.setTestsPassed( testNames );
finish();
}
} );
else
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
@Override
public void run() {
startTestSuite();
}
} );
}
@Override
public void onFailure(final Throwable t) {
logger.err( t, "While running test suite" );
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
@Override
public void run() {
finish();
}
} );
}
}, mainExecutor );
}
public void onAction(final View v) {
if (action != null)
action.run();
}
private void setStatus(final int statusId, final int buttonId, @Nullable final Runnable action) {
this.action = action;
if (statusId == 0)
statusView.setText( null );
else
statusView.setText( statusId );
if (buttonId == 0)
actionButton.setText( null );
else
actionButton.setText( buttonId );
actionButton.setEnabled( action != null );
}
@Override
public void progress(final int current, final int max, final String messageFormat, final Object... args) {
runOnUiThread( new Runnable() {
@Override
public void run() {
logView.append( strf( "%n" + messageFormat, args ) );
progressView.setMax( max );
progressView.setProgress( current );
}
} );
}
}

View File

@@ -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>
@@ -253,15 +253,6 @@
</LinearLayout>
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textSize="16sp"
android:text="@string/btn_tests"
android:onClick="integrityTests"
android:background="@android:color/transparent" />
<View
android:layout_width="1dp"
android:layout_height="0dp"

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:orientation="vertical"
android:gravity="center">
<View
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/img_stats" />
<ProgressBar
android:id="@+id/progressView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
tools:max="100"
tools:progress="80"
style="?android:progressBarStyleHorizontal" />
<TextView
android:id="@+id/statusView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/sitePasswordField"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/tests_testing" />
<TextView
android:id="@+id/logView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:gravity="bottom"
android:background="@android:color/transparent"
android:textIsSelectable="true"
android:textSize="9sp"
android:textColor="@android:color/tertiary_text_dark" />
<Button
android:id="@+id/actionButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:enabled="false"
android:text="@string/tests_btn_testing"
android:onClick="onAction" />
<CheckBox
android:id="@+id/nativeKDFField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/nativeKDF" />
</LinearLayout>
</ScrollView>

View File

@@ -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" />

View File

@@ -0,0 +1,184 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXFileReference section */
DA1554DE20B3928E00EA92C5 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm.h"; sourceTree = "<group>"; };
DA1554E020B3928E00EA92C5 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = "<group>"; };
DA1554E120B3928E00EA92C5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = "<group>"; };
DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v2.c"; sourceTree = "<group>"; };
DA1554E320B3928E00EA92C5 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = "<group>"; };
DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = "<group>"; };
DA1554E520B3928E00EA92C5 /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = "<group>"; };
DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = "<group>"; };
DA1554E720B3928E00EA92C5 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
DA1554E820B3928E00EA92C5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = "<group>"; };
DA1554E920B3928E00EA92C5 /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm.c"; sourceTree = "<group>"; };
DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = "<group>"; };
DA1554EC20B3928E00EA92C5 /* mpw-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-types.h"; sourceTree = "<group>"; };
DA1554ED20B3928E00EA92C5 /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = "<group>"; };
DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = "<group>"; };
DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v3.c"; sourceTree = "<group>"; };
DA1F44B020BCF0C200957B45 /* mpw-jni.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-jni.h"; sourceTree = "<group>"; };
DA1F44B120BCF0C200957B45 /* mpw-jni.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-jni.c"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
DA1554D220B3924000EA92C5 = {
isa = PBXGroup;
children = (
DA1554DD20B3928E00EA92C5 /* core */,
);
sourceTree = "<group>";
};
DA1554DD20B3928E00EA92C5 /* core */ = {
isa = PBXGroup;
children = (
DA1554DE20B3928E00EA92C5 /* aes.c */,
DA1554E720B3928E00EA92C5 /* aes.h */,
DA1554E920B3928E00EA92C5 /* base64.c */,
DA1554E020B3928E00EA92C5 /* base64.h */,
DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */,
DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */,
DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */,
DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */,
DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */,
DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */,
DA1F44B120BCF0C200957B45 /* mpw-jni.c */,
DA1F44B020BCF0C200957B45 /* mpw-jni.h */,
DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */,
DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */,
DA1554E120B3928E00EA92C5 /* mpw-marshal.c */,
DA1554E820B3928E00EA92C5 /* mpw-marshal.h */,
DA1554E320B3928E00EA92C5 /* mpw-types.c */,
DA1554EC20B3928E00EA92C5 /* mpw-types.h */,
DA1554E520B3928E00EA92C5 /* mpw-util.c */,
DA1554ED20B3928E00EA92C5 /* mpw-util.h */,
);
name = core;
path = "../platform-independent/c/core/src";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXLegacyTarget section */
DA1554D720B3924000EA92C5 /* MasterPassword-JNI */ = {
isa = PBXLegacyTarget;
buildArgumentsString = ":masterpassword-algorithm:nativeGenHeaders";
buildConfigurationList = DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */;
buildPhases = (
);
buildToolPath = gradle;
buildWorkingDirectory = /Users/lhunath/Documents/workspace/lyndir/MasterPassword/gradle;
dependencies = (
);
name = "MasterPassword-JNI";
passBuildSettingsInEnvironment = 1;
productName = "MasterPassword-JNI";
};
/* End PBXLegacyTarget section */
/* Begin PBXProject section */
DA1554D320B3924000EA92C5 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Maarten Billemont";
TargetAttributes = {
DA1554D720B3924000EA92C5 = {
CreatedOnToolsVersion = 9.3.1;
};
};
};
buildConfigurationList = DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = DA1554D220B3924000EA92C5;
projectDirPath = "";
projectRoot = "";
targets = (
DA1554D720B3924000EA92C5 /* MasterPassword-JNI */,
);
};
/* End PBXProject section */
/* Begin XCBuildConfiguration section */
DA1554D820B3924000EA92C5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
DA1554D920B3924000EA92C5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Release;
};
DA1554DB20B3924000EA92C5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/include\"",
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
);
JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home;
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
};
name = Debug;
};
DA1554DC20B3924000EA92C5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(PROJECT_DIR)/../lib/libsodium/build-ios~/out/include\"",
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
);
JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home;
OTHER_CFLAGS = (
"-DMPW_SODIUM=1",
"-DMPW_CPERCIVA=0",
);
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA1554D820B3924000EA92C5 /* Debug */,
DA1554D920B3924000EA92C5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DA1554DB20B3924000EA92C5 /* Debug */,
DA1554DC20B3924000EA92C5 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = DA1554D320B3924000EA92C5 /* Project object */;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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"

File diff suppressed because it is too large Load Diff

View File

@@ -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"

View File

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

View File

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

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