2
0

Compare commits

..

98 Commits

Author SHA1 Message Date
Maarten Billemont
67e18895ab Update Android APK to fix scrypt issue. 2017-02-09 23:33:04 -05:00
Maarten Billemont
8b7cf2e86d Instructions, so I don't forget. 2017-02-09 23:31:22 -05:00
Maarten Billemont
a267c0d1db APK release configuration. 2017-02-09 23:25:42 -05:00
Maarten Billemont
f60093513e Change to new masterpassword.keystore 2017-02-09 22:59:22 -05:00
Maarten Billemont
5b47d47a1b Android 2.4.1 2017-02-09 22:54:20 -05:00
Maarten Billemont
f8f48743b0 Fix native scrypt on Android. 2017-02-09 00:48:07 -05:00
Maarten Billemont
b46bf25c19 Migrate to Gradle. 2017-02-06 11:16:04 -05:00
Maarten Billemont
e754e1ddce Evaluate the speed of the first and second stage of mpw individually. 2017-01-05 10:58:02 -05:00
Maarten Billemont
0f4a66f5d3 Fix setupterm error evaluation. 2016-11-10 11:15:23 -05:00
Maarten Billemont
3036697004 Don't exit if TERM is not set and color is enabled; setupterm is strange.. 2016-11-06 11:19:52 -05:00
Maarten Billemont
097d240feb Fix leak and segfault wrt reading MP_FULLNAME 2016-11-06 11:17:02 -05:00
Maarten Billemont
dd9e4eafbc lineSize needs to be > 1. 2016-11-06 10:42:23 -05:00
Maarten Billemont
2199757d9b Build and Travis fix. 2016-11-03 20:13:43 -04:00
Maarten Billemont
00887f6277 Travis. 2016-11-03 19:45:37 -04:00
Maarten Billemont
21945ae23f Try to fix Travis builds again. 2016-11-03 16:46:58 -04:00
Maarten Billemont
d3f2a01da2 Fix memory leaks, thanks @daltomi - #134. 2016-11-03 10:31:07 -04:00
Maarten Billemont
f427e06692 Change the names of some utility functions to be more standard and consistent. 2016-11-03 10:04:18 -04:00
Maarten Billemont
73421b3299 Merge branch 'master' of github.com:Lyndir/MasterPassword 2016-10-29 09:29:13 -04:00
Maarten Billemont
564e5d9084 Standardize mpw-wide constants and explain their purpose, also allow non-home .mpw.d. 2016-10-29 09:29:01 -04:00
Maarten Billemont
88d818833c Merge pull request #110 from joshterrill/master
fixed wording on set password dialog
2016-10-29 08:24:21 -04:00
Maarten Billemont
0498a245c6 Some minor code improvements. 2016-10-29 08:18:20 -04:00
Maarten Billemont
77bb2ef4cd Merge pull request #118 from joelsnape/master
Corrected conversion exception (from long to UnsignedInteger) on linux oracle and open jdk.
2016-10-29 07:55:36 -04:00
Maarten Billemont
207b375ae9 Fix version number parsing. 2016-10-27 14:49:02 -04:00
Maarten Billemont
c1f4d2db24 Merge branch 'master' of github.com:Lyndir/MasterPassword 2016-10-27 14:24:49 -04:00
Maarten Billemont
ca3a8ee78c Update Master Password Web version to support all algorithm versions and Tom's latest mpw-js. 2016-10-27 14:14:58 -04:00
Maarten Billemont
e88ec0927e Merge pull request #108 from rolandog/patch-1
Prevented domain name and password leakage
2016-10-27 14:13:20 -04:00
Maarten Billemont
e6774592d7 Merge pull request #121 from nat13ejo/master
Modified the symlink in mpw_test.xml to point to the new location of mpw_test.xml
2016-10-27 14:12:20 -04:00
Emil Johansson
6834f3689f Modified the symlink in mpw_test.xml to point to the new location of
the file at ../Java/masterpassword-tests/src/main/resources/mpw_tests.xml

Fixes #120
2016-10-22 10:26:29 +02:00
Maarten Billemont
c2fc5e6072 Merge pull request #119 from nat13ejo/master
Added the option "-selection clip" to the xclip command. This fixes
2016-10-21 16:04:51 -04:00
Emil Johansson
ade5c274b1 Added the option "-selection clip" to the xclip command. This fixes
the bugg that the automatic copying to the clipboard accesible with
ctrl-V in applications like in e.g firefox is not working in OpenSUSE
41.1 and i suspect in other Linux distros as well.
2016-10-20 22:33:11 +02:00
Joel Snape
1da235bbdf Corrected conversion exception (from long to UnsignedInteger) on linux oracle and open jdk. 2016-10-08 20:51:19 +01:00
Maarten Billemont
b050cc4994 Build fixes. 2016-09-22 18:17:19 -04:00
Maarten Billemont
3e31dac7e0 Update project for Xcode 8, finally with named provisioning profile identifiers! 2016-09-22 17:37:21 -04:00
Maarten Billemont
eea9051dbb Adjust mpw-bench to compare to hmac-sha-256 instead of sha-256, their performance characteristics are quite different. 2016-08-24 00:07:58 -04:00
Maarten Billemont
d560a2052d Mac update. 2016-08-17 18:36:39 -04:00
Maarten Billemont
af7edd05d4 Make TouchID optional. 2016-08-17 18:34:32 -04:00
Joshua Terrill
33f817a585 fixed wording on set password dialog
The wordong says "Click 'Change Password' ...", but the button says "Set Password", not "Change Password".
2016-08-02 00:11:37 -07:00
Maarten Billemont
e2d3f14fdf Fix a crash when the master key could not be computed. 2016-07-23 11:44:17 -04:00
Maarten Billemont
e205926c8c Bump Crashlytics. 2016-07-21 20:07:20 -04:00
Maarten Billemont
d48494a566 Update Master Password for Mac. 2016-07-21 20:06:37 -04:00
Maarten Billemont
00ad9d59ca Better fix to Mac user getting logged out after the app is locked. 2016-07-21 20:03:47 -04:00
Maarten Billemont
af7327555c Merge branch 'master' of github.com:Lyndir/MasterPassword 2016-07-21 10:02:35 -04:00
Maarten Billemont
1977a423a5 Move a few batches of UI work into the main thread. 2016-07-21 09:59:37 -04:00
Maarten Billemont
fa588f8fe2 Update Crashlytics. 2016-07-19 12:06:22 -04:00
Maarten Billemont
ba00d89b99 Fix some potential crashes and memory leaks. 2016-07-19 12:00:19 -04:00
Maarten Billemont
c498d8b1ec Merge pull request #109 from dkunzler/master
fix mpsites export on Java
2016-07-06 15:22:14 -04:00
David Kunzler
e6b398d09d fix mpsites export on Java 2016-07-06 20:23:45 +02:00
Maarten Billemont
a72d893203 Include the build in the short version string. 2016-07-06 01:24:58 -04:00
Maarten Billemont
a5368033a3 Default to Long on invalid type. 2016-07-06 01:18:35 -04:00
Maarten Billemont
588ebe08cd Fix crash when default type is not a generated type, when password is unset and don't crash for fatals. 2016-07-06 01:16:10 -04:00
Maarten Billemont
28bd162e05 Fixed issue when signing out on iOS + issue with biometrics not getting enabled properly after enabling TouchID. 2016-07-05 20:15:18 -04:00
Maarten Billemont
2897bc741c Version can't be > 18 chars, so use the major as the repeater. 2016-07-02 09:46:42 -04:00
Maarten Billemont
e11e73c0db Little hack to work around stupid iTunesConnect restriction. 2016-07-02 09:29:50 -04:00
Maarten Billemont
672d8ba089 Update Master Password for Mac. 2016-07-02 09:18:55 -04:00
Maarten Billemont
3a70d5e38d Don't forget the active user when signing out, so sign-in can re-use the same user.
Also fix some deprecated method usages.
2016-07-02 09:04:31 -04:00
Maarten Billemont
b9298996e8 Make Reveal weak. 2016-06-04 12:01:20 -04:00
Maarten Billemont
28afa1a56d Bump Pearl. 2016-06-04 11:52:17 -04:00
Maarten Billemont
17cc647cf5 Turn off tests. 2016-06-04 11:38:37 -04:00
Maarten Billemont
9863fbb073 Bump Crashlytics. 2016-06-04 11:29:21 -04:00
Maarten Billemont
49398bb9f0 Another attempt at fixing dumb xctool bugs. 2016-06-04 11:27:37 -04:00
Maarten Billemont
b52b310e82 Fix saving of user after sign-in. 2016-06-04 10:44:43 -04:00
Maarten Billemont
6a74ada2fa Dismiss keyboard if active when opening question answers. 2016-06-04 10:14:19 -04:00
Maarten Billemont
c8a40a7062 Build fix for iOS. 2016-06-04 09:52:19 -04:00
Maarten Billemont
2889c73af3 Let's call it 'Desktop' now. 2016-05-16 08:46:55 -04:00
Maarten Billemont
9249967c6f Bump master password mac and distribute via the website instead of through the app store. 2016-05-16 08:44:06 -04:00
Maarten Billemont
24f5ceac51 Fix misplaced frames. 2016-05-16 08:36:14 -04:00
Maarten Billemont
060059ff0c Bugfixes, a gradient backdrop behind bottom buttons and support for generated login names. 2016-05-16 00:50:17 -04:00
Maarten Billemont
0f7793e9ba Fix "full screen" menu item not updating when toggled. 2016-05-15 00:14:41 -04:00
Maarten Billemont
a4cf7f9f3c Mac 2.4 beta. 2016-05-02 11:42:34 -04:00
Maarten Billemont
8978433aed fadeIn/fadeOut cleanup. 2016-04-30 18:09:27 -04:00
Maarten Billemont
b4efe301a4 Fix issues with focus and tips in security questions panel. 2016-04-30 18:06:23 -04:00
Maarten Billemont
9a82e617b3 Fix copy/paste/undo/redo editing hotkeys. 2016-04-30 17:41:51 -04:00
Maarten Billemont
2647279ff6 Only reset the frame size and position if switching window level. 2016-04-30 15:48:10 -04:00
Maarten Billemont
dae84c4a2e Manually fix hardcoded absolute paths, silly Xcode. 2016-04-25 11:13:24 -04:00
Maarten Billemont
3b74543c51 Security answer generation for question keywords. 2016-04-23 23:56:16 -04:00
Maarten Billemont
1918c30bed Wire up some of the security answers UI. Still WIP. 2016-04-23 14:07:08 -04:00
Maarten Billemont
bbeb6bb948 Fix deprecated NSAlert usage. 2016-04-23 12:22:15 -04:00
Maarten Billemont
15b14d67db Improvements to layout, password types and preparations for security answers. 2016-04-23 11:54:13 -04:00
Maarten Billemont
35c443d82d Support for windowed Master Password window on OS X, some UI improvements and modern version of window translucency. 2016-04-17 19:30:06 -04:00
Maarten Billemont
d950d4be3b Improvements to the question UI. 2016-04-17 16:29:37 -04:00
Maarten Billemont
d7aae64b5d Fix appearance of UI on Mac. 2016-04-16 17:22:11 -04:00
rolandog
657e4c8a9d Prevented domain name and password leakage
This prevents a user from logging in with any password into a tab that was left open and being able to view the last domain name and generated password.
2016-04-01 23:01:55 +00:00
Maarten Billemont
f238bb723d WIP - upgrade to tmthrgd latest code. 2016-03-05 16:57:58 -05:00
Maarten Billemont
b4da801bb0 Skip existing files when uploading to s3. 2016-02-21 11:51:32 -05:00
Maarten Billemont
ce7aa46af6 Bump masterpassword-android to 2.4. 2016-02-21 09:08:02 -05:00
Maarten Billemont
83c28692ad [maven-release-plugin] rollback changes from release preparation of 2.4-java 2016-02-20 22:29:27 -05:00
Maarten Billemont
f21d0f7cfc [maven-release-plugin] prepare release 2.4-java 2016-02-20 22:29:27 -05:00
Maarten Billemont
7eb10cb5a6 Fix a bug with storing the default algorithm version. 2016-02-20 22:26:50 -05:00
Maarten Billemont
64829c99d8 Initial support for security questions in Mac app. 2016-02-20 21:56:04 -05:00
Maarten Billemont
0269c2741a Silence warning when releasing about jarsigner version ambiguity. 2016-02-20 21:53:58 -05:00
Maarten Billemont
f5638ea798 A little clean-up. 2016-02-20 21:48:18 -05:00
Maarten Billemont
6a1768a50d Fixed a few bugs. 2016-02-20 21:45:11 -05:00
Maarten Billemont
b346b3be65 Finish up Android UI improvements. 2016-02-20 21:27:59 -05:00
Maarten Billemont
060ec0b5cd Move preferences into a global preferences controller. 2016-02-20 20:30:08 -05:00
Maarten Billemont
7f8a36e32e Added ability to switch from native to java-only KDF. 2016-02-20 18:50:44 -05:00
Maarten Billemont
024899f311 Updated and fixed encoding of a few PNGs. 2016-02-20 18:49:21 -05:00
Maarten Billemont
6ffef78469 Fix some C warnings. 2016-02-19 08:34:06 -05:00
Maarten Billemont
b574158d92 Update logback layout to new format. 2016-02-19 08:25:14 -05:00
219 changed files with 3395 additions and 1964 deletions

4
.gitmodules vendored
View File

@@ -16,6 +16,6 @@
[submodule "External/jrswizzle"] [submodule "External/jrswizzle"]
path = External/jrswizzle path = External/jrswizzle
url = git://github.com/jonmarimba/jrswizzle.git url = git://github.com/jonmarimba/jrswizzle.git
[submodule "Site/mpw-js/js/mpw-js"] [submodule "MasterPassword/Web/js/mpw-js"]
path = Site/mpw-js/js/mpw-js path = MasterPassword/Web/js/mpw-js
url = https://github.com/tmthrgd/mpw-js.git url = https://github.com/tmthrgd/mpw-js.git

View File

@@ -5,7 +5,6 @@
<inspection_tool class="Convert to string" enabled="true" level="WEAK WARNING" enabled_by_default="true" /> <inspection_tool class="Convert to string" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />

View File

@@ -1,8 +1,6 @@
language: objective-c language: objective-c
osx_image: xcode7 osx_image: xcode8
xcode_scheme: MasterPassword iOS (App Store) env: TERM=dumb SHLVL=0
xcode_workspace: MasterPassword.xcworkspace
xcode_sdk: iphonesimulator
env: TERM=dumb
git: git:
submodules: true submodules: true
script: xcodebuild -workspace MasterPassword.xcworkspace -scheme 'MasterPassword iOS (App Store)' -configuration 'AdHoc-iOS' -sdk iphonesimulator

View File

@@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)stackFrameWithSymbol:(NSString *)symbol; + (instancetype)stackFrameWithSymbol:(NSString *)symbol;
@property (nonatomic, copy, nullable) NSString *symbol; @property (nonatomic, copy, nullable) NSString *symbol;
@property (nonatomic, copy, nullable) NSString *rawSymbol;
@property (nonatomic, copy, nullable) NSString *library; @property (nonatomic, copy, nullable) NSString *library;
@property (nonatomic, copy, nullable) NSString *fileName; @property (nonatomic, copy, nullable) NSString *fileName;
@property (nonatomic, assign) uint32_t lineNumber; @property (nonatomic, assign) uint32_t lineNumber;

View File

@@ -18,7 +18,10 @@ NS_ASSUME_NONNULL_BEGIN
@protocol CrashlyticsDelegate; @protocol CrashlyticsDelegate;
/** /**
* Crashlytics. Handles configuration and initialization of Crashlytics. * Crashlytics. Handles configuration and initialization of Crashlytics.
*
* Note: The Crashlytics class cannot be subclassed. If this is causing you pain for
* testing, we suggest using either a wrapper class or a protocol extension.
*/ */
@interface Crashlytics : NSObject @interface Crashlytics : NSObject

View File

@@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>BuildMachineOSBuild</key> <key>BuildMachineOSBuild</key>
<string>14F1021</string> <string>15F34</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>English</string> <string>English</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.6.0</string> <string>3.7.2</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
@@ -25,27 +25,29 @@
<string>MacOSX</string> <string>MacOSX</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>99</string> <string>112</string>
<key>DTCompiler</key> <key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string> <string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key> <key>DTPlatformBuild</key>
<string>7B91b</string> <string>7D175</string>
<key>DTPlatformVersion</key> <key>DTPlatformVersion</key>
<string>GM</string> <string>GM</string>
<key>DTSDKBuild</key> <key>DTSDKBuild</key>
<string>15A278</string> <string>15E60</string>
<key>DTSDKName</key> <key>DTSDKName</key>
<string>macosx10.11</string> <string>macosx10.11</string>
<key>DTXcode</key> <key>DTXcode</key>
<string>0710</string> <string>0730</string>
<key>DTXcodeBuild</key> <key>DTXcodeBuild</key>
<string>7B91b</string> <string>7D175</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Crashlytics, Inc. All rights reserved.</string> <string>Copyright © 2016 Crashlytics, Inc. All rights reserved.</string>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<integer>1</integer> <integer>3</integer>
<integer>2</integer> <integer>2</integer>
<integer>1</integer>
<integer>4</integer>
</array> </array>
</dict> </dict>
</plist> </plist>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.6.4</string> <string>1.6.7</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
@@ -25,27 +25,29 @@
<string>MacOSX</string> <string>MacOSX</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>45</string> <string>53</string>
<key>DTCompiler</key> <key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string> <string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key> <key>DTPlatformBuild</key>
<string>7B91b</string> <string>7C1002</string>
<key>DTPlatformVersion</key> <key>DTPlatformVersion</key>
<string>GM</string> <string>GM</string>
<key>DTSDKBuild</key> <key>DTSDKBuild</key>
<string>15A278</string> <string>15C43</string>
<key>DTSDKName</key> <key>DTSDKName</key>
<string>macosx10.11</string> <string>macosx10.11</string>
<key>DTXcode</key> <key>DTXcode</key>
<string>0710</string> <string>0721</string>
<key>DTXcodeBuild</key> <key>DTXcodeBuild</key>
<string>7B91b</string> <string>7C1002</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Twitter. All rights reserved.</string> <string>Copyright © 2015 Twitter. All rights reserved.</string>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<integer>1</integer> <integer>3</integer>
<integer>2</integer> <integer>2</integer>
<integer>1</integer>
<integer>4</integer>
</array> </array>
</dict> </dict>
</plist> </plist>

Binary file not shown.

2
External/Pearl vendored

Binary file not shown.

View File

@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
* *
* @param signUpMethodOrNil The method by which a user logged in, e.g. Twitter or Digits. * @param signUpMethodOrNil The method by which a user logged in, e.g. Twitter or Digits.
* @param signUpSucceededOrNil The ultimate success or failure of the login * @param signUpSucceededOrNil The ultimate success or failure of the login
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logSignUpWithMethod:(nullable NSString *)signUpMethodOrNil + (void)logSignUpWithMethod:(nullable NSString *)signUpMethodOrNil
success:(nullable NSNumber *)signUpSucceededOrNil success:(nullable NSNumber *)signUpSucceededOrNil
@@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
* *
* @param loginMethodOrNil The method by which a user logged in, e.g. email, Twitter or Digits. * @param loginMethodOrNil The method by which a user logged in, e.g. email, Twitter or Digits.
* @param loginSucceededOrNil The ultimate success or failure of the login * @param loginSucceededOrNil The ultimate success or failure of the login
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logLoginWithMethod:(nullable NSString *)loginMethodOrNil + (void)logLoginWithMethod:(nullable NSString *)loginMethodOrNil
success:(nullable NSNumber *)loginSucceededOrNil success:(nullable NSNumber *)loginSucceededOrNil
@@ -61,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN
* your application. * your application.
* *
* @param inviteMethodOrNil The method of invitation, e.g. GameCenter, Twitter, email. * @param inviteMethodOrNil The method of invitation, e.g. GameCenter, Twitter, email.
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logInviteWithMethod:(nullable NSString *)inviteMethodOrNil + (void)logInviteWithMethod:(nullable NSString *)inviteMethodOrNil
customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil; customAttributes:(nullable ANS_GENERIC_NSDICTIONARY(NSString *, id) *)customAttributesOrNil;
@@ -74,8 +74,8 @@ NS_ASSUME_NONNULL_BEGIN
* @param currencyOrNil The ISO4217 currency code. Example: USD * @param currencyOrNil The ISO4217 currency code. Example: USD
* @param purchaseSucceededOrNil Was the purchase succesful or unsuccesful * @param purchaseSucceededOrNil Was the purchase succesful or unsuccesful
* @param itemNameOrNil The human-readable form of the item's name. Example: * @param itemNameOrNil The human-readable form of the item's name. Example:
* @param itemIdOrNil The machine-readable, unique item identifier Example: SKU
* @param itemTypeOrNil The type, or genre of the item. Example: Song * @param itemTypeOrNil The type, or genre of the item. Example: Song
* @param itemIdOrNil The machine-readable, unique item identifier Example: SKU
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase.
*/ */
+ (void)logPurchaseWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil + (void)logPurchaseWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
@@ -101,7 +101,7 @@ NS_ASSUME_NONNULL_BEGIN
* @param levelNameOrNil The name of the level completed, E.G. "1" or "Training" * @param levelNameOrNil The name of the level completed, E.G. "1" or "Training"
* @param scoreOrNil The score the user completed the level with. * @param scoreOrNil The score the user completed the level with.
* @param levelCompletedSuccesfullyOrNil A boolean representing whether or not the level was completed succesfully. * @param levelCompletedSuccesfullyOrNil A boolean representing whether or not the level was completed succesfully.
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logLevelEnd:(nullable NSString *)levelNameOrNil + (void)logLevelEnd:(nullable NSString *)levelNameOrNil
score:(nullable NSNumber *)scoreOrNil score:(nullable NSNumber *)scoreOrNil
@@ -118,7 +118,7 @@ NS_ASSUME_NONNULL_BEGIN
* @param itemNameOrNil The human-readable form of the item's name. Example: * @param itemNameOrNil The human-readable form of the item's name. Example:
* @param itemTypeOrNil The type, or genre of the item. Example: Song * @param itemTypeOrNil The type, or genre of the item. Example: Song
* @param itemIdOrNil The machine-readable, unique item identifier Example: SKU * @param itemIdOrNil The machine-readable, unique item identifier Example: SKU
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logAddToCartWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil + (void)logAddToCartWithPrice:(nullable NSDecimalNumber *)itemPriceOrNil
currency:(nullable NSString *)currencyOrNil currency:(nullable NSString *)currencyOrNil
@@ -135,7 +135,7 @@ NS_ASSUME_NONNULL_BEGIN
* @param totalPriceOrNil The total price of the cart. * @param totalPriceOrNil The total price of the cart.
* @param currencyOrNil The ISO4217 currency code. Example: USD * @param currencyOrNil The ISO4217 currency code. Example: USD
* @param itemCountOrNil The number of items in the cart. * @param itemCountOrNil The number of items in the cart.
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. * @param customAttributesOrNil A dictionary of custom attributes to associate with this event.
*/ */
+ (void)logStartCheckoutWithPrice:(nullable NSDecimalNumber *)totalPriceOrNil + (void)logStartCheckoutWithPrice:(nullable NSDecimalNumber *)totalPriceOrNil
currency:(nullable NSString *)currencyOrNil currency:(nullable NSString *)currencyOrNil
@@ -188,7 +188,7 @@ NS_ASSUME_NONNULL_BEGIN
* the name of the event, since this is how the event will appear in Answers. * the name of the event, since this is how the event will appear in Answers.
* *
* @param eventName The human-readable name for the event. * @param eventName The human-readable name for the event.
* @param customAttributesOrNil A dictionary of custom attributes to associate with this purchase. Attribute keys * @param customAttributesOrNil A dictionary of custom attributes to associate with this event. Attribute keys
* must be <code>NSString</code> and and values must be <code>NSNumber</code> or <code>NSString</code>. * must be <code>NSString</code> and and values must be <code>NSNumber</code> or <code>NSString</code>.
* @discussion How we treat <code>NSNumbers</code>: * @discussion How we treat <code>NSNumbers</code>:
* We will provide information about the distribution of values over time. * We will provide information about the distribution of values over time.

View File

@@ -26,6 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)stackFrameWithSymbol:(NSString *)symbol; + (instancetype)stackFrameWithSymbol:(NSString *)symbol;
@property (nonatomic, copy, nullable) NSString *symbol; @property (nonatomic, copy, nullable) NSString *symbol;
@property (nonatomic, copy, nullable) NSString *rawSymbol;
@property (nonatomic, copy, nullable) NSString *library; @property (nonatomic, copy, nullable) NSString *library;
@property (nonatomic, copy, nullable) NSString *fileName; @property (nonatomic, copy, nullable) NSString *fileName;
@property (nonatomic, assign) uint32_t lineNumber; @property (nonatomic, assign) uint32_t lineNumber;

View File

@@ -18,7 +18,10 @@ NS_ASSUME_NONNULL_BEGIN
@protocol CrashlyticsDelegate; @protocol CrashlyticsDelegate;
/** /**
* Crashlytics. Handles configuration and initialization of Crashlytics. * Crashlytics. Handles configuration and initialization of Crashlytics.
*
* Note: The Crashlytics class cannot be subclassed. If this is causing you pain for
* testing, we suggest using either a wrapper class or a protocol extension.
*/ */
@interface Crashlytics : NSObject @interface Crashlytics : NSObject
@@ -181,6 +184,21 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (void)recordCustomExceptionName:(NSString *)name reason:(nullable NSString *)reason frameArray:(CLS_GENERIC_NSARRAY(CLSStackFrame *) *)frameArray; - (void)recordCustomExceptionName:(NSString *)name reason:(nullable NSString *)reason frameArray:(CLS_GENERIC_NSARRAY(CLSStackFrame *) *)frameArray;
/**
*
* This allows you to record a non-fatal event, described by an NSError object. These events will be grouped and
* displayed similarly to crashes. Keep in mind that this method can be expensive. Also, the total number of
* NSErrors that can be recorded during your app's life-cycle is limited by a fixed-size circular buffer. If the
* buffer is overrun, the oldest data is dropped. Errors are relayed to Crashlytics on a subsequent launch
* of your application.
*
* You can also use the -recordError:withAdditionalUserInfo: to include additional context not represented
* by the NSError instance itself.
*
**/
- (void)recordError:(NSError *)error;
- (void)recordError:(NSError *)error withAdditionalUserInfo:(nullable CLS_GENERIC_NSDICTIONARY(NSString *, id) *)userInfo;
- (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:"); - (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
- (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:"); - (void)logEvent:(NSString *)eventName attributes:(nullable NSDictionary *) attributes CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");
+ (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:"); + (void)logEvent:(NSString *)eventName CLS_DEPRECATED("Please refer to Answers +logCustomEventWithName:");

Binary file not shown.

View File

@@ -11,8 +11,8 @@ DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
DIR="\"${DIR}" DIR="\"${DIR}"
PATH_SEP="/" PATH_SEP="/"
VALIDATE_COMMAND="uploadDSYM\" $@ validate" VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
UPLOAD_COMMAND="uploadDSYM\" $@" UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
# Ensure params are as expected, run in sync mode to validate # Ensure params are as expected, run in sync mode to validate
eval $DIR$PATH_SEP$VALIDATE_COMMAND eval $DIR$PATH_SEP$VALIDATE_COMMAND

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,7 +2,19 @@
// FABAttributes.h // FABAttributes.h
// Fabric // Fabric
// //
// Copyright (c) 2015 Twitter. All rights reserved. // Copyright (C) 2015 Twitter, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// //
#pragma once #pragma once

View File

@@ -1,7 +1,20 @@
// //
// Fabric.h // Fabric.h
// Fabric
// //
// Copyright (c) 2015 Twitter. All rights reserved. // Copyright (C) 2015 Twitter, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>

View File

@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.6.0</string> <string>1.6.7</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
@@ -25,31 +25,33 @@
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>37</string> <string>53</string>
<key>DTCompiler</key> <key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string> <string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key> <key>DTPlatformBuild</key>
<string>13B137</string> <string>13C75</string>
<key>DTPlatformName</key> <key>DTPlatformName</key>
<string>iphoneos</string> <string>iphoneos</string>
<key>DTPlatformVersion</key> <key>DTPlatformVersion</key>
<string>9.1</string> <string>9.2</string>
<key>DTSDKBuild</key> <key>DTSDKBuild</key>
<string>13B137</string> <string>13C75</string>
<key>DTSDKName</key> <key>DTSDKName</key>
<string>iphoneos9.1</string> <string>iphoneos9.2</string>
<key>DTXcode</key> <key>DTXcode</key>
<string>0710</string> <string>0721</string>
<key>DTXcodeBuild</key> <key>DTXcodeBuild</key>
<string>7B91b</string> <string>7C1002</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>6.0</string> <string>6.0</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Twitter. All rights reserved.</string> <string>Copyright © 2015 Twitter. All rights reserved.</string>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>
<array> <array>
<integer>1</integer> <integer>3</integer>
<integer>2</integer> <integer>2</integer>
<integer>1</integer>
<integer>4</integer>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@@ -11,8 +11,8 @@ DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
DIR="\"${DIR}" DIR="\"${DIR}"
PATH_SEP="/" PATH_SEP="/"
VALIDATE_COMMAND="uploadDSYM\" $@ validate" VALIDATE_COMMAND="uploadDSYM\" $@ validate run-script"
UPLOAD_COMMAND="uploadDSYM\" $@" UPLOAD_COMMAND="uploadDSYM\" $@ run-script"
# Ensure params are as expected, run in sync mode to validate # Ensure params are as expected, run in sync mode to validate
eval $DIR$PATH_SEP$VALIDATE_COMMAND eval $DIR$PATH_SEP$VALIDATE_COMMAND

Binary file not shown.

View File

@@ -18,17 +18,17 @@
}, },
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1DC75A27-0030-4493-ACE8-E1D49AB9A549", "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1DC75A27-0030-4493-ACE8-E1D49AB9A549",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"304AD0F97EA7B4893D91DFB8C3413D4E627B9472" : "MasterPassword\/External\/KCOrderedAccessorFix", "304AD0F97EA7B4893D91DFB8C3413D4E627B9472" : "MasterPassword\/External\/KCOrderedAccessorFix\/",
"2A70319CE0F91B35406CA7D970AE7CB4957B0A75" : "", "2A70319CE0F91B35406CA7D970AE7CB4957B0A75" : "",
"8A15A8EA0B3D0B497C4883425BC74DF995224BB3" : "MasterPassword\/External\/Pearl\/External\/jrswizzle", "8A15A8EA0B3D0B497C4883425BC74DF995224BB3" : "MasterPassword\/External\/jrswizzle\/",
"1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA" : "MasterPassword\/External\/InAppSettingsKit", "1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA" : "MasterPassword\/External\/InAppSettingsKit\/",
"1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A" : "MasterPassword\/External\/LoveLyndir", "1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A" : "MasterPassword\/External\/LoveLyndir",
"3E67FB08419C920516AAC3B00DAAF23073B8CF77" : "MasterPassword\/External\/RHStatusItemView", "3E67FB08419C920516AAC3B00DAAF23073B8CF77" : "MasterPassword\/External\/RHStatusItemView",
"3ED8592497DB6A564366943C9AAD5A46341B5076" : "MasterPassword\/External\/AttributedMarkdown", "3ED8592497DB6A564366943C9AAD5A46341B5076" : "MasterPassword\/External\/AttributedMarkdown\/",
"4DDCFFD91B41F00326AD14553BD66CFD366ABD91" : "MasterPassword\/External\/Pearl", "4DDCFFD91B41F00326AD14553BD66CFD366ABD91" : "MasterPassword\/External\/Pearl\/",
"E47DEC29CB0D0FDE3560EF46E1808FA1C723D657" : "MasterPassword\/External\/UbiquityStoreManager", "E47DEC29CB0D0FDE3560EF46E1808FA1C723D657" : "MasterPassword\/External\/UbiquityStoreManager",
"2FE140B36B7D26140DC8D5E5C639DC5900EFCF35" : "MasterPassword\/External\/Pearl\/External\/uicolor-utilities", "2FE140B36B7D26140DC8D5E5C639DC5900EFCF35" : "MasterPassword\/External\/uicolor-utilities\/",
"F788B28042EDBEF29EFE34687DA79A778C2CC260" : "MasterPassword" "F788B28042EDBEF29EFE34687DA79A778C2CC260" : "MasterPassword\/"
}, },
"DVTSourceControlWorkspaceBlueprintNameKey" : "MasterPassword", "DVTSourceControlWorkspaceBlueprintNameKey" : "MasterPassword",
"DVTSourceControlWorkspaceBlueprintVersion" : 204, "DVTSourceControlWorkspaceBlueprintVersion" : 204,

View File

@@ -5,3 +5,4 @@ set -e
cd "${BASH_SOURCE%/*}" cd "${BASH_SOURCE%/*}"
rm -vfr lib/*/{.unpacked,.patched,src} lib/include rm -vfr lib/*/{.unpacked,.patched,src} lib/include
rm -vfr *.o *.dSYM mpw mpw-bench mpw-tests

View File

@@ -19,6 +19,9 @@
const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) {
if (!fullName || !masterPassword)
return NULL;
switch (algorithmVersion) { switch (algorithmVersion) {
case MPAlgorithmVersion0: case MPAlgorithmVersion0:
return mpw_masterKeyForUser_v0( fullName, masterPassword ); return mpw_masterKeyForUser_v0( fullName, masterPassword );
@@ -37,6 +40,9 @@ const uint8_t *mpw_masterKeyForUser(const char *fullName, const char *masterPass
const char *mpw_passwordForSite(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const char *mpw_passwordForSite(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter,
const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion) { const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion) {
if (!masterKey || !siteName)
return NULL;
switch (algorithmVersion) { switch (algorithmVersion) {
case MPAlgorithmVersion0: case MPAlgorithmVersion0:
return mpw_passwordForSite_v0( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext ); return mpw_passwordForSite_v0( masterKey, siteName, siteType, siteCounter, siteVariant, siteContext );

View File

@@ -8,6 +8,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h" #include "mpw-types.h"
#include "mpw-util.h" #include "mpw-util.h"
@@ -21,10 +22,9 @@ static const char *mpw_templateForType_v0(MPSiteType type, uint16_t seedByte) {
size_t count = 0; size_t count = 0;
const char **templates = mpw_templatesForType( type, &count ); const char **templates = mpw_templatesForType( type, &count );
if (!count) char const *template = count? templates[seedByte % count]: NULL;
return NULL; free( templates );
return template;
return templates[seedByte % count];
} }
static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedByte) { static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedByte) {
@@ -37,7 +37,7 @@ static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword ); const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 0 ); trc( "algorithm: v%d\n", 0 );
trc( "fullName: %s (%zu)\n", fullName, mpw_charlen( fullName ) ); trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword ); trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope ); trc( "key scope: %s\n", mpKeyScope );
@@ -45,14 +45,14 @@ static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *
// masterKeySalt = mpKeyScope . #fullName . fullName // masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
mpw_pushString( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_pushInt( &masterKeySalt, &masterKeySaltSize, htonl( mpw_charlen( fullName ) ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_pushString( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno ); ftl( "Could not allocate master key salt: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKeySalt ID: %s\n", mpw_idForBuf( masterKeySalt, masterKeySaltSize ) ); trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt ) // masterKey = scrypt( masterPassword, masterKeySalt )
@@ -62,7 +62,7 @@ static const uint8_t *mpw_masterKeyForUser_v0(const char *fullName, const char *
ftl( "Could not allocate master key: %d\n", errno ); ftl( "Could not allocate master key: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKey ID: %s\n", mpw_idForBuf( masterKey, MP_dkLen ) ); trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey; return masterKey;
} }
@@ -86,19 +86,19 @@ static const char *mpw_passwordForSite_v0(const uint8_t *masterKey, const char *
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0; size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL; uint8_t *sitePasswordInfo = NULL;
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_charlen( siteName ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteName ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) { if (siteContext) {
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_charlen( siteContext ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteContext ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
} }
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno ); ftl( "Could not allocate site seed info: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordInfo ID: %s\n", mpw_idForBuf( sitePasswordInfo, sitePasswordInfoSize ) ); trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const char *sitePasswordSeed = (const char *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); const char *sitePasswordSeed = (const char *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize );
@@ -106,7 +106,7 @@ static const char *mpw_passwordForSite_v0(const uint8_t *masterKey, const char *
ftl( "Could not allocate site seed: %d\n", errno ); ftl( "Could not allocate site seed: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordSeed ID: %s\n", mpw_idForBuf( sitePasswordSeed, 32 ) ); trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template. // Determine the template.
const char *template = mpw_templateForType_v0( siteType, htons( sitePasswordSeed[0] ) ); const char *template = mpw_templateForType_v0( siteType, htons( sitePasswordSeed[0] ) );

View File

@@ -8,6 +8,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h" #include "mpw-types.h"
#include "mpw-util.h" #include "mpw-util.h"
@@ -21,7 +22,7 @@ static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword ); const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 1 ); trc( "algorithm: v%d\n", 1 );
trc( "fullName: %s (%zu)\n", fullName, mpw_charlen( fullName ) ); trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword ); trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope ); trc( "key scope: %s\n", mpKeyScope );
@@ -29,14 +30,14 @@ static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *
// masterKeySalt = mpKeyScope . #fullName . fullName // masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
mpw_pushString( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_pushInt( &masterKeySalt, &masterKeySaltSize, htonl( mpw_charlen( fullName ) ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_pushString( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno ); ftl( "Could not allocate master key salt: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKeySalt ID: %s\n", mpw_idForBuf( masterKeySalt, masterKeySaltSize ) ); trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt ) // masterKey = scrypt( masterPassword, masterKeySalt )
@@ -46,7 +47,7 @@ static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *
ftl( "Could not allocate master key: %d\n", errno ); ftl( "Could not allocate master key: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKey ID: %s\n", mpw_idForBuf( masterKey, MP_dkLen ) ); trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey; return masterKey;
} }
@@ -70,19 +71,19 @@ static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0; size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL; uint8_t *sitePasswordInfo = NULL;
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_charlen( siteName ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteName ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) { if (siteContext) {
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_charlen( siteContext ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteContext ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
} }
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno ); ftl( "Could not allocate site seed info: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordInfo ID: %s\n", mpw_idForBuf( sitePasswordInfo, sitePasswordInfoSize ) ); trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize );
@@ -90,7 +91,7 @@ static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *
ftl( "Could not allocate site seed: %d\n", errno ); ftl( "Could not allocate site seed: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordSeed ID: %s\n", mpw_idForBuf( sitePasswordSeed, 32 ) ); trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template. // Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] ); const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );

View File

@@ -8,6 +8,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h" #include "mpw-types.h"
#include "mpw-util.h" #include "mpw-util.h"
@@ -21,7 +22,7 @@ static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *
const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword ); const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
trc( "algorithm: v%d\n", 2 ); trc( "algorithm: v%d\n", 2 );
trc( "fullName: %s (%zu)\n", fullName, mpw_charlen( fullName ) ); trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
trc( "masterPassword: %s\n", masterPassword ); trc( "masterPassword: %s\n", masterPassword );
trc( "key scope: %s\n", mpKeyScope ); trc( "key scope: %s\n", mpKeyScope );
@@ -29,14 +30,14 @@ static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *
// masterKeySalt = mpKeyScope . #fullName . fullName // masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
mpw_pushString( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_pushInt( &masterKeySalt, &masterKeySaltSize, htonl( mpw_charlen( fullName ) ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) );
mpw_pushString( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno ); ftl( "Could not allocate master key salt: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKeySalt ID: %s\n", mpw_idForBuf( masterKeySalt, masterKeySaltSize ) ); trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt ) // masterKey = scrypt( masterPassword, masterKeySalt )
@@ -46,7 +47,7 @@ static const uint8_t *mpw_masterKeyForUser_v2(const char *fullName, const char *
ftl( "Could not allocate master key: %d\n", errno ); ftl( "Could not allocate master key: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKey ID: %s\n", mpw_idForBuf( masterKey, MP_dkLen ) ); trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey; return masterKey;
} }
@@ -70,19 +71,19 @@ static const char *mpw_passwordForSite_v2(const uint8_t *masterKey, const char *
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0; size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL; uint8_t *sitePasswordInfo = NULL;
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) { if (siteContext) {
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
} }
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno ); ftl( "Could not allocate site seed info: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordInfo ID: %s\n", mpw_idForBuf( sitePasswordInfo, sitePasswordInfoSize ) ); trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize );
@@ -90,7 +91,7 @@ static const char *mpw_passwordForSite_v2(const uint8_t *masterKey, const char *
ftl( "Could not allocate site seed: %d\n", errno ); ftl( "Could not allocate site seed: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordSeed ID: %s\n", mpw_idForBuf( sitePasswordSeed, 32 ) ); trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template. // Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] ); const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );

View File

@@ -8,6 +8,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <arpa/inet.h>
#include "mpw-types.h" #include "mpw-types.h"
#include "mpw-util.h" #include "mpw-util.h"
@@ -29,14 +30,14 @@ static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *
// masterKeySalt = mpKeyScope . #fullName . fullName // masterKeySalt = mpKeyScope . #fullName . fullName
size_t masterKeySaltSize = 0; size_t masterKeySaltSize = 0;
uint8_t *masterKeySalt = NULL; uint8_t *masterKeySalt = NULL;
mpw_pushString( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope );
mpw_pushInt( &masterKeySalt, &masterKeySaltSize, htonl( strlen( fullName ) ) ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( strlen( fullName ) ) );
mpw_pushString( &masterKeySalt, &masterKeySaltSize, fullName ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName );
if (!masterKeySalt) { if (!masterKeySalt) {
ftl( "Could not allocate master key salt: %d\n", errno ); ftl( "Could not allocate master key salt: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKeySalt ID: %s\n", mpw_idForBuf( masterKeySalt, masterKeySaltSize ) ); trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) );
// Calculate the master key. // Calculate the master key.
// masterKey = scrypt( masterPassword, masterKeySalt ) // masterKey = scrypt( masterPassword, masterKeySalt )
@@ -46,7 +47,7 @@ static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *
ftl( "Could not allocate master key: %d\n", errno ); ftl( "Could not allocate master key: %d\n", errno );
return NULL; return NULL;
} }
trc( "masterKey ID: %s\n", mpw_idForBuf( masterKey, MP_dkLen ) ); trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) );
return masterKey; return masterKey;
} }
@@ -70,19 +71,19 @@ static const char *mpw_passwordForSite_v3(const uint8_t *masterKey, const char *
// sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext )
size_t sitePasswordInfoSize = 0; size_t sitePasswordInfoSize = 0;
uint8_t *sitePasswordInfo = NULL; uint8_t *sitePasswordInfo = NULL;
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
if (siteContext) { if (siteContext) {
mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
} }
if (!sitePasswordInfo) { if (!sitePasswordInfo) {
ftl( "Could not allocate site seed info: %d\n", errno ); ftl( "Could not allocate site seed info: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordInfo ID: %s\n", mpw_idForBuf( sitePasswordInfo, sitePasswordInfoSize ) ); trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize );
mpw_free( sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize );
@@ -90,7 +91,7 @@ static const char *mpw_passwordForSite_v3(const uint8_t *masterKey, const char *
ftl( "Could not allocate site seed: %d\n", errno ); ftl( "Could not allocate site seed: %d\n", errno );
return NULL; return NULL;
} }
trc( "sitePasswordSeed ID: %s\n", mpw_idForBuf( sitePasswordSeed, 32 ) ); trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) );
// Determine the template. // Determine the template.
const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] ); const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );

View File

@@ -8,6 +8,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/time.h> #include <sys/time.h>
@@ -56,52 +57,79 @@ int main(int argc, char *const argv[]) {
const MPSiteVariant siteVariant = MPSiteVariantPassword; const MPSiteVariant siteVariant = MPSiteVariantPassword;
const char *siteContext = NULL; const char *siteContext = NULL;
struct timeval startTime; struct timeval startTime;
unsigned int iterations;
float percent;
const uint8_t *masterKey;
// Start HMAC-SHA-256
// Similar to phase-two of mpw
uint8_t *sitePasswordInfo = malloc( 128 );
iterations = 3000000;
masterKey = mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent );
if (!masterKey) {
ftl( "Could not allocate master key: %d\n", errno );
abort();
}
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
free( (void *)mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, 128 ) );
if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rhmac-sha-256: iteration %d / %d (%.0f%%)..", i, iterations, percent );
}
const double hmacSha256Speed = mpw_showSpeed( startTime, iterations, "hmac-sha-256" );
free( (void *)masterKey );
// Start BCrypt
// Similar to phase-one of mpw
int bcrypt_cost = 9;
iterations = 1000;
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
crypt( masterPassword, crypt_gensalt( "$2b$", bcrypt_cost, fullName, strlen( fullName ) ) );
if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d (%.0f%%)..", bcrypt_cost, i, iterations, percent );
}
const double bcrypt9Speed = mpw_showSpeed( startTime, iterations, "bcrypt9" );
// Start SCrypt
// Phase one of mpw
iterations = 50;
mpw_getTime( &startTime );
for (int i = 1; i <= iterations; ++i) {
free( (void *)mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent ) );
if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rscrypt_mpw: iteration %d / %d (%.0f%%)..", i, iterations, percent );
}
const double scryptSpeed = mpw_showSpeed( startTime, iterations, "scrypt_mpw" );
// Start MPW // Start MPW
unsigned int iterations = 100; // Both phases of mpw
iterations = 50;
mpw_getTime( &startTime ); mpw_getTime( &startTime );
for (int i = 0; i < iterations; ++i) { for (int i = 1; i <= iterations; ++i) {
const uint8_t *masterKey = mpw_masterKeyForUser( masterKey = mpw_masterKeyForUser( fullName, masterPassword, MPAlgorithmVersionCurrent );
fullName, masterPassword, MPAlgorithmVersionCurrent ); if (!masterKey) {
if (!masterKey)
ftl( "Could not allocate master key: %d\n", errno ); ftl( "Could not allocate master key: %d\n", errno );
abort();
}
free( (void *)mpw_passwordForSite( free( (void *)mpw_passwordForSite(
masterKey, siteName, siteType, siteCounter, siteVariant, siteContext, MPAlgorithmVersionCurrent ) ); masterKey, siteName, siteType, siteCounter, siteVariant, siteContext, MPAlgorithmVersionCurrent ) );
free( (void *)masterKey ); free( (void *)masterKey );
if (i % ( iterations / 100 ) == 0) if (modff(100.f * i / iterations, &percent) == 0)
fprintf( stderr, "\rmpw: iteration %d / %d (%d%%)..", i, iterations, i * 100 / iterations ); fprintf( stderr, "\rmpw: iteration %d / %d (%.0f%%)..", i, iterations, percent );
} }
const double mpwSpeed = mpw_showSpeed( startTime, iterations, "mpw" ); const double mpwSpeed = mpw_showSpeed( startTime, iterations, "mpw" );
// Start SHA-256
iterations = 45000000;
uint8_t hash[32];
mpw_getTime( &startTime );
for (int i = 0; i < iterations; ++i) {
SHA256_Buf( masterPassword, strlen( masterPassword ), hash );
if (i % ( iterations / 100 ) == 0)
fprintf( stderr, "\rsha256: iteration %d / %d (%d%%)..", i, iterations, i * 100 / iterations );
}
const double sha256Speed = mpw_showSpeed( startTime, iterations, "sha256" );
// Start BCrypt
int bcrypt_cost = 9;
iterations = 1000;
mpw_getTime( &startTime );
for (int i = 0; i < iterations; ++i) {
crypt( masterPassword, crypt_gensalt( "$2b$", bcrypt_cost, fullName, strlen( fullName ) ) );
if (i % ( iterations / 100 ) == 0)
fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d (%d%%)..", bcrypt_cost, i, iterations, i * 100 / iterations );
}
const double bcrypt9Speed = mpw_showSpeed( startTime, iterations, "bcrypt9" );
// Summarize. // Summarize.
fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" ); fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" );
fprintf( stdout, " - mpw is %f times slower than sha256 (reference: 320000 on an MBP Late 2013).\n", sha256Speed / mpwSpeed ); fprintf( stdout, " - mpw is %f times slower than hmac-sha-256 (reference: 320000 on an MBP Late 2013).\n", hmacSha256Speed / mpwSpeed );
fprintf( stdout, " - mpw is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / mpwSpeed ); fprintf( stdout, " - mpw is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / mpwSpeed );
fprintf( stdout, " - scrypt is %f times slower than bcrypt (cost 9) (reference: 22 on an MBP Late 2013).\n", bcrypt9Speed / scryptSpeed );
return 0; return 0;
} }

View File

@@ -78,14 +78,14 @@ static char *homedir(const char *filename) {
return homefile; return homefile;
} }
static char *getlinep(const char *prompt) { static char *getline_prompt(const char *prompt) {
char *buf = NULL; char *buf = NULL;
size_t bufSize = 0; size_t bufSize = 0;
ssize_t lineSize; ssize_t lineSize;
fprintf( stderr, "%s", prompt ); fprintf( stderr, "%s", prompt );
fprintf( stderr, " " ); fprintf( stderr, " " );
if ((lineSize = getline( &buf, &bufSize, stdin )) < 0) { if ((lineSize = getline( &buf, &bufSize, stdin )) <= 1) {
free( buf ); free( buf );
return NULL; return NULL;
} }
@@ -96,7 +96,7 @@ static char *getlinep(const char *prompt) {
int main(int argc, char *const argv[]) { int main(int argc, char *const argv[]) {
// Read the environment. // Read the environment.
char *fullName = getenv( MP_env_fullname ); const char *fullName = NULL;
const char *masterPassword = NULL; const char *masterPassword = NULL;
const char *siteName = NULL; const char *siteName = NULL;
MPSiteType siteType = MPSiteTypeGeneratedLong; MPSiteType siteType = MPSiteTypeGeneratedLong;
@@ -116,7 +116,7 @@ int main(int argc, char *const argv[]) {
for (int opt; (opt = getopt( argc, argv, "u:P:t:c:V:a:C:vqh" )) != -1;) for (int opt; (opt = getopt( argc, argv, "u:P:t:c:V:a:C:vqh" )) != -1;)
switch (opt) { switch (opt) {
case 'u': case 'u':
fullName = optarg; fullName = strdup( optarg );
break; break;
case 'P': case 'P':
// Do not use this. Passing your master password via the command-line // Do not use this. Passing your master password via the command-line
@@ -166,12 +166,14 @@ int main(int argc, char *const argv[]) {
ftl("Unexpected option: %c", opt); ftl("Unexpected option: %c", opt);
} }
if (optind < argc) if (optind < argc)
siteName = argv[optind]; siteName = strdup( argv[optind] );
// Convert and validate input. // Convert and validate input.
if (!fullName && !(fullName = getlinep( "Your full name:" ))) if (!fullName && (fullName = getenv( MP_env_fullname )))
fullName = strdup( fullName );
if (!fullName && !(fullName = getline_prompt( "Your full name:" )))
ftl( "Missing full name.\n" ); ftl( "Missing full name.\n" );
if (!siteName && !(siteName = getlinep( "Site name:" ))) if (!siteName && !(siteName = getline_prompt( "Site name:" )))
ftl( "Missing site name.\n" ); ftl( "Missing site name.\n" );
if (siteCounterString) if (siteCounterString)
siteCounter = (uint32_t)atol( siteCounterString ); siteCounter = (uint32_t)atol( siteCounterString );
@@ -210,21 +212,27 @@ int main(int argc, char *const argv[]) {
masterPassword = getpass( "Your master password: " ); masterPassword = getpass( "Your master password: " );
// Summarize operation. // Summarize operation.
fprintf( stderr, "%s's password for %s:\n[ %s ]: ", fullName, siteName, mpw_identicon( fullName, masterPassword ) ); const char *identicon = mpw_identicon( fullName, masterPassword );
fprintf( stderr, "%s's password for %s:\n[ %s ]: ", fullName, siteName, identicon );
mpw_free_string( identicon );
// Output the password. // Output the password.
const uint8_t *masterKey = mpw_masterKeyForUser( const uint8_t *masterKey = mpw_masterKeyForUser(
fullName, masterPassword, algorithmVersion ); fullName, masterPassword, algorithmVersion );
mpw_freeString( masterPassword ); mpw_free_string( masterPassword );
mpw_free_string( fullName );
if (!masterKey) if (!masterKey)
ftl( "Couldn't derive master key." ); ftl( "Couldn't derive master key." );
const char *sitePassword = mpw_passwordForSite( const char *sitePassword = mpw_passwordForSite(
masterKey, siteName, siteType, siteCounter, siteVariant, siteContextString, algorithmVersion ); masterKey, siteName, siteType, siteCounter, siteVariant, siteContextString, algorithmVersion );
mpw_free( masterKey, MP_dkLen ); mpw_free( masterKey, MP_dkLen );
mpw_free_string( siteName );
if (!sitePassword) if (!sitePassword)
ftl( "Couldn't derive site password." ); ftl( "Couldn't derive site password." );
fprintf( stdout, "%s\n", sitePassword ); fprintf( stdout, "%s\n", sitePassword );
mpw_free_string( sitePassword );
return 0; return 0;
} }

View File

@@ -65,7 +65,7 @@ int main(int argc, char *const argv[]) {
} }
// Free test case. // Free test case.
mpw_freeString( sitePassword ); mpw_free_string( sitePassword );
xmlFree( id ); xmlFree( id );
xmlFree( fullName ); xmlFree( fullName );
xmlFree( masterPassword ); xmlFree( masterPassword );

View File

@@ -50,6 +50,7 @@ const MPSiteType mpw_typeWithName(const char *typeName) {
return MPSiteTypeGeneratedPhrase; return MPSiteTypeGeneratedPhrase;
ftl( "Not a generated type name: %s", stdTypeName ); ftl( "Not a generated type name: %s", stdTypeName );
return MPSiteTypeGeneratedLong;
} }
const char **mpw_templatesForType(MPSiteType type, size_t *count) { const char **mpw_templatesForType(MPSiteType type, size_t *count) {
@@ -62,11 +63,11 @@ const char **mpw_templatesForType(MPSiteType type, size_t *count) {
switch (type) { switch (type) {
case MPSiteTypeGeneratedMaximum: { case MPSiteTypeGeneratedMaximum: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" ); "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" );
} }
case MPSiteTypeGeneratedLong: { case MPSiteTypeGeneratedLong: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno",
"CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno",
"CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno",
@@ -76,27 +77,27 @@ const char **mpw_templatesForType(MPSiteType type, size_t *count) {
"CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" ); "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" );
} }
case MPSiteTypeGeneratedMedium: { case MPSiteTypeGeneratedMedium: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"CvcnoCvc", "CvcCvcno" ); "CvcnoCvc", "CvcCvcno" );
} }
case MPSiteTypeGeneratedBasic: { case MPSiteTypeGeneratedBasic: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"aaanaaan", "aannaaan", "aaannaaa" ); "aaanaaan", "aannaaan", "aaannaaa" );
} }
case MPSiteTypeGeneratedShort: { case MPSiteTypeGeneratedShort: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"Cvcn" ); "Cvcn" );
} }
case MPSiteTypeGeneratedPIN: { case MPSiteTypeGeneratedPIN: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"nnnn" ); "nnnn" );
} }
case MPSiteTypeGeneratedName: { case MPSiteTypeGeneratedName: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"cvccvcvcv" ); "cvccvcvcv" );
} }
case MPSiteTypeGeneratedPhrase: { case MPSiteTypeGeneratedPhrase: {
return alloc_array( *count, const char *, return mpw_alloc_array( *count, const char *,
"cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" ); "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
} }
default: { default: {
@@ -111,10 +112,7 @@ const char *mpw_templateForType(MPSiteType type, uint8_t seedByte) {
size_t count = 0; size_t count = 0;
const char **templates = mpw_templatesForType( type, &count ); const char **templates = mpw_templatesForType( type, &count );
if (!count) char const *template = count? templates[seedByte % count]: NULL;
return NULL;
char const *template = templates[seedByte % count];
free( templates ); free( templates );
return template; return template;
} }

View File

@@ -21,7 +21,7 @@
#include "mpw-util.h" #include "mpw-util.h"
void mpw_pushBuf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) { void mpw_push_buf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) {
if (*bufferSize == (size_t)-1) if (*bufferSize == (size_t)-1)
// The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content. // The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content.
@@ -42,23 +42,25 @@ void mpw_pushBuf(uint8_t **const buffer, size_t *const bufferSize, const void *p
memcpy( pushDst, pushBuffer, pushSize ); memcpy( pushDst, pushBuffer, pushSize );
} }
void mpw_pushString(uint8_t **buffer, size_t *const bufferSize, const char *pushString) { void mpw_push_string(uint8_t **buffer, size_t *const bufferSize, const char *pushString) {
mpw_pushBuf( buffer, bufferSize, pushString, strlen( pushString ) ); mpw_push_buf( buffer, bufferSize, pushString, strlen( pushString ) );
} }
void mpw_pushInt(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) { void mpw_push_int(uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt) {
mpw_pushBuf( buffer, bufferSize, &pushInt, sizeof( pushInt ) ); mpw_push_buf( buffer, bufferSize, &pushInt, sizeof( pushInt ) );
} }
void mpw_free(const void *buffer, const size_t bufferSize) { void mpw_free(const void *buffer, const size_t bufferSize) {
memset( (void *)buffer, 0, bufferSize ); if (buffer) {
free( (void *)buffer ); memset( (void *)buffer, 0, bufferSize );
free( (void *)buffer );
}
} }
void mpw_freeString(const char *string) { void mpw_free_string(const char *string) {
mpw_free( string, strlen( string ) ); mpw_free( string, strlen( string ) );
} }
@@ -66,6 +68,9 @@ void mpw_freeString(const char *string) {
uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize, 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) { uint64_t N, uint32_t r, uint32_t p) {
if (!secret || !salt)
return NULL;
uint8_t *key = malloc( keySize ); uint8_t *key = malloc( keySize );
if (!key) if (!key)
return NULL; return NULL;
@@ -88,7 +93,7 @@ uint8_t const *mpw_hmac_sha256(const uint8_t *key, const size_t keySize, const u
return buffer; return buffer;
} }
const char *mpw_idForBuf(const void *buf, size_t length) { const char *mpw_id_buf(const void *buf, size_t length) {
uint8_t hash[32]; uint8_t hash[32];
SHA256_Buf( buf, length, hash ); SHA256_Buf( buf, length, hash );
@@ -124,15 +129,23 @@ const char *mpw_hex_l(uint32_t number) {
#ifdef COLOR #ifdef COLOR
static int putvari; static int putvari;
static char *putvarc = NULL; static char *putvarc = NULL;
static int istermsetup = 0; static int termsetup;
static void initputvar() { static int initputvar() {
if (!isatty(STDERR_FILENO))
return 0;
if (putvarc) if (putvarc)
free(putvarc); free(putvarc);
if (!termsetup) {
int status;
if (! (termsetup = (setupterm(NULL, STDERR_FILENO, &status) == OK && status == 1))) {
wrn( "Terminal doesn't support color (setupterm errno %d).\n", status );
return 0;
}
}
putvarc=(char *)calloc(256, sizeof(char)); putvarc=(char *)calloc(256, sizeof(char));
putvari=0; putvari=0;
return 1;
if (!istermsetup)
istermsetup = (OK == setupterm(NULL, STDERR_FILENO, NULL));
} }
static int putvar(int c) { static int putvar(int c) {
putvarc[putvari++]=c; putvarc[putvari++]=c;
@@ -156,9 +169,8 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
char *colorString, *resetString; char *colorString, *resetString;
#ifdef COLOR #ifdef COLOR
if (isatty( STDERR_FILENO )) { if (initputvar()) {
uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1); uint8_t colorIdentifier = (uint8_t)(identiconSeed[4] % 7 + 1);
initputvar();
tputs(tparm(tgetstr("AF", NULL), colorIdentifier), 1, putvar); tputs(tparm(tgetstr("AF", NULL), colorIdentifier), 1, putvar);
colorString = calloc(strlen(putvarc) + 1, sizeof(char)); colorString = calloc(strlen(putvarc) + 1, sizeof(char));
strcpy(colorString, putvarc); strcpy(colorString, putvarc);
@@ -189,7 +201,7 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword) {
/** /**
* @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte. * @return the amount of bytes used by UTF-8 to encode a single character that starts with the given byte.
*/ */
static int mpw_charByteSize(unsigned char utf8Byte) { static int mpw_utf8_sizeof(unsigned char utf8Byte) {
if (!utf8Byte) if (!utf8Byte)
return 0; return 0;
@@ -207,11 +219,11 @@ static int mpw_charByteSize(unsigned char utf8Byte) {
return 0; return 0;
} }
const size_t mpw_charlen(const char *utf8String) { const size_t mpw_utf8_strlen(const char *utf8String) {
size_t charlen = 0; size_t charlen = 0;
char *remainingString = (char *)utf8String; char *remainingString = (char *)utf8String;
for (int charByteSize; (charByteSize = mpw_charByteSize( (unsigned char)*remainingString )); remainingString += charByteSize) for (int charByteSize; (charByteSize = mpw_utf8_sizeof( (unsigned char)*remainingString )); remainingString += charByteSize)
++charlen; ++charlen;
return charlen; return charlen;

View File

@@ -54,7 +54,7 @@ int mpw_verbosity;
//// Buffers and memory. //// Buffers and memory.
#define alloc_array(_count, _type, ...) ({ \ #define mpw_alloc_array(_count, _type, ...) ({ \
_type stackElements[] = { __VA_ARGS__ }; \ _type stackElements[] = { __VA_ARGS__ }; \
_count = sizeof( stackElements ) / sizeof( _type ); \ _count = sizeof( stackElements ) / sizeof( _type ); \
_type *allocElements = malloc( sizeof( stackElements ) ); \ _type *allocElements = malloc( sizeof( stackElements ) ); \
@@ -63,19 +63,19 @@ int mpw_verbosity;
}) })
/** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */ /** Push a buffer onto a buffer. reallocs the given buffer and appends the given buffer. */
void mpw_pushBuf( void mpw_push_buf(
uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize); 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. */ /** Push a string onto a buffer. reallocs the given buffer and appends the given string. */
void mpw_pushString( void mpw_push_string(
uint8_t **buffer, size_t *const bufferSize, const char *pushString); 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. */ /** Push an integer onto a buffer. reallocs the given buffer and appends the given integer. */
void mpw_pushInt( void mpw_push_int(
uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt); uint8_t **const buffer, size_t *const bufferSize, const uint32_t pushInt);
/** Free a buffer after zero'ing its contents. */ /** Free a buffer after zero'ing its contents. */
void mpw_free( void mpw_free(
const void *buffer, const size_t bufferSize); const void *buffer, const size_t bufferSize);
/** Free a string after zero'ing its contents. */ /** Free a string after zero'ing its contents. */
void mpw_freeString( void mpw_free_string(
const char *string); const char *string);
//// Cryptographic functions. //// Cryptographic functions.
@@ -98,7 +98,7 @@ const char *mpw_hex(const void *buf, size_t length);
const char *mpw_hex_l(uint32_t number); const char *mpw_hex_l(uint32_t number);
/** Encode a fingerprint for a buffer. /** Encode a fingerprint for a buffer.
* @return A C-string in a reused buffer, do not free or store it. */ * @return A C-string in a reused buffer, do not free or store it. */
const char *mpw_idForBuf(const void *buf, size_t length); const char *mpw_id_buf(const void *buf, size_t length);
/** Encode a visual fingerprint for a user. /** Encode a visual fingerprint for a user.
* @return A newly allocated string. */ * @return A newly allocated string. */
const char *mpw_identicon(const char *fullName, const char *masterPassword); const char *mpw_identicon(const char *fullName, const char *masterPassword);
@@ -106,4 +106,4 @@ const char *mpw_identicon(const char *fullName, const char *masterPassword);
//// String utilities. //// String utilities.
/** @return The amount of display characters in the given UTF-8 string. */ /** @return The amount of display characters in the given UTF-8 string. */
const size_t mpw_charlen(const char *utf8String); const size_t mpw_utf8_strlen(const char *utf8String);

View File

@@ -5,7 +5,7 @@ mpw() {
if hash pbcopy 2>/dev/null; then if hash pbcopy 2>/dev/null; then
pbcopy pbcopy
elif hash xclip 2>/dev/null; then elif hash xclip 2>/dev/null; then
xclip xclip -selection clip
else else
cat; echo 2>/dev/null cat; echo 2>/dev/null
return return

View File

@@ -1 +1 @@
../Java/masterpassword-algorithm/src/test/resources/mpw_tests.xml ../Java/masterpassword-tests/src/main/resources/mpw_tests.xml

View File

@@ -1,2 +1,8 @@
# Gradle
build
.gradle
local.properties
# Maven
target target
dependency-reduced-pom.xml dependency-reduced-pom.xml

View File

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

View File

@@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Wed Feb 08 01:04:17 EST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

172
MasterPassword/Java/gradlew vendored Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
MasterPassword/Java/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

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

View File

@@ -0,0 +1,74 @@
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 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;
}

View File

@@ -16,12 +16,12 @@ import org.jetbrains.annotations.Contract;
*/ */
public enum MPSiteType { public enum MPSiteType {
GeneratedMaximum( "20 characters, contains symbols.", // GeneratedMaximum( "Max", "20 characters, contains symbols.", //
ImmutableList.of( "x", "max", "maximum" ), // ImmutableList.of( "x", "max", "maximum" ), //
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), // ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPSiteTypeClass.Generated, 0x0 ), MPSiteTypeClass.Generated, 0x0 ),
GeneratedLong( "Copy-friendly, 14 characters, contains symbols.", // GeneratedLong( "Long", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( "l", "long" ), // ImmutableList.of( "l", "long" ), //
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ), ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
@@ -36,49 +36,50 @@ public enum MPSiteType {
new MPTemplate( "CvccCvcvCvccno" ) ), // new MPTemplate( "CvccCvcvCvccno" ) ), //
MPSiteTypeClass.Generated, 0x1 ), MPSiteTypeClass.Generated, 0x1 ),
GeneratedMedium( "Copy-friendly, 8 characters, contains symbols.", // GeneratedMedium( "Medium", "Copy-friendly, 8 characters, contains symbols.", //
ImmutableList.of( "m", "med", "medium" ), // ImmutableList.of( "m", "med", "medium" ), //
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), // ImmutableList.of( new MPTemplate( "CvcnoCvc" ), new MPTemplate( "CvcCvcno" ) ), //
MPSiteTypeClass.Generated, 0x2 ), MPSiteTypeClass.Generated, 0x2 ),
GeneratedBasic( "8 characters, no symbols.", // GeneratedBasic( "Basic", "8 characters, no symbols.", //
ImmutableList.of( "b", "basic" ), // ImmutableList.of( "b", "basic" ), //
ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), // ImmutableList.of( new MPTemplate( "aaanaaan" ), new MPTemplate( "aannaaan" ), new MPTemplate( "aaannaaa" ) ), //
MPSiteTypeClass.Generated, 0x3 ), MPSiteTypeClass.Generated, 0x3 ),
GeneratedShort( "Copy-friendly, 4 characters, no symbols.", // GeneratedShort( "Short", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( "s", "short" ), // ImmutableList.of( "s", "short" ), //
ImmutableList.of( new MPTemplate( "Cvcn" ) ), // ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPSiteTypeClass.Generated, 0x4 ), MPSiteTypeClass.Generated, 0x4 ),
GeneratedPIN( "4 numbers.", // GeneratedPIN( "PIN", "4 numbers.", //
ImmutableList.of( "i", "pin" ), // ImmutableList.of( "i", "pin" ), //
ImmutableList.of( new MPTemplate( "nnnn" ) ), // ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPSiteTypeClass.Generated, 0x5 ), MPSiteTypeClass.Generated, 0x5 ),
GeneratedName( "9 letter name.", // GeneratedName( "Name", "9 letter name.", //
ImmutableList.of( "n", "name" ), // ImmutableList.of( "n", "name" ), //
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), // ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPSiteTypeClass.Generated, 0xE ), MPSiteTypeClass.Generated, 0xE ),
GeneratedPhrase( "20 character sentence.", // GeneratedPhrase( "Phrase", "20 character sentence.", //
ImmutableList.of( "p", "phrase" ), // ImmutableList.of( "p", "phrase" ), //
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ), ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), // new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
MPSiteTypeClass.Generated, 0xF ), MPSiteTypeClass.Generated, 0xF ),
StoredPersonal( "AES-encrypted, exportable.", // StoredPersonal( "Personal", "AES-encrypted, exportable.", //
ImmutableList.of( "personal" ), // ImmutableList.of( "personal" ), //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ), MPSiteTypeClass.Stored, 0x0, MPSiteFeature.ExportContent ),
StoredDevicePrivate( "AES-encrypted, not exported.", // StoredDevicePrivate( "Device", "AES-encrypted, not exported.", //
ImmutableList.of( "device" ), // ImmutableList.of( "device" ), //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate ); MPSiteTypeClass.Stored, 0x1, MPSiteFeature.DevicePrivate );
static final Logger logger = Logger.get( MPSiteType.class ); static final Logger logger = Logger.get( MPSiteType.class );
private final String shortName;
private final String description; private final String description;
private final List<String> options; private final List<String> options;
private final List<MPTemplate> templates; private final List<MPTemplate> templates;
@@ -86,9 +87,10 @@ public enum MPSiteType {
private final int typeIndex; private final int typeIndex;
private final Set<MPSiteFeature> typeFeatures; private final Set<MPSiteFeature> typeFeatures;
MPSiteType(final String description, final List<String> options, final List<MPTemplate> templates, final MPSiteTypeClass typeClass, MPSiteType(final String shortName, final String description, final List<String> options, final List<MPTemplate> templates,
final int typeIndex, final MPSiteFeature... typeFeatures) { final MPSiteTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
this.shortName = shortName;
this.description = description; this.description = description;
this.options = options; this.options = options;
this.templates = templates; this.templates = templates;
@@ -102,6 +104,10 @@ public enum MPSiteType {
this.typeFeatures = typeFeaturesBuilder.build(); this.typeFeatures = typeFeaturesBuilder.build();
} }
public String getShortName() {
return shortName;
}
public String getDescription() { public String getDescription() {
return description; return description;

View File

@@ -16,10 +16,12 @@ import org.jetbrains.annotations.NotNull;
public abstract class MasterKey { public abstract class MasterKey {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKey.class ); private static final Logger logger = Logger.get( MasterKey.class );
private static boolean allowNativeByDefault = true;
@Nonnull @Nonnull
private final String fullName; private final String fullName;
private boolean allowNative = allowNativeByDefault;
@Nullable @Nullable
private byte[] masterKey; private byte[] masterKey;
@@ -46,6 +48,23 @@ public abstract class MasterKey {
throw new UnsupportedOperationException( "Unsupported version: " + version ); throw new UnsupportedOperationException( "Unsupported version: " + 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(@NotNull final String fullName) { protected MasterKey(@NotNull final String fullName) {
this.fullName = fullName; this.fullName = fullName;
@@ -63,6 +82,15 @@ public abstract class MasterKey {
return fullName; return fullName;
} }
public boolean isAllowNative() {
return allowNative;
}
public MasterKey setAllowNative(final boolean allowNative) {
this.allowNative = allowNative;
return this;
}
@Nonnull @Nonnull
protected byte[] getKey() { protected byte[] getKey() {

View File

@@ -1,6 +1,5 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
@@ -8,7 +7,6 @@ import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.system.*; import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*; import java.nio.*;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.Arrays; import java.util.Arrays;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -25,19 +23,11 @@ import javax.annotation.Nullable;
*/ */
public class MasterKeyV0 extends MasterKey { public class MasterKeyV0 extends MasterKey {
private static final int MP_intLen = 32;
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKeyV0.class ); private static final Logger logger = Logger.get( MasterKeyV0.class );
protected final int MP_N = 32768;
protected final int MP_r = 8;
protected final int MP_p = 2;
protected final int MP_dkLen = 64;
protected final int MP_intLen = 32;
protected final Charset MP_charset = Charsets.UTF_8;
protected final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
protected final MessageDigests MP_hash = MessageDigests.SHA256;
protected final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
public MasterKeyV0(final String fullName) { public MasterKeyV0(final String fullName) {
super( fullName ); super( fullName );
} }
@@ -52,21 +42,28 @@ public class MasterKeyV0 extends MasterKey {
@Override @Override
protected byte[] deriveKey(final char[] masterPassword) { protected byte[] deriveKey(final char[] masterPassword) {
String fullName = getFullName(); String fullName = getFullName();
byte[] fullNameBytes = fullName.getBytes( MP_charset ); byte[] fullNameBytes = fullName.getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullName.length() ); byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
String mpKeyScope = MPSiteVariant.Password.getScope(); String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MP_charset ), fullNameLengthBytes, fullNameBytes ); byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope ); logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) ); logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) ); ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()]; byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length ); mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte) 0 ); Arrays.fill( mpBytesBuf.array(), (byte) 0 );
return scrypt( masterKeySalt, mpBytes );
}
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try { try {
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen ); 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 (GeneralSecurityException e) { catch (GeneralSecurityException e) {
logger.bug( e ); logger.bug( e );
@@ -92,22 +89,22 @@ public class MasterKeyV0 extends MasterKey {
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); 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 ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes ); sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) ); logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeedBytes = MP_mac.of( getKey(), sitePasswordInfo ); byte[] sitePasswordSeedBytes = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length]; int[] sitePasswordSeed = new int[sitePasswordSeedBytes.length];
for (int i = 0; i < sitePasswordSeedBytes.length; ++i) { for (int i = 0; i < sitePasswordSeedBytes.length; ++i) {
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN ); ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( ByteOrder.BIG_ENDIAN );
@@ -139,16 +136,16 @@ public class MasterKeyV0 extends MasterKey {
@Override @Override
protected byte[] bytesForInt(final int number) { protected byte[] bytesForInt(final int number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MP_byteOrder ).putInt( number ).array(); return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number ).array();
} }
@Override @Override
protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) { protected byte[] bytesForInt(@Nonnull final UnsignedInteger number) {
return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MP_byteOrder ).putInt( number.intValue() ).array(); return ByteBuffer.allocate( MP_intLen / Byte.SIZE ).order( MPConstant.mpw_byteOrder ).putInt( number.intValue() ).array();
} }
@Override @Override
protected byte[] idForBytes(final byte[] bytes) { protected byte[] idForBytes(final byte[] bytes) {
return MP_hash.of( bytes ); return MPConstant.mpw_hash.of( bytes );
} }
} }

View File

@@ -46,22 +46,22 @@ public class MasterKeyV1 extends MasterKeyV0 {
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteName.length() ); byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); 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 ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes ); sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) ); logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MP_mac.of( getKey(), sitePasswordInfo ); byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) ); logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 ); Preconditions.checkState( sitePasswordSeed.length > 0 );

View File

@@ -45,22 +45,22 @@ public class MasterKeyV2 extends MasterKeyV1 {
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 ); siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (300 * 1000)) * 300 );
String siteScope = siteVariant.getScope(); String siteScope = siteVariant.getScope();
byte[] siteNameBytes = siteName.getBytes( MP_charset ); byte[] siteNameBytes = siteName.getBytes( MPConstant.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length ); byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
byte[] siteCounterBytes = bytesForInt( siteCounter ); byte[] siteCounterBytes = bytesForInt( siteCounter );
byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MP_charset ); byte[] siteContextBytes = siteContext == null || siteContext.isEmpty()? null: siteContext.getBytes( MPConstant.mpw_charset );
byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length ); byte[] siteContextLengthBytes = bytesForInt( siteContextBytes == null? 0: siteContextBytes.length );
logger.trc( "site scope: %s, context: %s", siteScope, siteContextBytes == null? "<empty>": siteContext ); 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 ), logger.trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)", siteScope, CodeUtils.encodeHex( siteNameLengthBytes ),
siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), CodeUtils.encodeHex( siteContextLengthBytes ),
siteContextBytes == null? "(null)": siteContext ); siteContextBytes == null? "(null)": siteContext );
byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MP_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes ); byte[] sitePasswordInfo = Bytes.concat( siteScope.getBytes( MPConstant.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (siteContextBytes != null) if (siteContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes ); sitePasswordInfo = Bytes.concat( sitePasswordInfo, siteContextLengthBytes, siteContextBytes );
logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) ); logger.trc( "sitePasswordInfo ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
byte[] sitePasswordSeed = MP_mac.of( getKey(), sitePasswordInfo ); byte[] sitePasswordSeed = MPConstant.mpw_digest.of( getKey(), sitePasswordInfo );
logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) ); logger.trc( "sitePasswordSeed ID: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeed ) ) );
Preconditions.checkState( sitePasswordSeed.length > 0 ); Preconditions.checkState( sitePasswordSeed.length > 0 );

View File

@@ -1,12 +1,10 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.system.CodeUtils; import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.security.GeneralSecurityException;
import java.util.Arrays; import java.util.Arrays;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -14,7 +12,7 @@ import javax.annotation.Nullable;
/** /**
* bugs: * bugs:
* - no known issues. * - no known issues.
* *
* @author lhunath, 2014-08-30 * @author lhunath, 2014-08-30
*/ */
public class MasterKeyV3 extends MasterKeyV2 { public class MasterKeyV3 extends MasterKeyV2 {
@@ -35,28 +33,19 @@ public class MasterKeyV3 extends MasterKeyV2 {
@Nullable @Nullable
@Override @Override
protected byte[] deriveKey(final char[] masterPassword) { protected byte[] deriveKey(final char[] masterPassword) {
byte[] fullNameBytes = getFullName().getBytes( MP_charset ); byte[] fullNameBytes = getFullName().getBytes( MPConstant.mpw_charset );
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length ); byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
String mpKeyScope = MPSiteVariant.Password.getScope(); String mpKeyScope = MPSiteVariant.Password.getScope();
byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MP_charset ), fullNameLengthBytes, fullNameBytes ); byte[] masterKeySalt = Bytes.concat( mpKeyScope.getBytes( MPConstant.mpw_charset ), fullNameLengthBytes, fullNameBytes );
logger.trc( "key scope: %s", mpKeyScope ); logger.trc( "key scope: %s", mpKeyScope );
logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) ); logger.trc( "masterKeySalt ID: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
ByteBuffer mpBytesBuf = MP_charset.encode( CharBuffer.wrap( masterPassword ) ); ByteBuffer mpBytesBuf = MPConstant.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
byte[] mpBytes = new byte[mpBytesBuf.remaining()]; byte[] mpBytes = new byte[mpBytesBuf.remaining()];
mpBytesBuf.get( mpBytes, 0, mpBytes.length ); mpBytesBuf.get( mpBytes, 0, mpBytes.length );
Arrays.fill( mpBytesBuf.array(), (byte)0 ); Arrays.fill( mpBytesBuf.array(), (byte) 0 );
try { return scrypt( masterKeySalt, mpBytes );
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
}
catch (GeneralSecurityException e) {
logger.bug( e );
return null;
}
finally {
Arrays.fill( mpBytes, (byte) 0 );
}
} }
} }

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyndir.masterpassword"
android:versionCode="2003"
android:versionName="2.3">
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="21" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:allowBackup="true">
<activity android:name=".TestActivity" android:theme="@style/MPTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".EmergencyActivity" android:theme="@style/MPTheme" />
</application>
</manifest>

View File

@@ -0,0 +1,44 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
defaultConfig {
applicationId "com.lyndir.masterpassword"
minSdkVersion 19
targetSdkVersion 25
versionCode 20401
versionName "2.4.1"
}
// release with: STORE_PW=$(mpw masterpassword.keystore) KEY_PW=$(mpw masterpassword-android) gradle assembleRelease
signingConfigs {
release {
storeFile file('masterpassword.keystore')
storePassword System.getenv('STORE_PW')
keyAlias 'masterpassword-android'
keyPassword System.getenv('KEY_PW')
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
dependencies {
compile project( ':masterpassword-algorithm' )
compile project( ':masterpassword-tests' )
// Android dependencies
compile 'org.slf4j:slf4j-android:1.7.13-underscore'
compile 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
compile files('libs/scrypt-1.4.0-native.jar')
}

View File

@@ -1,8 +0,0 @@
/*___Generated_by_IDEA___*/
package com.lyndir.masterpassword;
/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
public final class BuildConfig {
public final static boolean DEBUG = Boolean.parseBoolean(null);
}

View File

@@ -1,7 +0,0 @@
/*___Generated_by_IDEA___*/
package com.lyndir.masterpassword;
/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
public final class Manifest {
}

View File

@@ -1,7 +0,0 @@
/*___Generated_by_IDEA___*/
package com.lyndir.masterpassword;
/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
public final class R {
}

View File

@@ -0,0 +1 @@
/Users/lhunath/annex/secret/release-com.lyndir.masterpassword.jks

View File

@@ -0,0 +1 @@
/Users/lhunath/annex/secret/masterpassword.keystore

View File

@@ -67,6 +67,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId> <artifactId>maven-jarsigner-plugin</artifactId>
<version>1.4</version>
<executions> <executions>
<execution> <execution>
<id>signing</id> <id>signing</id>

View File

@@ -1 +0,0 @@
/Users/lhunath/SpiderOak Hive/secret/release-com.lyndir.masterpassword.jks

View File

@@ -1,174 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="@drawable/background">
<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" />
<EditText
android:id="@+id/fullNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/masterPasswordField"
android:inputType="text|textCapWords|textPersonName"
android:hint="@string/fullName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="26sp" />
<CheckBox
android:id="@+id/rememberFullNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/rememberPasswordField"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/remember" />
<EditText
android:id="@id/masterPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteNameField"
android:inputType="text|textPassword"
android:hint="@string/masterPassword_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="18sp" />
<CheckBox
android:id="@id/rememberPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/forgetOnClose" />
<EditText
android:id="@id/siteNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/sitePasswordField"
android:inputType="text|textNoSuggestions|textUri"
android:hint="@string/siteName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="18sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progressView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="20dp"
android:indeterminate="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<Button
android:id="@id/sitePasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteTypeField"
android:gravity="center"
android:background="@android:color/transparent"
android:textColor="#FFFFFF"
android:textSize="32sp"
android:text="LuxdZozvDuma4["
android:onClick="copySitePassword" />
<TextView
android:id="@+id/sitePasswordTip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/sitePasswordField"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/sitePassword_hint" />
</LinearLayout>
</FrameLayout>
<CheckBox
android:id="@+id/maskPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/maskPassword" />
<Spinner
android:id="@id/siteTypeField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/counterField"
android:gravity="center" />
<EditText
android:id="@id/counterField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteVersionField"
android:gravity="center"
android:inputType="text|textNoSuggestions"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:text="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/counterField"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteCounter_hint" />
<Spinner
android:id="@id/siteVersionField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@id/rememberFullNameField"
android:gravity="center" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:labelFor="@id/siteVersionField"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="14sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteVersion_hint" />
<View
android:layout_width="1dp"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyndir.masterpassword">
<application
android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:name=".EmergencyActivity"
android:theme="@style/MPTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".TestActivity"
android:theme="@style/MPTheme" />
</application>
</manifest>

View File

@@ -1,6 +1,5 @@
package com.lyndir.masterpassword; package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import android.app.*; import android.app.*;
@@ -14,12 +13,14 @@ import android.text.method.PasswordTransformationMethod;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.*; import android.widget.*;
import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.google.common.util.concurrent.*; import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.text.MessageFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -32,60 +33,52 @@ public class EmergencyActivity extends Activity {
private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) ); private static final ClipData EMPTY_CLIP = new ClipData( new ClipDescription( "", new String[0] ), new ClipData.Item( "" ) );
private static final int PASSWORD_NOTIFICATION = 0; private static final int PASSWORD_NOTIFICATION = 0;
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() ); private final Preferences preferences = Preferences.get( this );
private final ValueChangedListener updateMasterKey = new ValueChangedListener() { private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
@Override private final ImmutableList<MPSiteType> allSiteTypes = ImmutableList.copyOf( MPSiteType.forClass( MPSiteTypeClass.Generated ) );
void update() { private final ImmutableList<MasterKey.Version> allVersions = ImmutableList.copyOf( MasterKey.Version.values() );
updateMasterKey();
}
};
private final ValueChangedListener updateSitePassword = new ValueChangedListener() {
@Override
void update() {
updateSitePassword();
}
};
private ListenableFuture<MasterKey> masterKeyFuture; private ListenableFuture<MasterKey> masterKeyFuture;
@InjectView(R.id.progressView) @BindView(R.id.progressView)
ProgressBar progressView; ProgressBar progressView;
@InjectView(R.id.fullNameField) @BindView(R.id.fullNameField)
EditText fullNameField; EditText fullNameField;
@InjectView(R.id.masterPasswordField) @BindView(R.id.masterPasswordField)
EditText masterPasswordField; EditText masterPasswordField;
@InjectView(R.id.siteNameField) @BindView(R.id.siteNameField)
EditText siteNameField; EditText siteNameField;
@InjectView(R.id.siteTypeField) @BindView(R.id.siteTypeButton)
Spinner siteTypeField; Button siteTypeButton;
@InjectView(R.id.counterField) @BindView(R.id.counterField)
EditText counterField; Button siteCounterButton;
@InjectView(R.id.siteVersionField) @BindView(R.id.siteVersionButton)
Spinner siteVersionField; Button siteVersionButton;
@InjectView(R.id.sitePasswordField) @BindView(R.id.sitePasswordField)
Button sitePasswordField; Button sitePasswordField;
@InjectView(R.id.sitePasswordTip) @BindView(R.id.sitePasswordTip)
TextView sitePasswordTip; TextView sitePasswordTip;
@InjectView(R.id.rememberFullNameField) @BindView(R.id.rememberFullNameField)
CheckBox rememberFullNameField; CheckBox rememberFullNameField;
@InjectView(R.id.rememberPasswordField) @BindView(R.id.rememberPasswordField)
CheckBox forgetPasswordField; CheckBox forgetPasswordField;
@InjectView(R.id.maskPasswordField) @BindView(R.id.maskPasswordField)
CheckBox maskPasswordField; CheckBox maskPasswordField;
private int hc_userName; private int id_userName;
private int hc_masterPassword; private int id_masterPassword;
private int id_version;
private String sitePassword; private String sitePassword;
public static void start(Context context) { public static void start(Context context) {
@@ -99,14 +92,60 @@ public class EmergencyActivity extends Activity {
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE ); getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
setContentView( R.layout.activity_emergency ); setContentView( R.layout.activity_emergency );
ButterKnife.inject( this ); ButterKnife.bind( this );
fullNameField.setOnFocusChangeListener( updateMasterKey ); fullNameField.setOnFocusChangeListener( new ValueChangedListener() {
masterPasswordField.setOnFocusChangeListener( updateMasterKey ); @Override
siteNameField.addTextChangedListener( updateSitePassword ); void update() {
siteTypeField.setOnItemSelectedListener( updateSitePassword ); updateMasterKey();
counterField.addTextChangedListener( updateSitePassword ); }
siteVersionField.setOnItemSelectedListener( updateMasterKey ); } );
masterPasswordField.setOnFocusChangeListener( new ValueChangedListener() {
@Override
void update() {
updateMasterKey();
}
} );
siteNameField.addTextChangedListener( new ValueChangedListener() {
@Override
void update() {
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
updateSitePassword();
}
} );
siteTypeButton.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() );
updateSitePassword();
}
} );
siteCounterButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(final View v) {
UnsignedInteger counter =
UnsignedInteger.valueOf( siteCounterButton.getText().toString() ).plus( UnsignedInteger.ONE );
siteCounterButton.setText( MessageFormat.format( "{0}", counter ) );
updateSitePassword();
}
} );
siteVersionButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(final View v) {
@SuppressWarnings("SuspiciousMethodCalls")
MasterKey.Version siteVersion =
allVersions.get( (allVersions.indexOf( siteVersionButton.getTag() ) + 1) % allVersions.size() );
preferences.setDefaultVersion( siteVersion );
siteVersionButton.setTag( siteVersion );
siteVersionButton.setText( siteVersion.name() );
updateMasterKey();
}
} );
sitePasswordField.addTextChangedListener( new ValueChangedListener() { sitePasswordField.addTextChangedListener( new ValueChangedListener() {
@Override @Override
void update() { void update() {
@@ -127,32 +166,26 @@ public class EmergencyActivity extends Activity {
sitePasswordField.setTypeface( Res.sourceCodePro_Black ); sitePasswordField.setTypeface( Res.sourceCodePro_Black );
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG ); sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "rememberFullName", isChecked ).apply(); preferences.setRememberFullName( isChecked );
if (isChecked) if (isChecked)
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullNameField.getText().toString() ).apply(); preferences.setFullName( fullNameField.getText().toString() );
else else
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", "" ).apply(); preferences.setFullName( null );
} }
} ); } );
forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { forgetPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "forgetPassword", isChecked ).apply(); preferences.setForgetPassword( isChecked );
} }
} ); } );
maskPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() { maskPasswordField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
getPreferences( MODE_PRIVATE ).edit().putBoolean( "maskPassword", isChecked ).apply(); preferences.setMaskPassword( isChecked );
sitePasswordField.setTransformationMethod( isChecked? new PasswordTransformationMethod(): null ); sitePasswordField.setTransformationMethod( isChecked? new PasswordTransformationMethod(): null );
} }
} ); } );
@@ -162,13 +195,24 @@ public class EmergencyActivity extends Activity {
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) ); MasterKey.setAllowNativeByDefault( preferences.isAllowNativeKDF() );
rememberFullNameField.setChecked( isRememberFullNameEnabled() );
forgetPasswordField.setChecked( isForgetPasswordEnabled() );
maskPasswordField.setChecked( isMaskPasswordEnabled() );
sitePasswordField.setTransformationMethod( isMaskPasswordEnabled()? new PasswordTransformationMethod(): null );
if (TextUtils.isEmpty( masterPasswordField.getText() )) 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();
siteVersionButton.setTag( defaultVersion );
siteVersionButton.setText( defaultVersion.name() );
siteCounterButton.setText( MessageFormat.format( "{0}", 1 ) );
if (TextUtils.isEmpty( fullNameField.getText() ))
fullNameField.requestFocus();
else if (TextUtils.isEmpty( masterPasswordField.getText() ))
masterPasswordField.requestFocus(); masterPasswordField.requestFocus();
else else
siteNameField.requestFocus(); siteNameField.requestFocus();
@@ -176,9 +220,9 @@ public class EmergencyActivity extends Activity {
@Override @Override
protected void onPause() { protected void onPause() {
if (isForgetPasswordEnabled()) { if (preferences.isForgetPassword()) {
synchronized (this) { synchronized (this) {
hc_userName = hc_masterPassword = 0; id_userName = id_masterPassword = 0;
if (masterKeyFuture != null) { if (masterKeyFuture != null) {
masterKeyFuture.cancel( true ); masterKeyFuture.cancel( true );
masterKeyFuture = null; masterKeyFuture = null;
@@ -195,35 +239,20 @@ public class EmergencyActivity extends Activity {
super.onPause(); super.onPause();
} }
private boolean isRememberFullNameEnabled() {
return getPreferences( MODE_PRIVATE ).getBoolean( "rememberFullName", false );
}
private boolean isForgetPasswordEnabled() {
return getPreferences( MODE_PRIVATE ).getBoolean( "forgetPassword", false );
}
private boolean isMaskPasswordEnabled() {
return getPreferences( MODE_PRIVATE ).getBoolean( "maskPassword", false );
}
private synchronized void updateMasterKey() { private synchronized void updateMasterKey() {
final String fullName = fullNameField.getText().toString(); final String fullName = fullNameField.getText().toString();
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray(); final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
final MasterKey.Version version = (MasterKey.Version) siteVersionField.getSelectedItem(); final MasterKey.Version version = (MasterKey.Version) siteVersionButton.getTag();
try { if (fullName.hashCode() == id_userName && Arrays.hashCode( masterPassword ) == id_masterPassword &&
if (fullName.hashCode() == hc_userName && Arrays.hashCode( masterPassword ) == hc_masterPassword && version.ordinal() == id_version && masterKeyFuture != null && !masterKeyFuture.isCancelled())
masterKeyFuture != null && masterKeyFuture.get().getAlgorithmVersion() == version)
return;
}
catch (InterruptedException | ExecutionException e) {
return; return;
}
hc_userName = fullName.hashCode();
hc_masterPassword = Arrays.hashCode( masterPassword );
if (isRememberFullNameEnabled()) id_userName = fullName.hashCode();
getPreferences( MODE_PRIVATE ).edit().putString( "fullName", fullName ).apply(); id_masterPassword = Arrays.hashCode( masterPassword );
id_version = version.ordinal();
if (preferences.isRememberFullName())
preferences.setFullName( fullName );
if (masterKeyFuture != null) if (masterKeyFuture != null)
masterKeyFuture.cancel( true ); masterKeyFuture.cancel( true );
@@ -243,7 +272,7 @@ public class EmergencyActivity extends Activity {
try { try {
return MasterKey.create( version, fullName, masterPassword ); return MasterKey.create( version, fullName, masterPassword );
} }
catch (RuntimeException e) { catch (Exception e) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE ); progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating master key." ); logger.err( e, "While generating master key." );
@@ -265,8 +294,8 @@ public class EmergencyActivity extends Activity {
private void updateSitePassword() { private void updateSitePassword() {
final String siteName = siteNameField.getText().toString(); final String siteName = siteNameField.getText().toString();
final MPSiteType type = (MPSiteType) siteTypeField.getSelectedItem(); final MPSiteType type = (MPSiteType) siteTypeButton.getTag();
final UnsignedInteger counter = UnsignedInteger.valueOf( ifNotNullElse( counterField.getText(), "1" ).toString() ); final UnsignedInteger counter = UnsignedInteger.valueOf( siteCounterButton.getText().toString() );
if (masterKeyFuture == null || siteName.isEmpty() || type == null) { if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
sitePasswordField.setText( "" ); sitePasswordField.setText( "" );
@@ -313,6 +342,14 @@ public class EmergencyActivity extends Activity {
} ); } );
} }
public void integrityTests(View view) {
if (masterKeyFuture != null) {
masterKeyFuture.cancel( true );
masterKeyFuture = null;
}
TestActivity.startNoSkip( this );
}
public void copySitePassword(View view) { public void copySitePassword(View view) {
final String currentSitePassword = this.sitePassword; final String currentSitePassword = this.sitePassword;
if (TextUtils.isEmpty( currentSitePassword )) if (TextUtils.isEmpty( currentSitePassword ))

View File

@@ -0,0 +1,148 @@
package com.lyndir.masterpassword;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2016-02-20
*/
public 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 Context context;
@Nullable
private SharedPreferences prefs;
public static synchronized Preferences get(final Context context) {
if (instance == null)
instance = new Preferences( context );
return instance;
}
private Preferences(Context context) {
this.context = context;
}
@Nonnull
private SharedPreferences prefs() {
if (prefs == null)
prefs = (context = context.getApplicationContext()).getSharedPreferences( getClass().getCanonicalName(), Context.MODE_PRIVATE );
return prefs;
}
public boolean setNativeKDFEnabled(boolean enabled) {
if (isAllowNativeKDF() == enabled)
return false;
prefs().edit().putBoolean( PREF_NATIVE_KDF, enabled ).apply();
return true;
}
public boolean isAllowNativeKDF() {
return prefs().getBoolean( PREF_NATIVE_KDF, MasterKey.isAllowNativeByDefault() );
}
public boolean setTestsPassed(final Set<String> value) {
if (Sets.symmetricDifference( getTestsPassed(), value ).isEmpty())
return false;
prefs().edit().putStringSet( PREF_TESTS_PASSED, value ).apply();
return true;
}
public Set<String> getTestsPassed() {
return prefs().getStringSet( PREF_TESTS_PASSED, ImmutableSet.<String>of() );
}
public boolean setRememberFullName(boolean enabled) {
if (isRememberFullName() == enabled)
return false;
prefs().edit().putBoolean( PREF_REMEMBER_FULL_NAME, enabled ).apply();
return true;
}
public boolean isRememberFullName() {
return prefs().getBoolean( PREF_REMEMBER_FULL_NAME, false );
}
public boolean setForgetPassword(boolean enabled) {
if (isForgetPassword() == enabled)
return false;
prefs().edit().putBoolean( PREF_FORGET_PASSWORD, enabled ).apply();
return true;
}
public boolean isForgetPassword() {
return prefs().getBoolean( PREF_FORGET_PASSWORD, false );
}
public boolean setMaskPassword(boolean enabled) {
if (isMaskPassword() == enabled)
return false;
prefs().edit().putBoolean( PREF_MASK_PASSWORD, enabled ).apply();
return true;
}
public boolean isMaskPassword() {
return prefs().getBoolean( PREF_MASK_PASSWORD, false );
}
public boolean setFullName(@Nullable String value) {
if (getFullName().equals( value ))
return false;
prefs().edit().putString( PREF_FULL_NAME, value ).apply();
return true;
}
@Nonnull
public String getFullName() {
return prefs().getString( PREF_FULL_NAME, "" );
}
public boolean setDefaultSiteType(@Nonnull MPSiteType value) {
if (getDefaultSiteType().equals( value ))
return false;
prefs().edit().putInt( PREF_SITE_TYPE, value.ordinal() ).apply();
return true;
}
@Nonnull
public MPSiteType getDefaultSiteType() {
return MPSiteType.values()[prefs().getInt( PREF_SITE_TYPE, MPSiteType.GeneratedLong.ordinal() )];
}
public boolean setDefaultVersion(@Nonnull MasterKey.Version value) {
if (getDefaultVersion().equals( value ))
return false;
prefs().edit().putInt( PREF_ALGORITHM_VERSION, value.ordinal() ).apply();
return true;
}
@Nonnull
public MasterKey.Version getDefaultVersion() {
return MasterKey.Version.values()[prefs().getInt( PREF_ALGORITHM_VERSION, MasterKey.Version.CURRENT.ordinal() )];
}
}

View File

@@ -3,17 +3,17 @@ package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import android.app.*; import android.app.*;
import android.content.Context;
import android.content.Intent;
import android.os.*; import android.os.*;
import android.view.View; import android.view.View;
import android.view.WindowManager;
import android.widget.*; import android.widget.*;
import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView;
import com.google.common.base.*; import com.google.common.base.*;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.google.common.util.concurrent.*; import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Set;
import java.util.concurrent.*; import java.util.concurrent.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@@ -23,34 +23,49 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( TestActivity.class ); 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 backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() ); private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
@InjectView(R.id.progressView) @BindView(R.id.progressView)
ProgressBar progressView; ProgressBar progressView;
@InjectView(R.id.statusView) @BindView(R.id.statusView)
TextView statusView; TextView statusView;
@InjectView(R.id.logView) @BindView(R.id.logView)
TextView logView; TextView logView;
@InjectView(R.id.actionButton) @BindView(R.id.actionButton)
Button actionButton; Button actionButton;
@BindView(R.id.nativeKDFField)
CheckBox nativeKDFField;
private MPTestSuite testSuite; private MPTestSuite testSuite;
private ListenableFuture<Boolean> testFuture; private ListenableFuture<Boolean> testFuture;
private Runnable action; private Runnable action;
private ImmutableSet<String> testNames; private ImmutableSet<String> testNames;
public static void startNoSkip(Context context) {
context.startActivity( new Intent( context, TestActivity.class ) );
}
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate( savedInstanceState ); super.onCreate( savedInstanceState );
Res.init( getResources() ); Res.init( getResources() );
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
setContentView( R.layout.activity_test ); setContentView( R.layout.activity_test );
ButterKnife.inject( this ); 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 { try {
setStatus( 0, 0, null ); setStatus( 0, 0, null );
@@ -76,63 +91,54 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
} }
} }
@Override
protected void onStart() {
super.onStart();
final Set<String> integrityTestsPassed = getPreferences( MODE_PRIVATE ).getStringSet( "integrityTestsPassed",
ImmutableSet.<String>of() );
if (!FluentIterable.from( testNames ).anyMatch( new Predicate<String>() {
@Override
public boolean apply(@Nullable final String testName) {
return !integrityTestsPassed.contains( testName );
}
} )) {
// None of the tests we need to perform were missing from the tests that have already been passed on this device.
finish();
EmergencyActivity.start( TestActivity.this );
}
}
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
if (testFuture == null) { nativeKDFField.setChecked( 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() {
getPreferences( MODE_PRIVATE ).edit().putStringSet( "integrityTestsPassed", testNames ).apply();
finish();
EmergencyActivity.start( TestActivity.this );
}
} );
else
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
@Override
public void run() {
finish();
}
} );
}
@Override if (testFuture == null)
public void onFailure(final Throwable t) { startTestSuite();
logger.err( t, "While running test suite" ); }
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
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 @Override
public void run() { public void run() {
preferences.setTestsPassed( testNames );
finish(); finish();
} }
} ); } );
} else
}, mainExecutor ); 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(View v) { public void onAction(View v) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

View File

@@ -0,0 +1,273 @@
<?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"
android:background="@drawable/background">
<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:layout_marginBottom="8dp"
android:importantForAccessibility="no"
android:src="@drawable/img_identity" />
<EditText
android:id="@+id/fullNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/masterPasswordField"
android:inputType="text|textCapWords|textPersonName"
android:hint="@string/fullName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<CheckBox
android:id="@+id/rememberFullNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/rememberPasswordField"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/remember" />
<EditText
android:id="@id/masterPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteNameField"
android:inputType="text|textPassword"
android:hint="@string/masterPassword_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<CheckBox
android:id="@id/rememberPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/forgetOnClose" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="8dp"
android:importantForAccessibility="no"
android:src="@drawable/img_key" />
<EditText
android:id="@id/siteNameField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/sitePasswordField"
android:inputType="text|textNoSuggestions|textUri"
android:hint="@string/siteName_hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progressView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible"
android:indeterminate="true"
tools:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<Button
android:id="@id/sitePasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nextFocusForward="@+id/siteTypeButton"
android:gravity="center"
android:background="@android:color/transparent"
android:textColor="#FFFFFF"
android:textSize="28sp"
tools:text="LuxdZozvDuma4["
android:onClick="copySitePassword" />
<TextView
android:id="@+id/sitePasswordTip"
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/sitePassword_hint" />
</LinearLayout>
</FrameLayout>
<CheckBox
android:id="@+id/maskPasswordField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/maskPassword" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="8dp"
android:importantForAccessibility="no"
android:src="@drawable/divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:buttonBarStyle"
android:orientation="horizontal"
android:gravity="center">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@id/siteTypeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
style="?android:buttonBarButtonStyle"
android:nextFocusForward="@+id/counterField"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:drawableStart="@drawable/icon_key"
android:drawablePadding="8dp"
android:background="@android:color/transparent"
tools:text="Long" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@id/siteTypeButton"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteType_hint" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@id/counterField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
style="?android:buttonBarButtonStyle"
android:nextFocusForward="@+id/siteVersionButton"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:drawableStart="@drawable/icon_plus"
android:drawablePadding="8dp"
android:background="@android:color/transparent"
tools:text="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@id/siteVersionButton"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteCounter_hint" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@id/siteVersionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
style="?android:buttonBarButtonStyle"
android:nextFocusForward="@+id/rememberFullNameField"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:drawableStart="@drawable/icon_gears"
android:drawablePadding="8dp"
android:background="@android:color/transparent"
tools:text="3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@id/siteVersionButton"
android:gravity="center"
android:background="@android:color/transparent"
android:textSize="12sp"
android:textColor="@android:color/tertiary_text_dark"
android:text="@string/siteVersion_hint" />
</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"
android:layout_weight="1" />
</LinearLayout>
</ScrollView>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true" android:fillViewport="true"
@@ -17,22 +18,31 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/img_stats" />
<ProgressBar <ProgressBar
android:id="@+id/progressView" android:id="@+id/progressView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_margin="8dp" android:layout_margin="8dp"
style="@android:style/Widget.ProgressBar.Horizontal" /> tools:max="100"
tools:progress="80"
style="?android:progressBarStyleHorizontal" />
<TextView <TextView
android:id="@+id/statusView" android:id="@+id/statusView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:labelFor="@id/sitePasswordField"
android:gravity="center" android:gravity="center"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:textSize="14sp" android:textSize="12sp"
android:textColor="@android:color/secondary_text_dark" android:textColor="@android:color/tertiary_text_dark"
android:text="@string/tests_testing" /> android:text="@string/tests_testing" />
<TextView <TextView
@@ -53,8 +63,15 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:enabled="false" android:enabled="false"
android:text="@string/tests_btn_testing" android:text="@string/tests_btn_testing"
android:onClick="onAction"/> 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> </LinearLayout>
</ScrollView> </ScrollView>

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