2
0

Compare commits

...

149 Commits

Author SHA1 Message Date
Maarten Billemont
1f173d7586 Support for dark mode icon. 2014-10-30 21:05:13 -04:00
Maarten Billemont
34be1eac70 Mac LoginHelper distribution configuration. 2014-10-30 00:39:56 -04:00
Maarten Billemont
e1a9c8194c Bump xib. 2014-10-30 00:26:42 -04:00
Maarten Billemont
e18dee2242 Also try upgrading to V2 if migrationlevel is unset but a store is available. 2014-10-30 00:18:01 -04:00
Maarten Billemont
a38829c1e2 Match the define name to its value. 2014-10-29 21:55:18 -04:00
Maarten Billemont
8615f6af5d Fuzzy site name search and highlight fuzzy results. 2014-10-29 21:24:35 -04:00
Maarten Billemont
d642cb1aee Use exposure adjust for darkening without destroying dark backgrounds. 2014-10-28 17:20:38 -04:00
Maarten Billemont
2be2a19fa0 Build fixes and layout improvements for Mac on Yosemite. 2014-10-28 00:53:16 -04:00
Maarten Billemont
0d5b51ed8d Put Mac icon into AppIconSet 2014-10-26 13:26:41 -04:00
Maarten Billemont
c781bcf10a Move Info.plist update script into Scripts to share it between Mac and iOS. 2014-10-26 12:01:30 -04:00
Maarten Billemont
1c45a0df4a Don't crash if attempting to import with an invalid password type. 2014-10-26 10:54:28 -04:00
Maarten Billemont
6b16e4d606 Remove USM from Mac app. 2014-10-26 10:41:15 -04:00
Maarten Billemont
e837752777 Explicitly synchronize configuration updates and warn if it fails. 2014-10-24 00:35:05 -04:00
Maarten Billemont
84c23fa7f6 debug genassets. 2014-10-24 00:00:51 -04:00
Maarten Billemont
2b0cc8ec7b Reference mpw-js from the main page + interlace the images. 2014-10-23 22:17:17 -04:00
Maarten Billemont
6f77e1922b Remove adwords. 2014-10-23 21:57:03 -04:00
Maarten Billemont
653f90c59c Force a refresh of the referenced stylesheet and js. 2014-10-23 21:35:17 -04:00
Maarten Billemont
3076cc3de4 A few disclaimers on mpw-js. 2014-10-23 21:33:19 -04:00
Maarten Billemont
15c53c06c6 Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-10-23 20:10:44 -04:00
Maarten Billemont
b3a886a6db mpw-js: A javascript implementation of Master Password. 2014-10-23 20:10:25 -04:00
Maarten Billemont
41ae6a5de5 Remove pushqueue/popqueue, not compatible with bash3 2014-10-23 17:29:14 -04:00
Maarten Billemont
92bd2cd016 Explicitly use sha256 digests. 2014-10-23 12:03:19 -04:00
Maarten Billemont
4b975b5b04 Fix pkg_sha of crypt_blowfish; verified by checking the signature of the package against crypt_blowfish-1.3.tar.gz.sign 2014-10-23 00:26:07 -04:00
Maarten Billemont
56f04a8924 xctool gets project targets confused; specify iOS project explicitly. 2014-10-23 00:14:45 -04:00
Maarten Billemont
3c2b5de4b8 Fix crash when clearing the pasteboard. 2014-10-22 23:32:25 -04:00
Maarten Billemont
33e1492b44 clean up todo. 2014-10-22 23:21:21 -04:00
Maarten Billemont
9384e27247 submodules needs to be explicitly true? + fix version numbering. 2014-10-22 23:10:07 -04:00
Maarten Billemont
a95561dd50 Re-enable submodule support in Travis; Pearl is no longer excessive. 2014-10-22 23:05:04 -04:00
Maarten Billemont
9d809f34d9 Remove MPCheckpoints, no longer useful. Perform pasteboard importing on a background thread. 2014-10-22 23:00:20 -04:00
Maarten Billemont
fc21bd959f Add a tip on how to solve a build error on the Raspberry Pi. 2014-10-22 22:29:05 -04:00
Maarten Billemont
2de17384ff More portable digest() 2014-10-22 22:02:17 -04:00
Maarten Billemont
85dab50996 More robust against exceptions and a few other fixes. 2014-10-22 21:54:48 -04:00
Maarten Billemont
bb97e8f3e8 Fix Core Data store migration code. 2014-10-22 20:26:22 -04:00
Maarten Billemont
f3d0368a75 Don't sync .git repos. 2014-10-22 16:03:40 -04:00
Maarten Billemont
283d555d3b Missing site resources. 2014-10-20 19:59:02 -04:00
Maarten Billemont
d909e64670 Add disclaimer. 2014-10-20 14:31:21 -04:00
Maarten Billemont
10f100186c Remove pushqueue for bash 3 compatibility. 2014-10-20 08:51:58 -04:00
Maarten Billemont
2af2351ebf Make usage text a bit more obvious. 2014-10-19 00:58:13 -04:00
Maarten Billemont
49b3fe7913 Add support for login names and security answers to C app. 2014-10-19 00:55:26 -04:00
Maarten Billemont
9d926be8ae Support for pre-downloaded dependency packages and digest verification.
[UPDATED]   Allow overriding of targets to build at command-line via target=X ./build
[ADDED]     Support pre-downloaded packages for integration with package managers.
[ADDED]     Support for package digest verification.
[UPDATED]   Skip fetching on in a method-specific way, more reliable.
2014-10-18 20:56:28 -04:00
Maarten Billemont
c3474de2ff FreeBSD build fixes. 2014-10-18 18:22:29 -04:00
Maarten Billemont
68b9b4e09a Fix git-svn/git checkouts of dependencies. 2014-10-18 17:13:01 -04:00
Maarten Billemont
b810c1032b Include signed version in release package. 2014-10-18 15:56:31 -04:00
Maarten Billemont
a4ab3c7bc9 Script to distribute C packages. 2014-10-18 15:42:49 -04:00
Maarten Billemont
039547b735 Check the presence of tools needed to build the C targets. 2014-10-18 15:38:51 -04:00
Maarten Billemont
6f741f6f2f Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-10-18 15:30:58 -04:00
Maarten Billemont
38d4b761b7 Remove binaries. I don't intend to maintain binary distributions at this point. 2014-10-18 14:36:05 -04:00
Maarten Billemont
18f8ebb9dc Fix check for whether a dependency was built + improved mpw-bench output. 2014-10-17 17:10:43 -04:00
Maarten Billemont
794d064a99 Merge pull request #91 from linwiz/master
Added information to the output of mpw-bench
2014-10-17 09:19:05 -04:00
linwiz
090b274363 Added information to the output of mpw-bench 2014-10-17 08:52:15 -04:00
Maarten Billemont
25ba87f119 Make mpw-bench optional. 2014-10-15 22:18:16 -04:00
Maarten Billemont
f0b659a0c7 Add bcrypt dependency and ability to compile arbitrary dependencies in C build script. 2014-10-15 22:17:49 -04:00
Maarten Billemont
7736788920 Disable debug verbosity by default. 2014-10-15 16:27:33 -04:00
Maarten Billemont
e3be98f3ad Added mpw-bench as an extra target. 2014-10-15 16:26:09 -04:00
Maarten Billemont
d9b1b44de0 Replace editline and readline with getpass. 2014-10-15 16:03:46 -04:00
Maarten Billemont
c3c2de5d14 Ensure master password isn't lost after ending editline context. 2014-10-15 15:37:29 -04:00
Maarten Billemont
6aa50bac04 Ensure we use the correct C language standard. 2014-10-15 15:32:10 -04:00
Maarten Billemont
5268039c3d A bunch of cross-platform fixes for mpw.c + make config file optional and read master password from input instead. 2014-10-15 14:00:44 -04:00
Maarten Billemont
0d66d4660e Add code to the build script for automatically fetching and building libscrypt. 2014-10-15 08:44:41 -04:00
Maarten Billemont
e981df3c8b Fixed type of level 3 attacker.
[FIXED]     Type of level 3 attacker was string instead of integer.
2014-10-13 23:39:07 -04:00
Maarten Billemont
543ebd4bac Update provisioning profiles. 2014-10-13 22:08:36 -04:00
Maarten Billemont
e6d21e1c1d Add new question cells and fix sizing issue with store cells.
[FIXED]     Cell sizing of autosized the store cells.
[IMPROVED]  Add new question rows as soon as the last question row is used.
2014-10-13 21:56:46 -04:00
Maarten Billemont
a3ebcf0608 Fix a few spelling mistakes. 2014-10-12 12:03:57 -04:00
Maarten Billemont
556d1d3d58 Make the site more mobile-friendly. 2014-10-07 19:55:36 -04:00
Maarten Billemont
979d3a2a5a Add fallback in case the video doesn't work. 2014-10-06 23:30:41 -04:00
Maarten Billemont
480e7f192a Added a new introduction video to the Master Password website. 2014-10-06 22:03:18 -04:00
Maarten Billemont
a18793b161 Update of the site to simplify understanding Master Password and how to use it. 2014-10-05 01:22:28 -04:00
Maarten Billemont
9b24efa65c Fix iOS 8 bug causing site search field to be auto-capitalized. 2014-10-01 07:35:57 -04:00
Maarten Billemont
3e217d5a69 Project configuration update. 2014-09-30 08:33:46 -04:00
Maarten Billemont
c8ca1c80e6 Remove generated resources from repository. 2014-09-30 08:25:47 -04:00
Maarten Billemont
88c18db010 Optimize icons. 2014-09-30 08:24:29 -04:00
Maarten Billemont
f909cdbae4 More icon fixes + don't delete store rows... 2014-09-30 08:20:35 -04:00
Maarten Billemont
8b8d5d325e Fix some warnings. 2014-09-30 00:09:40 -04:00
Maarten Billemont
c7670f47db Record the amount of fuel consumed and show status + icon update & genassets run script. 2014-09-30 00:01:33 -04:00
Maarten Billemont
f3f25f5890 Add question about hiding passwords to setup flow. 2014-09-28 22:57:38 -04:00
Maarten Billemont
3065433a37 Stop showing thanks tips after user opens thanks page. 2014-09-28 22:25:48 -04:00
Maarten Billemont
41b3964363 Lots of UI improvements and tips + parental gate, guide update.
[IMPROVED]  Emergency VC can now scroll when keyboard is up.
[IMPROVED]  Language of the guide + new updated screenshots.
[FIXED]     Size of guide cells on different devices.
[IMPROVED]  Don't show messages claiming login name was updated when nothing changed.
[FIXED]     Weird back-toggle bug when toggling site settings.
[ADDED]     Lots of handy tips throughout.
[ADDED]     Notification of new store features.
[FIXED]     Weird sizing issue & animation with store cells.
[ADDED]     Loading spinner while loading store products.
[ADDED]     Thanks link to store footer.
[FIXED]     Bought products should not respond to click, non-bought ones should.
[FIXED]     Fuel elapsed time counter was backward.
[ADDED]     Parental gate when deleting or resetting users.
[UPDATED]   App Icon background texture.
2014-09-28 22:15:55 -04:00
Maarten Billemont
5e8810c535 Dismiss popdown on sign out, fuel check date not recorded, avatar improvements. 2014-09-28 10:05:36 -04:00
Maarten Billemont
8c3dfc8510 Update of icon and launch image + background for iPhone 6 / 6+ 2014-09-28 01:53:50 -04:00
Maarten Billemont
b4b9ee3cb9 Import sites from pasteboard. 2014-09-27 20:29:58 -04:00
Maarten Billemont
da4bad7977 Fix a few build warnings, two-way site question relationship. 2014-09-27 16:30:17 -04:00
Maarten Billemont
984434cca4 Remove header hack to inset password cells, use collection layout instead. 2014-09-27 14:53:30 -04:00
Maarten Billemont
064122f36d Build fixes. 2014-09-27 12:52:17 -04:00
Maarten Billemont
5db083bf7c Improve notification registration and cleanup + fix removal of site questions. 2014-09-27 01:27:05 -04:00
Maarten Billemont
44f91e0618 Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-09-26 00:32:19 -04:00
Maarten Billemont
6050b5d6fd Development fuel, store improvements and navigation fixes. 2014-09-26 00:32:07 -04:00
Maarten Billemont
8e3e77c2c1 Remove UbiquityStoreManager 2014-09-24 16:04:35 -04:00
Maarten Billemont
a2e71aa94d Merge branch 'master' of github.com:Lyndir/MasterPassword
Conflicts:
	MasterPassword/ObjC/iOS/MPPasswordsViewController.m
2014-09-24 16:02:29 -04:00
Maarten Billemont
a5bc2eb584 Store product thumbnails. 2014-09-24 08:00:10 -04:00
Maarten Billemont
9bb613a3b6 MPAlgorithm V2: handle multi-byte UTF-8 correctly by counting bytes, not characters. 2014-09-24 07:58:23 -04:00
Maarten Billemont
466863f8fd Improved overlay navigation, store refactoring and automatic sizing of store cells. 2014-09-24 01:07:02 -04:00
Maarten Billemont
fe5828c724 Fix removal of questions. Blast you Core Data. 2014-09-22 22:32:31 -04:00
Maarten Billemont
b3ec7a848d Make answers VC a pop-over. 2014-09-22 08:48:51 -04:00
Maarten Billemont
17734652b4 Completed answers generation. 2014-09-21 23:48:49 -04:00
Maarten Billemont
9e742fa40f Use fullDescription for all error logging. 2014-09-21 23:28:50 -04:00
Maarten Billemont
d03b1746e0 Handle failure to load store. 2014-09-21 23:11:05 -04:00
Maarten Billemont
58156be793 Generating security question answers for sites. 2014-09-21 22:45:21 -04:00
Maarten Billemont
d5a5cd7de4 Fix a few issues after element->site rename. 2014-09-21 14:09:43 -04:00
Maarten Billemont
2100662fb3 Add a model version for MPSiteQuestionEntity and element->site renames. 2014-09-21 13:56:37 -04:00
Maarten Billemont
248627aa92 Project cleanup. 2014-09-21 13:45:33 -04:00
Maarten Billemont
449ccaa3d4 Storyboard fixups. 2014-09-21 13:39:47 -04:00
Maarten Billemont
0a7465282b Prepare generate answers product. 2014-09-21 12:54:48 -04:00
Maarten Billemont
5b85ba3a4b Element -> Site 2014-09-21 11:47:53 -04:00
Maarten Billemont
b3a0b6a7c0 Element -> Site, site security question answers 2014-09-21 10:49:57 -04:00
Maarten Billemont
4396ce436e Element -> Site WIP 2014-09-21 10:39:09 -04:00
Maarten Billemont
68e6106ee7 Extract In-App logic into app delegate category & improvements to import file handling and advanced export + store fixes. 2014-09-21 10:29:18 -04:00
Maarten Billemont
4c12f368f5 Ability to generate pass phrases as well as names. 2014-09-21 01:57:45 -04:00
Maarten Billemont
0156f8c3c8 More store work.
[FIXED]     A strange issue with reloading password cells.
[FIXED]     Product identifiers and showing the first product in the store.
[ADDED]     Restoring purchases made from other devices.
[REMOVED]   iCloud entitlements.
2014-09-17 20:59:03 -04:00
Maarten Billemont
2e5cbac761 Added in-app purchase store and made generated logins a product. 2014-09-17 02:00:33 -04:00
Maarten Billemont
a043b7c049 Fixes to new store loading if not migrated. 2014-09-16 07:53:31 -04:00
Maarten Billemont
06c62f70ed Fixes to V0 algorithm debug log output. 2014-09-16 00:45:39 -04:00
Maarten Billemont
c97546a232 Improvements to login name editing, saving/generating. 2014-09-16 00:34:22 -04:00
Maarten Billemont
88fdc89f27 Removed iCloud + added generated login names.
[REMOVED]   UbiquityStoreManager and iCloud support.  Now using simplified local Core Data store logic.
[ADDED]     Generating site login names.
[IMPROVED]  Some refactoring and interface improvements for optionally generated user names.
2014-09-15 08:47:36 -04:00
Maarten Billemont
9109a59410 Fixes for better landscape sizing of avatar cells. 2014-09-12 17:13:33 -04:00
Maarten Billemont
61bed8b29c Fixes for positioning of avatars in different states. 2014-09-12 00:41:17 -04:00
Maarten Billemont
72b1d36626 Fix sizing issues with avatars on different size devices.
[FIXED]     Avatar cells badly sized on some size devices.
2014-09-11 20:31:23 -04:00
Maarten Billemont
6e14554f95 Weird layout problems now when building from Xcode 6.. 2014-09-11 00:26:01 -04:00
Maarten Billemont
fecbd2ea1c Some storyboard maintenance for Xcode 6. 2014-09-10 22:40:43 -04:00
Maarten Billemont
1c5f5675a5 Project update. 2014-09-10 22:18:26 -04:00
Maarten Billemont
76b717e06d Fix build for iOS simulator. 2014-09-10 22:07:51 -04:00
Maarten Billemont
eb48f749e2 Remove Love Lyndir from privacy statement, no longer used. 2014-09-09 08:35:32 -04:00
Maarten Billemont
398f7bdb66 login name UI improvements and saved key login fix.
[IMPROVED]  -saveContent now returns YES if successful and NO if nothing changed.
[FIXED]     Fix for unsetting the login key when key is saved due to a notification race.
[IMPROVED]  UI improvements for login name.
[IMPROVED]  Remove system fonts all-over and replace with Exo2.
[IMPROVED]  Various UI improvements and fixes throughout.
2014-09-08 00:15:18 -04:00
Maarten Billemont
d40ccee0fe Update of icons and site updates with new support and mac app store link. 2014-09-04 00:30:51 -04:00
Maarten Billemont
a481626f80 Small tweaks to avoid a rare crash during initialization of cells. 2014-09-03 19:29:46 -04:00
Maarten Billemont
24c48a78f8 Minor Pearl bump. 2014-09-02 23:50:32 -04:00
Maarten Billemont
edda3cf12a Fix the border radius of the iOS icon. 2014-09-02 23:48:04 -04:00
Maarten Billemont
6c2cd01015 Prettier password cells. 2014-09-02 23:19:34 -04:00
Maarten Billemont
c9988d8cc2 Fix for showing setup VC on landscape iPad + old -> new section objects crash. 2014-09-02 21:40:53 -04:00
Maarten Billemont
bc88daf08d Don't use old section info from an old NSFetchedResultsSectionInfo object. 2014-09-02 14:51:04 -04:00
Maarten Billemont
a8bb434ded Add mp.update.check property to disable update checking. 2014-08-31 22:14:18 -04:00
Maarten Billemont
1e8a832cba Bump lyndir POM to 1.20 to fix some warnings and dependency issues. 2014-08-31 21:55:37 -04:00
Maarten Billemont
4f70e0f676 Master Password Java GUI update. 2014-08-30 20:11:10 -04:00
Maarten Billemont
9d7799c814 Improved Master Password algorithm API & GUI improvements.
[IMPROVED]  Read the master password using Console, not stdin.
[IMPROVED]  Clear the site password when the dialog closes.
[IMPROVED]  Make the site password selectable.
2014-08-30 20:08:20 -04:00
Maarten Billemont
2adb74c971 Make log level configurable with -Dlog.level, default to INFO. Thanks @pitpalme. 2014-08-30 15:54:52 -04:00
Maarten Billemont
cc80a66331 Update of images on homepage. 2014-08-29 21:07:49 -04:00
Maarten Billemont
cf8ecb2952 Site style tweaks and Android beta link. 2014-08-28 20:10:53 -04:00
Maarten Billemont
adcea94a37 Master Password update on the site for Android & Java GUI. 2014-08-28 09:53:08 -04:00
Maarten Billemont
3ebef16007 Sign android release build and fix check for Apple classes in GUI. 2014-08-28 09:50:10 -04:00
Maarten Billemont
3225985e1e Fix update check. 2014-08-28 00:07:24 -04:00
Maarten Billemont
76280ac71c Update check for Java GUI + Copy password on Android + Native scrypt for Android. 2014-08-27 23:05:24 -04:00
Maarten Billemont
f47ff67ba9 Add tip to copy password & close app + less console verbosity in Java GUI. 2014-08-27 22:08:53 -04:00
Maarten Billemont
65cef6d8ed First working Master Password for Android, yay! 2014-08-26 19:54:33 -04:00
Maarten Billemont
89145d6e13 Prepare for Android development.
[FIXED]     Naming of avatar images.
[FIXED]     Dependency, SDK & other Maven configuration.
[UPDATED]   Dependencies changed to stable versions.
2014-08-24 22:43:34 -04:00
Maarten Billemont
63b4c605e2 OS X -> Mac 2014-08-24 00:22:03 -04:00
Maarten Billemont
b3b7858c1d Round-rect Mac icon. 2014-08-24 00:13:01 -04:00
Maarten Billemont
eb4ea08a8b Update Media.xcassets. 2014-08-24 00:01:17 -04:00
Maarten Billemont
51d61b8bc0 Mac Icon update. 2014-08-23 23:36:18 -04:00
Maarten Billemont
bddbd199e2 Type warning fixes. 2014-08-23 23:33:10 -04:00
Maarten Billemont
b579dac180 Icon update. 2014-08-23 19:17:41 -04:00
480 changed files with 23692 additions and 6777 deletions

6
.gitignore vendored
View File

@@ -16,6 +16,9 @@
xcuserdata/
/DerivedData/
# Generated
MasterPassword/Resources/Media/Images.xcassets/
# Media
Press/Background.png
Press/Front-Page.png
@@ -29,7 +32,10 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
MasterPassword/Java/**/target
# C
MasterPassword/C/VERSION
MasterPassword/C/*.o
MasterPassword/C/mpw-*.tar.gz
MasterPassword/C/mpw
MasterPassword/C/mpw-bench
MasterPassword/C/lib/*/*
!MasterPassword/C/lib/*/.source

21
.gitmodules vendored
View File

@@ -4,9 +4,18 @@
[submodule "External/InAppSettingsKit"]
path = External/InAppSettingsKit
url = git://github.com/lhunath/InAppSettingsKit.git
[submodule "External/UbiquityStoreManager"]
path = External/UbiquityStoreManager
url = git://github.com/lhunath/UbiquityStoreManager.git
[submodule "External/RHStatusItemView"]
path = External/RHStatusItemView
url = git://github.com/lhunath/RHStatusItemView.git
[submodule "External/KCOrderedAccessorFix"]
path = External/KCOrderedAccessorFix
url = https://github.com/CFKevinRef/KCOrderedAccessorFix.git
[submodule "External/AttributedMarkdown"]
path = External/AttributedMarkdown
url = https://github.com/dreamwieber/AttributedMarkdown.git
[submodule "External/uicolor-utilities"]
path = External/uicolor-utilities
url = git://github.com/lhunath/uicolor-utilities.git
[submodule "External/jrswizzle"]
path = External/jrswizzle
url = git://github.com/jonmarimba/jrswizzle.git
[submodule "Site/2013-05/mpw-js/js/mpw-js"]
path = Site/2013-05/mpw-js/js/mpw-js
url = https://github.com/Lyndir/mpw-js.git

View File

@@ -1,7 +1,6 @@
language: objective-c
xcode_workspace: MasterPassword.xcworkspace
xcode_project: MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj
xcode_scheme: MasterPassword iOS (Development)
xcode_sdk: iphonesimulator
git:
submodules: false
before_install: ./Scripts/updateDependencies
submodules: true

1
External/AttributedMarkdown vendored Submodule

View File

@@ -0,0 +1 @@
Versions/Current/Modules

View File

@@ -38,6 +38,7 @@
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
/**
*
@@ -46,6 +47,8 @@ OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
@protocol CrashlyticsDelegate;

View File

@@ -0,0 +1,6 @@
framework module Crashlytics {
umbrella header "Crashlytics.h"
export *
module * { export * }
}

View File

@@ -15,13 +15,13 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.1.2</string>
<string>2.2.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>macosx</string>
</array>
<key>CFBundleVersion</key>
<string>9</string>
<string>39</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>MinimumOSVersion</key>

Binary file not shown.

2
External/Pearl vendored

View File

@@ -0,0 +1,6 @@
framework module Crashlytics {
umbrella header "Crashlytics.h"
export *
module * { export * }
}

View File

@@ -38,6 +38,7 @@
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
/**
*
@@ -46,6 +47,8 @@ OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
@protocol CrashlyticsDelegate;

View File

@@ -15,13 +15,13 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.2</string>
<string>2.2.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>36</string>
<string>40</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
External/jrswizzle vendored Submodule

Submodule External/jrswizzle added at 98d18aee73

1
External/uicolor-utilities vendored Submodule

View File

@@ -10,57 +10,85 @@
<string>MasterPassword</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</key>
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
<string>git://github.com/Lyndir/love-lyndir.client.git</string>
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
<string>git://github.com/lhunath/UbiquityStoreManager.git</string>
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
<string>ssh://github.com/Lyndir/Pearl.git</string>
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
<key>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</key>
<string>github.com:Lyndir/Lyndir.git</string>
<key>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</key>
<string>git://github.com/lhunath/uicolor-utilities.git</string>
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
<key>304AD0F97EA7B4893D91DFB8C3413D4E627B9472</key>
<string>https://github.com/CFKevinRef/KCOrderedAccessorFix.git</string>
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
<string>git://github.com/lhunath/RHStatusItemView.git</string>
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
<key>3ED8592497DB6A564366943C9AAD5A46341B5076</key>
<string>https://github.com/dreamwieber/AttributedMarkdown.git</string>
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
<string>ssh://github.com/Lyndir/Pearl.git</string>
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
<string>git://github.com/jonmarimba/jrswizzle.git</string>
<key>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</key>
<string>git://github.com/lhunath/UbiquityStoreManager.git</string>
<key>F788B28042EDBEF29EFE34687DA79A778C2CC260</key>
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>MasterPassword.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</key>
<string>../External/InAppSettingsKit</string>
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
<string>../External/LoveLyndir</string>
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
<string>../External/UbiquityStoreManager</string>
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
<string>..</string>
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
<string>../External/Pearl</string>
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
<key>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</key>
<string>../..</string>
<key>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</key>
<string>../External/Pearl/External/uicolor-utilities</string>
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
<key>304AD0F97EA7B4893D91DFB8C3413D4E627B9472</key>
<string>../External/KCOrderedAccessorFix</string>
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
<string>../External/RHStatusItemView</string>
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
<string>../External/InAppSettingsKit</string>
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
<key>3ED8592497DB6A564366943C9AAD5A46341B5076</key>
<string>../External/AttributedMarkdown</string>
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
<string>../External/Pearl</string>
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
<string>../External/Pearl/External/jrswizzle</string>
<key>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</key>
<string>../External/UbiquityStoreManager</string>
<key>F788B28042EDBEF29EFE34687DA79A778C2CC260</key>
<string>..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>110</integer>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
<string>F788B28042EDBEF29EFE34687DA79A778C2CC260</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</string>
<string>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</string>
<key>IDESourceControlWCCName</key>
<string></string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>3ED8592497DB6A564366943C9AAD5A46341B5076</string>
<key>IDESourceControlWCCName</key>
<string>AttributedMarkdown</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</string>
<key>IDESourceControlWCCName</key>
<string>InAppSettingsKit</string>
</dict>
@@ -68,10 +96,18 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>E4C8E206-229C-4DA8-A130-0C544DEC7E07</string>
<string>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</string>
<key>IDESourceControlWCCName</key>
<string>jrswizzle</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>304AD0F97EA7B4893D91DFB8C3413D4E627B9472</string>
<key>IDESourceControlWCCName</key>
<string>KCOrderedAccessorFix</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
@@ -84,7 +120,7 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
<string>F788B28042EDBEF29EFE34687DA79A778C2CC260</string>
<key>IDESourceControlWCCName</key>
<string>MasterPassword</string>
</dict>
@@ -92,7 +128,7 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</string>
<string>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</string>
<key>IDESourceControlWCCName</key>
<string>Pearl</string>
</dict>
@@ -100,7 +136,7 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</string>
<string>3E67FB08419C920516AAC3B00DAAF23073B8CF77</string>
<key>IDESourceControlWCCName</key>
<string>RHStatusItemView</string>
</dict>
@@ -108,7 +144,7 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>42C94803-87A2-403E-896C-D9AC3A807E1B</string>
<string>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</string>
<key>IDESourceControlWCCName</key>
<string>UbiquityStoreManager</string>
</dict>
@@ -116,7 +152,7 @@
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>AE3786C7-912B-4651-A73F-2E1DACBFB604</string>
<string>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</string>
<key>IDESourceControlWCCName</key>
<string>uicolor-utilities</string>
</dict>

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,264 @@
#!/usr/bin/env bash
# Run with -DDEBUG to enable trace-level output.
#
# TROUBLESHOOTING
# - To enable verbose algorithm/implementation debugging, use ./build -DDEBUG
# - If you see 'undefined reference to `clock_gettime'',
# try ./build -lrt instead.
# - If you see 'x86.S:202: Error: junk at end of line, first unrecognized character is `,'',
# try commenting the line in lib/bcrypt/x86.S.
#
# BUGS
# masterpassword@lyndir.com
#
# AUTHOR
# Maarten Billemont
#
cd "${BASH_SOURCE%/*}"
shopt -s extglob
set -e
[[ -e lib/scrypt/scryptenc.o ]] || { echo >&2 "Missing scrypt. First get and build the scrypt source in lib/scrypt from <$(<lib/scrypt/.source)>.\n"; exit 1; }
deps=( -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"crypto" -L"." -L"lib/scrypt" )
### CONFIGURATION
gcc "${deps[@]}" -Qunused-arguments -c types.c -o types.o "$@"
gcc "${deps[@]}" -Qunused-arguments -l"types.o" mpw.c -o mpw "$@"
# Targets to build.
if [[ $targets ]]; then
read -ra targets <<< "$targets"
else
# Default targets.
# Modify here or override using targets='mpw mpw-bench' ./build
targets=(
mpw # C CLI version of Master Password.
#mpw-bench # C CLI Master Password benchmark utility.
)
fi
### DEPENDENCIES
digest() {
openssl sha -sha256 -binary < "$1" | od -t x1 -An -v | tr -d '[:space:]'
}
fetch() {
if hash wget 2>/dev/null; then
wget -O "${1##*/}" "$1"
elif hash curl 2>/dev/null; then
curl "$1" > "${1##*/}"
fi
}
unpack() {
if [[ $1 = *.tar.gz || $1 = *.tgz ]]; then
tar -xvzf "$1"
elif [[ $1 = *.tar.bz2 || $1 = *.tbz2 ]]; then
tar -xvjf "$1"
elif [[ $1 = *.tar ]]; then
tar -xvf "$1"
else
echo 2>&1 "Don't know how to unpack: $1"
fi
printf 'Verifying package: %s, against digest: %s...' "$1" "$2"
[[ $(digest "$1") = $2 ]] || {
printf ' mismatch!\n'
echo 2>&1 "Downloaded package doesn't match digest."
exit 1
}
printf ' OK!\n'
files=( !("$1") )
if [[ -d $files ]] && (( ${#files[@]} == 1 )); then
mv "$files"/* .
rmdir "$files"
fi
}
fetchSource() (
source .source
if [[ $pkg && -e "${pkg##*/}" ]]; then
files=( !("${pkg##*/}") )
[[ -e $files ]] || {
echo
echo "Unpacking: ${PWD##*/}, using package..."
unpack "${pkg##*/}" "$pkg_sha256"
}
elif [[ $git ]] && hash git 2>/dev/null; then
[[ -e .git ]] || {
echo
echo "Fetching: ${PWD##*/}, using git..."
git clone "$svn" .
printf '%s' "$(git describe --always)" > "${PWD##*/}-version"
}
elif [[ $svn ]] && hash git 2>/dev/null && [[ -x "$(git --exec-path)/git-svn" ]]; then
[[ -e .git ]] || {
echo
echo "Fetching: ${PWD##*/}, using git-svn..."
git svn clone --prefix=origin/ --stdlayout "$svn" .
printf '%s' "$(git describe --always)" > "${PWD##*/}-version"
}
elif [[ $svn ]] && hash svn 2>/dev/null; then
[[ -e .svn ]] || {
echo
echo "Fetching: ${PWD##*/}, using svn..."
svn checkout "$svn/trunk" .
printf 'r%s' "$(svn info | awk '/^Revision:/{ print $2 }')" > "${PWD##*/}-version"
}
elif [[ $pkg ]]; then
files=( !("${pkg##*/}") )
[[ -e $files ]] || {
echo
echo "Fetching: ${PWD##*/}, using package..."
fetch "$pkg"
unpack "${pkg##*/}" "$pkg_sha256"
}
else
echo >&2 "error: Missing git-svn or svn."
echo >&2 "error: Please install either or manually check out the sources"
echo >&2 "error: from: $home"
echo >&2 "error: into: $PWD"
exit 1
fi
)
depend() {
echo
echo "Checking dependency: $1..."
[[ -e "lib/$1/.built" ]] && return
pushd "lib/$1"
fetchSource
echo
echo "Configuring dependency: $1..."
if [[ -e configure.ac ]]; then
if [[ ! -e configure ]]; then
# create configure using autotools.
if ! hash aclocal || ! hash automake; then
echo >&2 "Need autotools to build $1. Please install automake and autoconf."
exit 1
fi
aclocal
autoheader
autoconf
mkdir -p config.aux
automake --add-missing
fi
fi
if [[ -e configure ]]; then
./configure
fi
echo
echo "Building dependency: $1..."
if [[ -e Makefile ]]; then
if ! hash make; then
echo >&2 "Need make to build $1. Please install GNU make."
exit 1
fi
make
date > .built
else
echo >&2 "error: Don't know how to build: $1"
exit 1
fi
popd
}
### MPW
mpw() {
depend scrypt
echo
echo "Building target: $target..."
CFLAGS=(
# include paths
-I"lib/scrypt/lib" -I"lib/scrypt/libcperciva"
)
LDFLAGS=(
# library paths
-L"." -L"lib/scrypt"
# link libraries
-l"crypto"
# scrypt
"lib/scrypt/scrypt-crypto_aesctr.o"
"lib/scrypt/scrypt-sha256.o"
"lib/scrypt/scrypt-crypto_scrypt-nosse.o"
"lib/scrypt/scrypt-memlimit.o"
"lib/scrypt/scrypt-scryptenc_cpuperf.o"
"lib/scrypt/scrypt-scryptenc.o"
)
cc "${CFLAGS[@]}" -c types.c -o types.o "$@"
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" mpw.c -o mpw "$@"
echo "done! Now run ./install or use ./mpw"
}
### MPW-BENCH
mpw-bench() {
depend scrypt
depend bcrypt
echo
echo "Building target: $target..."
CFLAGS=(
# include paths
-I"lib/scrypt/lib" -I"lib/scrypt/libcperciva"
-I"lib/bcrypt"
)
LDFLAGS=(
# library paths
-L"." -L"lib/scrypt"
-L"lib/bcrypt"
# libraries
-l"crypto"
# scrypt
"lib/scrypt/scrypt-crypto_aesctr.o"
"lib/scrypt/scrypt-sha256.o"
"lib/scrypt/scrypt-crypto_scrypt-nosse.o"
"lib/scrypt/scrypt-memlimit.o"
"lib/scrypt/scrypt-scryptenc_cpuperf.o"
"lib/scrypt/scrypt-scryptenc.o"
# bcrypt
"lib/bcrypt/crypt_blowfish.o"
"lib/bcrypt/crypt_gensalt.o"
"lib/bcrypt/wrapper.o"
"lib/bcrypt/x86.o"
)
cc "${CFLAGS[@]}" -c types.c -o types.o "$@"
cc "${CFLAGS[@]}" "${LDFLAGS[@]}" "types.o" mpw-bench.c -o mpw-bench "$@"
echo "done! Now use ./mpw-bench"
}
### TARGETS
cc() {
if hash llvm-gcc 2>/dev/null; then
llvm-gcc "$@"
elif hash gcc 2>/dev/null; then
gcc -std=gnu99 "$@"
elif hash clang 2>/dev/null; then
clang "$@"
else
echo >&2 "Need a compiler. Please install GCC or LLVM."
exit 1
fi
}
echo "Will build targets: ${targets[*]}..."
for target in "${targets[@]}"; do
"$target" "$@"
done

20
MasterPassword/C/distribute Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
cd "${BASH_SOURCE%/*}"
tag=$(git describe)
commit=$(git describe --long --dirty)
[[ $tag && $commit = $tag-* ]] || exit 1
git show --show-signature --pretty=format:%H --quiet "$tag" > VERSION
mpwArchive=mpw-$commit.tar.gz
[[ -e $mpwArchive ]] && echo "WARNING: $mpwArchive already exists. Will overwrite."
read -n1 -p "Will prepare and release $mpwArchive. Press a key to continue or ^C to abort."
git ls-files -z . | xargs -0 tar -cvzf "$mpwArchive"
echo "$mpwArchive ready, SHA256: $(openssl sha -sha256 < "$mpwArchive")"
cd ../../Site/current
ln -sf "../../MasterPassword/C/$mpwArchive"
[[ -e $_ ]]
echo "Linked from site, please update your hyperlinks to point to http://masterpasswordapp.com/$mpwArchive"

View File

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

View File

@@ -1 +1,4 @@
https://code.google.com/p/scrypt/
home=https://code.google.com/p/scrypt/
svn=http://scrypt.googlecode.com/svn
pkg=http://masterpasswordapp.com/libscrypt-b12b554.tar.gz
pkg_sha256=c726daec68a345e420896f005394a948dc5a6924713ed94b684c856d4c247f0b

View File

@@ -0,0 +1,187 @@
#include <sys/time.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <pwd.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <alg/sha256.h>
#include <crypto/crypto_scrypt.h>
#include <ow-crypt.h>
#include "types.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_dkLen 64
#define MP_hash PearlHashSHA256
int main(int argc, char *const argv[]) {
char *userName = "Robert Lee Mitchel";
char *masterPassword = "banana colored duckling";
char *siteName = "masterpasswordapp.com";
uint32_t siteCounter = 1;
MPElementType siteType = MPElementTypeGeneratedLong;
// Start MP
struct timeval startTime;
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
int iterations = 100;
for (int i = 0; i < iterations; ++i) {
// Calculate the master key salt.
char *mpNameSpace = "com.lyndir.masterpassword";
const uint32_t n_userNameLength = htonl(strlen(userName));
const size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength );
if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
return 1;
}
char *mKS = masterKeySalt;
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace);
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
if (mKS - masterKeySalt != masterKeySaltLength)
abort();
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
// Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen );
if (!masterKey) {
fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1;
}
if (crypto_scrypt( (const uint8_t *)masterPassword, strlen(masterPassword), (const uint8_t *)masterKeySalt, masterKeySaltLength, MP_N, MP_r, MP_p, masterKey, MP_dkLen ) < 0) {
fprintf(stderr, "Could not generate master key: %d\n", errno);
return 1;
}
memset(masterKeySalt, 0, masterKeySaltLength);
free(masterKeySalt);
// Calculate the site seed.
const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter);
const size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1;
}
char *sPI = sitePasswordInfo;
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace);
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort();
uint8_t sitePasswordSeed[32];
HMAC_SHA256_Buf(masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed);
memset(masterKey, 0, MP_dkLen);
memset(sitePasswordInfo, 0, sitePasswordInfoLength);
free(masterKey);
free(sitePasswordInfo);
// Determine the cipher.
const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
trc("type %d, cipher: %s\n", siteType, cipher);
if (strlen(cipher) > 32)
abort();
// Encode the password from the seed using the cipher.
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) {
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
}
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
if (i % 1 == 0)
fprintf( stderr, "\rmpw: iteration %d / %d..", i, iterations );
}
// Output timing results.
struct timeval endTime;
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
long long secs = (endTime.tv_sec - startTime.tv_sec);
long long usecs = (endTime.tv_usec - startTime.tv_usec);
double elapsed = secs + usecs / 1000000.0;
double mpwSpeed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, mpwSpeed );
// Start SHA-256
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
iterations = 50000000;
uint8_t hash[32];
for (int i = 0; i < iterations; ++i) {
SHA256_Buf(masterPassword, strlen(masterPassword), hash);
if (i % 1000 == 0)
fprintf( stderr, "\rsha256: iteration %d / %d..", i, iterations );
}
// Output timing results.
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
secs = (endTime.tv_sec - startTime.tv_sec);
usecs = (endTime.tv_usec - startTime.tv_usec);
elapsed = secs + usecs / 1000000.0;
double sha256Speed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, sha256Speed );
// Start BCrypt
if (gettimeofday(&startTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
int bcrypt_cost = 9;
iterations = 600;
for (int i = 0; i < iterations; ++i) {
crypt(masterPassword, crypt_gensalt("$2b$", bcrypt_cost, userName, strlen(userName)));
if (i % 10 == 0)
fprintf( stderr, "\rbcrypt (cost %d): iteration %d / %d..", bcrypt_cost, i, iterations );
}
// Output timing results.
if (gettimeofday(&endTime, NULL) != 0) {
fprintf(stderr, "Could not get time: %d\n", errno);
return 1;
}
secs = (endTime.tv_sec - startTime.tv_sec);
usecs = (endTime.tv_usec - startTime.tv_usec);
elapsed = secs + usecs / 1000000.0;
double bcrypt9Speed = iterations / elapsed;
fprintf( stdout, " done. %d iterations in %llds %lldµs -> %.2f/s\n", iterations, secs, usecs, bcrypt9Speed );
// Summarize.
fprintf( stdout, "\n== SUMMARY ==\nOn this machine,\n" );
fprintf( stdout, "mpw is %f times slower than sha256\n", sha256Speed / mpwSpeed );
fprintf( stdout, "mpw is %f times slower than bcrypt (cost 9)\n", bcrypt9Speed / mpwSpeed );
return 0;
}

View File

@@ -1,4 +1,5 @@
#define _WITH_GETLINE
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -23,6 +24,12 @@
#include <crypto/crypto_scrypt.h>
#include "types.h"
#if defined(READLINE)
#include <readline/readline.h>
#elif defined(EDITLINE)
#include <histedit.h>
#endif
#define MP_N 32768
#define MP_r 8
#define MP_p 2
@@ -38,15 +45,28 @@ void usage() {
fprintf(stderr, " -u name Specify the full name of the user.\n"
" Defaults to %s in env.\n\n", MP_env_username);
fprintf(stderr, " -t type Specify the password's template.\n"
" Defaults to %s in env or 'long'.\n"
" Defaults to %s in env or 'long' for password, 'name' for login.\n"
" x, max, maximum | 20 characters, contains symbols.\n"
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
" b, basic | 8 characters, no symbols.\n"
" s, short | Copy-friendly, 4 characters, no symbols.\n"
" p, pin | 4 numbers.\n\n", MP_env_sitetype);
" i, pin | 4 numbers.\n"
" n, name | 9 letter name.\n"
" p, phrase | 20 character sentence.\n\n", MP_env_sitetype);
fprintf(stderr, " -c counter The value of the counter.\n"
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter);
fprintf(stderr, " -v variant The kind of content to generate.\n"
" Defaults to 'password'.\n"
" p, password | The password to log in with.\n"
" l, login | The username to log in as.\n"
" a, answer | The answer to a security question.\n\n");
fprintf(stderr, " -C context A variant-specific context.\n"
" Defaults to empty.\n"
" -v p, password | Doesn't currently use a context.\n"
" -v l, login | Doesn't currently use a context.\n"
" -v a, answer | Empty for a universal site answer or\n"
" | the most significant word(s) of the question.\n\n");
exit(0);
}
@@ -86,16 +106,15 @@ int main(int argc, char *const argv[]) {
const char *siteName = NULL;
MPElementType siteType = MPElementTypeGeneratedLong;
const char *siteTypeString = getenv( MP_env_sitetype );
MPElementVariant siteVariant = MPElementVariantPassword;
const char *siteVariantString = NULL;
const char *siteContextString = NULL;
uint32_t siteCounter = 1;
const char *siteCounterString = getenv( MP_env_sitecounter );
// Read the options.
char opt;
while ((opt = getopt(argc, argv, "u:t:c:h")) != -1)
for (int opt; (opt = getopt(argc, argv, "u:t:c:v:C:h")) != -1;)
switch (opt) {
case 'h':
usage();
break;
case 'u':
userName = optarg;
break;
@@ -105,6 +124,15 @@ int main(int argc, char *const argv[]) {
case 'c':
siteCounterString = optarg;
break;
case 'v':
siteVariantString = optarg;
break;
case 'C':
siteContextString = optarg;
break;
case 'h':
usage();
break;
case '?':
switch (optopt) {
case 'u':
@@ -144,6 +172,13 @@ int main(int argc, char *const argv[]) {
return 1;
}
trc("siteCounter: %d\n", siteCounter);
if (siteVariantString)
siteVariant = VariantWithName( siteVariantString );
trc("siteVariant: %d (%s)\n", siteVariant, siteVariantString);
if (siteVariant == MPElementVariantLogin)
siteType = MPElementTypeGeneratedName;
if (siteVariant == MPElementVariantAnswer)
siteType = MPElementTypeGeneratedPhrase;
if (siteTypeString)
siteType = TypeWithName( siteTypeString );
trc("siteType: %d (%s)\n", siteType, siteTypeString);
@@ -156,37 +191,34 @@ int main(int argc, char *const argv[]) {
}
trc("mpwConfigPath: %s\n", mpwConfigPath);
FILE *mpwConfig = fopen(mpwConfigPath, "r");
if (!mpwConfig) {
fprintf(stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
return 1;
}
free(mpwConfigPath);
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
if (strcmp(strsep(&line, ":"), userName) == 0) {
masterPassword = strsep(&line, "\n");
break;
}
if (!masterPassword) {
fprintf(stderr, "Missing master password for user: %s\n", userName);
return 1;
if (mpwConfig) {
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
if (strcmp(strsep(&line, ":"), userName) == 0) {
masterPassword = strsep(&line, "\n");
break;
}
}
while (!masterPassword)
masterPassword = getpass( "Your master password: " );
trc("masterPassword: %s\n", masterPassword);
// Calculate the master key salt.
char *mpNameSpace = "com.lyndir.masterpassword";
const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
trc("key scope: %s\n", mpKeyScope);
const uint32_t n_userNameLength = htonl(strlen(userName));
size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength );
const size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = (char *)malloc( masterKeySaltLength );
if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
return 1;
}
char *mKS = masterKeySalt;
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace);
memcpy(mKS, mpKeyScope, strlen(mpKeyScope)); mKS += strlen(mpKeyScope);
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
if (mKS - masterKeySalt != masterKeySaltLength)
@@ -194,7 +226,7 @@ int main(int argc, char *const argv[]) {
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
// Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen );
uint8_t *masterKey = (uint8_t *)malloc( MP_dkLen );
if (!masterKey) {
fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1;
@@ -210,23 +242,32 @@ int main(int argc, char *const argv[]) {
trc("masterKey ID: %s\n", IDForBuf(masterKey, MP_dkLen));
// Calculate the site seed.
const char *mpSiteScope = ScopeForVariant(siteVariant);
trc("site scope: %s, context: %s\n", mpSiteScope, siteContextString == NULL? "<empty>": siteContextString);
const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter);
size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
const uint32_t n_siteContextLength = siteContextString == NULL? 0: htonl(strlen(siteContextString));
size_t sitePasswordInfoLength = strlen(mpSiteScope) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
if (siteContextString)
sitePasswordInfoLength += sizeof(n_siteContextLength) + strlen(siteContextString);
char *sitePasswordInfo = (char *)malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1;
}
char *sPI = sitePasswordInfo;
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace);
memcpy(sPI, mpSiteScope, strlen(mpSiteScope)); sPI += strlen(mpSiteScope);
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (siteContextString) {
memcpy(sPI, &n_siteContextLength, sizeof(n_siteContextLength)); sPI += sizeof(n_siteContextLength);
memcpy(sPI, siteContextString, strlen(siteContextString)); sPI += strlen(siteContextString);
}
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort();
trc("seed from: hmac-sha256(masterKey, 'com.lyndir.masterpassword' | %s | %s | %s)\n", Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)), Hex(&n_siteContextLength, sizeof(n_siteContextLength)), siteContextString);
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
uint8_t sitePasswordSeed[32];
@@ -244,7 +285,7 @@ int main(int argc, char *const argv[]) {
abort();
// Encode the password from the seed using the cipher.
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
char *sitePassword = (char *)calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) {
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);

View File

@@ -31,8 +31,12 @@ const MPElementType TypeWithName(const char *typeName) {
return MPElementTypeGeneratedBasic;
if (0 == strcmp(lowerTypeName, "s") || 0 == strcmp(lowerTypeName, "short"))
return MPElementTypeGeneratedShort;
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin"))
if (0 == strcmp(lowerTypeName, "i") || 0 == strcmp(lowerTypeName, "pin"))
return MPElementTypeGeneratedPIN;
if (0 == strcmp(lowerTypeName, "n") || 0 == strcmp(lowerTypeName, "name"))
return MPElementTypeGeneratedName;
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "phrase"))
return MPElementTypeGeneratedPhrase;
fprintf(stderr, "Not a generated type name: %s", lowerTypeName);
abort();
@@ -46,19 +50,19 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
switch (type) {
case MPElementTypeGeneratedMaximum: {
char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
const char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedLong: {
char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
const char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
return ciphers[seedByte % 21];
}
case MPElementTypeGeneratedMedium: {
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
const char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedBasic: {
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
const char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
return ciphers[seedByte % 3];
}
case MPElementTypeGeneratedShort: {
@@ -67,6 +71,13 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
case MPElementTypeGeneratedPIN: {
return "nnnn";
}
case MPElementTypeGeneratedName: {
return "cvccvcvcv";
}
case MPElementTypeGeneratedPhrase: {
const char *ciphers[] = { "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" };
return ciphers[seedByte % 3];
}
default: {
fprintf(stderr, "Unknown generated type: %d", type);
abort();
@@ -74,6 +85,41 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
}
}
const MPElementVariant VariantWithName(const char *variantName) {
char lowerVariantName[strlen(variantName)];
strcpy(lowerVariantName, variantName);
for (char *vN = lowerVariantName; *vN; ++vN)
*vN = tolower(*vN);
if (0 == strcmp(lowerVariantName, "p") || 0 == strcmp(lowerVariantName, "password"))
return MPElementVariantPassword;
if (0 == strcmp(lowerVariantName, "l") || 0 == strcmp(lowerVariantName, "login"))
return MPElementVariantLogin;
if (0 == strcmp(lowerVariantName, "a") || 0 == strcmp(lowerVariantName, "answer"))
return MPElementVariantAnswer;
fprintf(stderr, "Not a variant name: %s", lowerVariantName);
abort();
}
const char *ScopeForVariant(MPElementVariant variant) {
switch (variant) {
case MPElementVariantPassword: {
return "com.lyndir.masterpassword";
}
case MPElementVariantLogin: {
return "com.lyndir.masterpassword.login";
}
case MPElementVariantAnswer: {
return "com.lyndir.masterpassword.answer";
}
default: {
fprintf(stderr, "Unknown variant: %d", variant);
abort();
}
}
}
const char CharacterFromClass(char characterClass, uint8_t seedByte) {
const char *classCharacters;
switch (characterClass) {
@@ -113,6 +159,10 @@ const char CharacterFromClass(char characterClass, uint8_t seedByte) {
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()";
break;
}
case ' ': {
classCharacters = " ";
break;
}
default: {
fprintf(stderr, "Unknown character class: %c", characterClass);
abort();
@@ -125,7 +175,7 @@ const char *IDForBuf(const void *buf, size_t length) {
uint8_t hash[32];
SHA256_Buf(buf, length, hash);
char *id = calloc(65, sizeof(char));
char *id = (char *)calloc(65, sizeof(char));
for (int kH = 0; kH < 32; kH++)
sprintf(&(id[kH * 2]), "%02X", hash[kH]);
@@ -133,7 +183,7 @@ const char *IDForBuf(const void *buf, size_t length) {
}
const char *Hex(const void *buf, size_t length) {
char *id = calloc(length*2+1, sizeof(char));
char *id = (char *)calloc(length*2+1, sizeof(char));
for (int kH = 0; kH < length; kH++)
sprintf(&(id[kH * 2]), "%02X", ((const uint8_t*)buf)[kH]);
return id;

View File

@@ -7,10 +7,13 @@
//
typedef enum {
MPElementContentTypePassword,
MPElementContentTypeNote,
MPElementContentTypePicture,
} MPElementContentType;
/** Generate the password to log in with. */
MPElementVariantPassword,
/** Generate the login name to log in as. */
MPElementVariantLogin,
/** Generate the answer to a security question. */
MPElementVariantAnswer,
} MPElementVariant;
typedef enum {
/** Generate the password. */
@@ -33,6 +36,8 @@ typedef enum {
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedName = 0xE | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPhrase = 0xF | MPElementTypeClassGenerated | 0x0,
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
@@ -44,6 +49,8 @@ typedef enum {
#define trc(...) do {} while (0)
#endif
const MPElementVariant VariantWithName(const char *variantName);
const char *ScopeForVariant(MPElementVariant variant);
const MPElementType TypeWithName(const char *typeName);
const char *CipherForType(MPElementType type, uint8_t seedByte);
const char CharacterFromClass(char characterClass, uint8_t seedByte);

View File

@@ -5,7 +5,7 @@
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
@@ -13,7 +13,7 @@
<name>Master Password Algorithm Implementation</name>
<description>The implementation of the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<packaging>jar</packaging>
@@ -24,12 +24,12 @@
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-system</artifactId>
<version>GIT-SNAPSHOT</version>
<version>1.6-p6</version>
</dependency>
<dependency>
<groupId>com.lyndir.lhunath.opal</groupId>
<artifactId>opal-crypto</artifactId>
<version>GIT-SNAPSHOT</version>
<version>1.6-p6</version>
</dependency>
<!-- EXTERNAL DEPENDENCIES -->
@@ -41,7 +41,7 @@
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.3.2</version>
<version>1.4.0</version>
</dependency>
</dependencies>

View File

@@ -1,5 +1,6 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Set;
@@ -79,11 +80,9 @@ public enum MPElementType {
*/
public static MPElementType forName(final String name) {
for (final MPElementType type : values()) {
if (type.getName().equalsIgnoreCase( name ) || type.getShortName().equalsIgnoreCase( name )) {
for (final MPElementType type : values())
if (type.getName().equalsIgnoreCase( name ) || type.getShortName().equalsIgnoreCase( name ))
return type;
}
}
throw logger.bug( "Element type not known: %s", name );
}
@@ -93,14 +92,12 @@ public enum MPElementType {
*
* @return All types that support the given class.
*/
public static ImmutableSet<MPElementType> forClass(final MPElementTypeClass typeClass) {
public static ImmutableList<MPElementType> forClass(final MPElementTypeClass typeClass) {
ImmutableSet.Builder<MPElementType> types = ImmutableSet.builder();
for (final MPElementType type : values()) {
if (type.getTypeClass() == typeClass) {
ImmutableList.Builder<MPElementType> types = ImmutableList.builder();
for (final MPElementType type : values())
if (type.getTypeClass() == typeClass)
types.add( type );
}
}
return types.build();
}

View File

@@ -1,6 +1,6 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.lyndir.lhunath.masterpassword.entity.*;
import com.lyndir.masterpassword.entity.*;
/**

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.util.MetaObject;

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.lyndir.lhunath.opal.system.util.MetaObject;
import com.lyndir.lhunath.opal.system.util.ObjectMeta;

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;

View File

@@ -1,7 +1,9 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.io.CharSource;
import com.google.common.io.CharStreams;
import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import com.lyndir.lhunath.opal.crypto.CryptUtils;
@@ -11,18 +13,17 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.xml.stream.events.Characters;
/**
* Implementation of the Master Password algorithm.
*
* <i>07 04, 2012</i>
*
* @author lhunath
* @author lhunath, 2014-08-30
*/
public abstract class MasterPassword {
public class MasterKey {
static final Logger logger = Logger.get( MasterPassword.class );
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MasterKey.class );
private static final int MP_N = 32768;
private static final int MP_r = 8;
private static final int MP_p = 2;
@@ -33,52 +34,60 @@ public abstract class MasterPassword {
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
private static final MPTemplates templates = MPTemplates.load();
public static byte[] keyForPassword(final String password, final String username) {
private final String userName;
private final byte[] key;
private boolean valid;
public MasterKey(final String userName, final String masterPassword) {
this.userName = userName;
long start = System.currentTimeMillis();
byte[] nusernameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
.order( MP_byteOrder )
.putInt( username.length() )
.array();
byte[] userNameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
.order( MP_byteOrder )
.putInt( userName.length() )
.array();
byte[] salt = Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
nusernameLengthBytes, //
username.getBytes( MP_charset ) );
userNameLengthBytes, userName.getBytes( MP_charset ) );
try {
byte[] key = SCrypt.scrypt( password.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
logger.trc( "User: %s, password: %s derives to key ID: %s (took %.2fs)", username, password,
CodeUtils.encodeHex( keyIDForKey( key ) ), (double) (System.currentTimeMillis() - start) / 1000 );
key = SCrypt.scrypt( masterPassword.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
valid = true;
return key;
logger.trc( "User: %s, master password derives to key ID: %s (took %.2fs)", //
userName, getKeyID(), (double) (System.currentTimeMillis() - start) / 1000 );
}
catch (GeneralSecurityException e) {
throw logger.bug( e );
}
}
public static byte[] subkeyForKey(final byte[] key, final int subkeyLength) {
public String getUserName() {
return userName;
}
public String getKeyID() {
Preconditions.checkState( valid );
return CodeUtils.encodeHex( MP_hash.of( key ) );
}
private byte[] getSubkey(final int subkeyLength) {
Preconditions.checkState( valid );
byte[] subkey = new byte[Math.min( subkeyLength, key.length )];
System.arraycopy( key, 0, subkey, 0, subkey.length );
return subkey;
}
public static byte[] keyIDForPassword(final String password, final String username) {
return keyIDForKey( keyForPassword( password, username ) );
}
public static byte[] keyIDForKey(final byte[] key) {
return MP_hash.of( key );
}
public static String generateContent(final MPElementType type, final String name, final byte[] key, int counter) {
public String encode(final String name, final MPElementType type, int counter) {
Preconditions.checkState( valid );
Preconditions.checkArgument( type.getTypeClass() == MPElementTypeClass.Generated );
Preconditions.checkArgument( !name.isEmpty() );
Preconditions.checkArgument( key.length > 0 );
if (counter == 0)
counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
@@ -112,17 +121,9 @@ public abstract class MasterPassword {
return password.toString();
}
public static void main(final String... arguments) {
public void invalidate() {
String masterPassword = "test-mp";
String username = "test-user";
String siteName = "test-site";
MPElementType siteType = MPElementType.GeneratedLong;
int siteCounter = 42;
String sitePassword = generateContent( siteType, siteName, keyForPassword( masterPassword, username ), siteCounter );
logger.inf( "master password: %s, username: %s\nsite name: %s, site type: %s, site counter: %d\n => site password: %s",
masterPassword, username, siteName, siteType, siteCounter, sitePassword );
valid = false;
Arrays.fill( key, (byte) 0 );
}
}

View File

@@ -1,18 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyndir.lhunath.masterpassword" android:versionCode="1" android:versionName="GIT-SNAPSHOT">
package="com.lyndir.masterpassword"
android:versionCode="1"
android:versionName="GIT-SNAPSHOT">
<uses-sdk android:minSdkVersion="11"
android:targetSdkVersion="16" />
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".UsersActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
android:allowBackup="true">
<activity android:name=".EmergencyActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".UsersActivity" />
</application>
</manifest>

View File

@@ -1,6 +1,6 @@
/*___Generated_by_IDEA___*/
package com.lyndir.lhunath.masterpassword;
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 {

View File

@@ -1,6 +1,6 @@
/*___Generated_by_IDEA___*/
package com.lyndir.lhunath.masterpassword;
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,6 +1,6 @@
/*___Generated_by_IDEA___*/
package com.lyndir.lhunath.masterpassword;
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

@@ -5,7 +5,7 @@
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
@@ -13,7 +13,7 @@
<name>Master Password Android</name>
<description>An Android application to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-android</artifactId>
<packaging>apk</packaging>
@@ -24,22 +24,73 @@
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<!--configuration>
<proguard>
<configuration>
<zipalign>
<verbose>true</verbose>
<skip>false</skip>
<config>proguard.cfg</config>
</proguard>
</configuration-->
</zipalign>
<sdk>
<platform>19</platform>
</sdk>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<executions>
<execution>
<id>signing</id>
<goals>
<goal>sign</goal>
</goals>
<phase>package</phase>
<inherited>true</inherited>
<configuration>
<archiveDirectory></archiveDirectory>
<includes>
<include>target/*.apk</include>
</includes>
<keystore>release.jks</keystore>
<storepass>${env.PASSWORD}</storepass>
<keypass>${env.PASSWORD}</keypass>
<alias>android</alias>
<arguments>
<argument>-sigalg</argument><argument>MD5withRSA</argument>
<argument>-digestalg</argument><argument>SHA1</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<sign>
<debug>false</debug>
</sign>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
@@ -47,18 +98,27 @@
<dependency>
<groupId>com.jakewharton</groupId>
<artifactId>butterknife</artifactId>
<version>5.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
</dependency>
<!-- clone https://github.com/mosabua/maven-android-sdk-deployer.git
run mvn install -P 4.4 -->
<dependency>
<groupId>com.google.android</groupId>
<groupId>android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>libscrypt</artifactId>
<version>1.4.0</version>
<type>so</type>
<classifier>android</classifier>
<scope>runtime</scope>
</dependency>
</dependencies>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,90 @@
<?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:orientation="vertical"
android:gravity="center">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ProgressBar
android:id="@+id/progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<EditText
android:id="@+id/userNameField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text|textCapWords|textPersonName"
android:hint="@string/userName.hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="26sp" />
<EditText
android:id="@+id/masterPasswordField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text|textPassword"
android:hint="@string/masterPassword.hint"
android:password="true"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="18sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/double_"
android:contentDescription="@string/empty" />
<EditText
android:id="@+id/siteNameField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text|textNoSuggestions|textUri"
android:hint="@string/siteName.hint"
android:gravity="center"
android:textColor="#FFFFFF"
android:textSize="26sp" />
<Button
android:id="@+id/sitePasswordField"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@null"
android:textColor="#FFFFFF"
android:textSize="32sp"
android:text="LuxdZozvDuma4["
android:onClick="copySitePassword" />
<Spinner
android:id="@+id/typeField"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<NumberPicker
android:id="@+id/counterField"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello masterpassword-android!</string>
<string name="app_name">masterpassword-android</string>
<string name="app_name">Master Password</string>
<string name="avatar">User Avatar</string>
<string name="siteName.hint">Site Name</string>
<string name="userName.hint">Your Name</string>
<string name="masterPassword.hint">Your Master Password</string>
<string name="empty" />
</resources>

View File

@@ -0,0 +1,273 @@
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
import android.app.Activity;
import android.content.*;
import android.graphics.Paint;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.*;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.concurrent.*;
public class EmergencyActivity extends Activity {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( EmergencyActivity.class );
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
@Override
void update() {
updateMasterKey();
}
};
private final ValueChangedListener updateSitePassword = new ValueChangedListener() {
@Override
void update() {
updateSitePassword();
}
};
private ListenableFuture<MasterKey> masterKeyFuture;
@InjectView(R.id.progressView)
ProgressBar progressView;
@InjectView(R.id.userNameField)
EditText userNameField;
@InjectView(R.id.masterPasswordField)
EditText masterPasswordField;
@InjectView(R.id.siteNameField)
EditText siteNameField;
@InjectView(R.id.typeField)
Spinner typeField;
@InjectView(R.id.counterField)
NumberPicker counterField;
@InjectView(R.id.sitePasswordField)
TextView sitePasswordField;
private int hc_userName;
private int hc_masterPassword;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
Res.init( getResources() );
setContentView( R.layout.activity_emergency );
ButterKnife.inject( this );
userNameField.setOnFocusChangeListener( updateMasterKey );
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
siteNameField.addTextChangedListener( updateSitePassword );
typeField.setOnItemSelectedListener( updateSitePassword );
counterField.setOnValueChangedListener( updateSitePassword );
userNameField.setTypeface( Res.exo_Thin );
userNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
masterPasswordField.setTypeface( Res.sourceCodePro_ExtraLight );
masterPasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
siteNameField.setTypeface( Res.exo_Regular );
siteNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
sitePasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
typeField.setAdapter(
new ArrayAdapter<MPElementType>( this, R.layout.type_item, MPElementType.forClass( MPElementTypeClass.Generated ) ) );
typeField.setSelection( MPElementType.GeneratedLong.ordinal() );
counterField.setMinValue( 1 );
counterField.setMaxValue( Integer.MAX_VALUE );
counterField.setWrapSelectorWheel( false );
}
@Override
protected void onResume() {
super.onResume();
userNameField.setText( getPreferences( MODE_PRIVATE ).getString( "userName", "" ) );
masterPasswordField.requestFocus();
}
@Override
protected void onPause() {
synchronized (this) {
hc_userName = hc_masterPassword = 0;
if (masterKeyFuture != null) {
masterKeyFuture.cancel( true );
masterKeyFuture = null;
}
}
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
super.onPause();
}
private synchronized void updateMasterKey() {
final String userName = userNameField.getText().toString();
final String masterPassword = masterPasswordField.getText().toString();
if (userName.hashCode() == hc_userName && masterPassword.hashCode() == hc_masterPassword)
return;
hc_userName = userName.hashCode();
hc_masterPassword = masterPassword.hashCode();
SharedPreferences.Editor pref = getPreferences( MODE_PRIVATE ).edit();
pref.putString( "userName", userName );
pref.commit();
if (masterKeyFuture != null)
masterKeyFuture.cancel( true );
if (userName.isEmpty() || masterPassword.isEmpty()) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
return;
}
progressView.setVisibility( View.VISIBLE );
(masterKeyFuture = executor.submit( new Callable<MasterKey>() {
@Override
public MasterKey call()
throws Exception {
try {
return new MasterKey( userName, masterPassword );
}
catch (RuntimeException e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating master key." );
throw e;
}
}
} )).addListener( new Runnable() {
@Override
public void run() {
runOnUiThread( new Runnable() {
@Override
public void run() {
updateSitePassword();
}
} );
}
}, executor );
}
private void updateSitePassword() {
final String siteName = siteNameField.getText().toString();
final MPElementType type = (MPElementType) typeField.getSelectedItem();
final int counter = counterField.getValue();
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
return;
}
progressView.setVisibility( View.VISIBLE );
executor.submit( new Runnable() {
@Override
public void run() {
try {
final String sitePassword = masterKeyFuture.get().encode( siteName, type, counter );
runOnUiThread( new Runnable() {
@Override
public void run() {
sitePasswordField.setText( sitePassword );
progressView.setVisibility( View.INVISIBLE );
}
} );
}
catch (InterruptedException ignored) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
}
catch (ExecutionException e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." );
throw Throwables.propagate( e );
}
catch (RuntimeException e) {
sitePasswordField.setText( "" );
progressView.setVisibility( View.INVISIBLE );
logger.err( e, "While generating site password." );
throw e;
}
}
} );
}
public void copySitePassword(View view) {
String sitePassword = sitePasswordField.getText().toString();
if (sitePassword.isEmpty())
return;
ClipDescription description = new ClipDescription( strf( "Password for %s", siteNameField.getText() ),
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip(
new ClipData( description, new ClipData.Item( sitePassword ) ) );
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
}
private abstract class ValueChangedListener
implements TextWatcher, NumberPicker.OnValueChangeListener, AdapterView.OnItemSelectedListener, View.OnFocusChangeListener {
abstract void update();
@Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
}
@Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
}
@Override
public void afterTextChanged(final Editable s) {
update();
}
@Override
public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {
update();
}
@Override
public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) {
update();
}
@Override
public void onNothingSelected(final AdapterView<?> parent) {
update();
}
@Override
public void onFocusChange(final View v, final boolean hasFocus) {
if (!hasFocus)
update();
}
}
}

View File

@@ -0,0 +1,35 @@
package com.lyndir.masterpassword;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.Typeface;
/**
* @author lhunath, 2014-08-25
*/
public class Res {
public static Typeface sourceCodePro_Black;
public static Typeface sourceCodePro_ExtraLight;
public static Typeface exo_Bold;
public static Typeface exo_ExtraBold;
public static Typeface exo_Regular;
public static Typeface exo_Thin;
private static boolean initialized;
public static void init(Resources resources) {
if (initialized)
return;
initialized = true;
sourceCodePro_Black = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-Black.otf" );
sourceCodePro_ExtraLight = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-ExtraLight.otf" );
exo_Bold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Bold.otf" );
exo_ExtraBold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-ExtraBold.otf" );
exo_Regular = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Regular.otf" );
exo_Thin = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Thin.otf" );
}
}

View File

@@ -1,13 +1,13 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.lyndir.lhunath.masterpassword.model.Avatar;
import com.lyndir.lhunath.masterpassword.model.User;
import com.lyndir.lhunath.masterpassword.view.AvatarView;
import com.lyndir.masterpassword.model.Avatar;
import com.lyndir.masterpassword.model.User;
import com.lyndir.masterpassword.view.AvatarView;
public class UsersActivity extends Activity {

View File

@@ -1,6 +1,6 @@
package com.lyndir.lhunath.masterpassword.model;
package com.lyndir.masterpassword.model;
import com.lyndir.lhunath.masterpassword.R;
import com.lyndir.masterpassword.R;
/**

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword.model;
package com.lyndir.masterpassword.model;
/**
* @author lhunath, 2014-08-20

View File

@@ -1,13 +1,11 @@
package com.lyndir.lhunath.masterpassword.view;
package com.lyndir.masterpassword.view;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import butterknife.ButterKnife;
import com.lyndir.lhunath.masterpassword.R;
import com.lyndir.lhunath.masterpassword.model.User;
import com.lyndir.masterpassword.R;
import com.lyndir.masterpassword.model.User;
/**

View File

@@ -5,7 +5,7 @@
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
@@ -13,7 +13,7 @@
<name>Master Password CLI</name>
<description>A CLI interface to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-cli</artifactId>
<packaging>jar</packaging>
@@ -59,7 +59,7 @@
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
<mainClass>com.lyndir.masterpassword.CLI</mainClass>
</transformer>
</transformers>
<filters>
@@ -84,7 +84,7 @@
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>

View File

@@ -13,13 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import com.google.common.io.LineReader;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.*;
import java.util.Arrays;
@@ -30,22 +33,24 @@ import java.util.Arrays;
*/
public class CLI {
static final Logger logger = Logger.get( CLI.class );
private static final String ENV_USERNAME = "MP_USERNAME";
private static final String ENV_PASSWORD = "MP_PASSWORD";
private static final String ENV_USERNAME = "MP_USERNAME";
private static final String ENV_PASSWORD = "MP_PASSWORD";
private static final String ENV_SITETYPE = "MP_SITETYPE";
private static final String ENV_SITECOUNTER = "MP_SITECOUNTER";
public static void main(final String[] args)
throws IOException {
String userName, masterPassword, siteName = null;
// Read information from the environment.
String siteName = null;
String userName = System.getenv().get( ENV_USERNAME );
String masterPassword = System.getenv().get( ENV_PASSWORD );
String siteTypeName = ifNotNullElse( System.getenv().get( ENV_SITETYPE ), "" );
MPElementType siteType = siteTypeName.isEmpty()? MPElementType.GeneratedLong: MPElementType.forName( siteTypeName );
String siteCounterName = ifNotNullElse( System.getenv().get( ENV_SITECOUNTER ), "" );
int siteCounter = siteCounterName.isEmpty()? 1: Integer.parseInt( siteCounterName );
/* Environment. */
userName = System.getenv().get( ENV_USERNAME );
masterPassword = System.getenv().get( ENV_PASSWORD );
/* Arguments. */
int counter = 1;
MPElementType type = MPElementType.GeneratedLong;
// Parse information from option arguments.
boolean typeArg = false, counterArg = false, userNameArg = false;
for (final String arg : Arrays.asList( args ))
if ("-t".equals( arg ) || "--type".equals( arg ))
@@ -58,12 +63,12 @@ public class CLI {
System.exit( 0 );
}
type = MPElementType.forName( arg );
siteType = MPElementType.forName( arg );
typeArg = false;
} else if ("-c".equals( arg ) || "--counter".equals( arg ))
counterArg = true;
else if (counterArg) {
counter = ConversionUtils.toIntegerNN( arg );
siteCounter = ConversionUtils.toIntegerNN( arg );
counterArg = false;
} else if ("-u".equals( arg ) || "--username".equals( arg ))
userNameArg = true;
@@ -80,12 +85,12 @@ public class CLI {
System.out.println( "Available options:" );
System.out.println( "\t-t | --type [site password type]" );
System.out.format( "\t\tDefault: %s. The password type to use for this site.\n", type.getName() );
System.out.format( "\t\tDefault: %s. The password type to use for this site.\n", siteType.getName() );
System.out.println( "\t\tUse 'list' to see the available types." );
System.out.println();
System.out.println( "\t-c | --counter [site counter]" );
System.out.format( "\t\tDefault: %d. The counter to use for this site.\n", counter );
System.out.format( "\t\tDefault: %d. The counter to use for this site.\n", siteCounter );
System.out.println( "\t\tIncrement the counter if you need a new password." );
System.out.println();
@@ -106,28 +111,33 @@ public class CLI {
} else
siteName = arg;
InputStreamReader inReader = new InputStreamReader( System.in );
try {
// Read missing information from the console.
Console console = System.console();
try (InputStreamReader inReader = new InputStreamReader( System.in )) {
LineReader lineReader = new LineReader( inReader );
if (siteName == null) {
System.err.format( "Site name: " );
siteName = lineReader.readLine();
}
if (userName == null) {
System.err.format( "User's name: " );
userName = lineReader.readLine();
}
if (masterPassword == null) {
System.err.format( "%s's master password: ", userName );
masterPassword = lineReader.readLine();
}
byte[] masterKey = MasterPassword.keyForPassword( masterPassword, userName );
String sitePassword = MasterPassword.generateContent( type, siteName, masterKey, counter );
System.out.println( sitePassword );
}
finally {
inReader.close();
if (masterPassword == null) {
if (console != null)
masterPassword = new String( console.readPassword( "%s's master password: ", userName ) );
else {
System.err.format( "%s's master password: ", userName );
masterPassword = lineReader.readLine();
}
}
}
// Encode and write out the site password.
System.out.println( new MasterKey( userName, masterPassword ).encode( siteName, siteType, siteCounter ) );
}
}

View File

@@ -1,4 +1,4 @@
<configuration scan="true">
<configuration scan="false">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
@@ -6,7 +6,7 @@
</layout>
</appender>
<logger name="com.lyndir" level="TRACE" />
<logger name="com.lyndir" level="${mp.log.level:-INFO}" />
<root level="INFO">
<appender-ref ref="STDOUT" />

View File

@@ -5,7 +5,7 @@
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
@@ -13,7 +13,7 @@
<name>Master Password GUI</name>
<description>A GUI interface to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-gui</artifactId>
<packaging>jar</packaging>
@@ -26,6 +26,14 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
@@ -39,7 +47,7 @@
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lyndir.lhunath.masterpassword.GUI</mainClass>
<mainClass>com.lyndir.masterpassword.GUI</mainClass>
</transformer>
</transformers>
<filters>
@@ -64,7 +72,7 @@
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<groupId>com.lyndir.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2008, Maarten Billemont
*
* 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.
*/
package com.lyndir.lhunath.masterpassword;
import com.google.common.base.Optional;
import com.lyndir.lhunath.opal.system.util.TypeUtils;
import java.io.IOException;
import javax.swing.*;
/**
* <p> <i>Jun 10, 2008</i> </p>
*
* @author mbillemo
*/
public class GUI implements UnlockFrame.SignInCallback {
private UnlockFrame unlockFrame = new UnlockFrame( this );
private PasswordFrame passwordFrame;
public static void main(final String[] args)
throws IOException {
// Apple
Optional<? extends GUI> appleGUI = TypeUtils.newInstance( AppleGUI.class );
if (appleGUI.isPresent()) {
appleGUI.get().open();
return;
}
// All others
new GUI().open();
}
void open() {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
if (passwordFrame == null) {
unlockFrame.setVisible( true );
} else {
passwordFrame.setVisible( true );
}
}
} );
}
@Override
public boolean signedIn(final User user) {
if (!user.hasKey()) {
return false;
}
user.getKey();
passwordFrame = new PasswordFrame( user );
open();
return true;
}
}

View File

@@ -1,6 +1,7 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.apple.eawt.*;
import javax.swing.*;
/**
@@ -29,4 +30,12 @@ public class AppleGUI extends GUI {
}
} );
}
@Override
protected PasswordFrame newPasswordFrame(final User user) {
PasswordFrame frame = super.newPasswordFrame( user );
frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
return frame;
}
}

View File

@@ -1,6 +1,5 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import com.google.common.io.Resources;
import java.awt.*;
import javax.swing.*;

View File

@@ -0,0 +1,20 @@
package com.lyndir.masterpassword;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
/**
* @author lhunath, 2014-08-31
*/
public class Config {
private static final Config instance = new Config();
public static Config get() {
return instance;
}
public boolean checkForUpdates() {
return ConversionUtils.toBoolean( System.getProperty( "mp.update.check" ) ).or( true );
}
}

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
@@ -89,7 +89,7 @@ public class ConfigAuthenticationPanel extends AuthenticationPanel implements It
return selectedUser;
}
return new User( selectedUser.getName(), new String( masterPasswordField.getPassword() ) );
return new User( selectedUser.getUserName(), new String( masterPasswordField.getPassword() ) );
}
public String getHelpText() {

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2008, Maarten Billemont
*
* 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.
*/
package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
import com.google.common.io.*;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.MessageDigests;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.TypeUtils;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.*;
import javax.swing.*;
/**
* <p> <i>Jun 10, 2008</i> </p>
*
* @author mbillemo
*/
public class GUI implements UnlockFrame.SignInCallback {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( GUI.class );
private UnlockFrame unlockFrame = new UnlockFrame( this );
private PasswordFrame passwordFrame;
public static void main(final String[] args)
throws IOException {
if (Config.get().checkForUpdates())
checkUpdate();
GUI gui;
try {
gui = TypeUtils.newInstance( AppleGUI.class );
}
catch (NoClassDefFoundError e) {
gui = new GUI();
}
gui.open();
}
private static void checkUpdate() {
try {
Enumeration<URL> manifestURLs = Thread.currentThread().getContextClassLoader().getResources( JarFile.MANIFEST_NAME );
while (manifestURLs.hasMoreElements()) {
InputStream manifestStream = manifestURLs.nextElement().openStream();
Attributes attributes = new Manifest( manifestStream ).getMainAttributes();
if (!GUI.class.getCanonicalName().equals( attributes.getValue( Attributes.Name.MAIN_CLASS ) ))
continue;
String manifestRevision = attributes.getValue( Attributes.Name.IMPLEMENTATION_VERSION );
String upstreamRevisionURL = "http://masterpasswordapp.com/masterpassword-gui.jar.rev";
CharSource upstream = Resources.asCharSource( URI.create( upstreamRevisionURL ).toURL(), Charsets.UTF_8 );
String upstreamRevision = upstream.readFirstLine();
logger.inf( "Local Revision: <%s>", manifestRevision );
logger.inf( "Upstream Revision: <%s>", upstreamRevision );
if (!manifestRevision.equalsIgnoreCase( upstreamRevision )) {
logger.wrn( "You are not running the current official version. Please update from:\n"
+ "http://masterpasswordapp.com/masterpassword-gui.jar" );
JOptionPane.showMessageDialog( null, "A new version of Master Password is available.\n"
+ "Please download the latest version from http://masterpasswordapp.com",
"Update Available", JOptionPane.WARNING_MESSAGE );
}
}
}
catch (IOException e) {
logger.wrn( e, "Couldn't check for version update." );
}
}
void open() {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
if (passwordFrame == null) {
unlockFrame.setVisible( true );
} else {
passwordFrame.setVisible( true );
}
}
} );
}
@Override
public boolean signedIn(final User user) {
if (!user.hasKey()) {
return false;
}
user.getKey();
passwordFrame = newPasswordFrame( user );
open();
return true;
}
protected PasswordFrame newPasswordFrame(final User user) {
PasswordFrame frame = new PasswordFrame( user );
frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
return frame;
}
}

View File

@@ -1,9 +1,9 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.Iterables;
import com.lyndir.lhunath.masterpassword.util.Components;
import com.lyndir.masterpassword.util.Components;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
@@ -21,7 +21,8 @@ public class PasswordFrame extends JFrame implements DocumentListener {
private final JTextField siteNameField;
private final JComboBox<MPElementType> siteTypeField;
private final JSpinner siteCounterField;
private final JLabel passwordLabel;
private final JTextField passwordField;
private final JLabel tipLabel;
public PasswordFrame(User user)
throws HeadlessException {
@@ -30,7 +31,6 @@ public class PasswordFrame extends JFrame implements DocumentListener {
JLabel label;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( new JPanel( new BorderLayout( 20, 20 ) ) {
{
setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
@@ -38,7 +38,8 @@ public class PasswordFrame extends JFrame implements DocumentListener {
} );
// User
add( label = new JLabel( strf( "Generating passwords for: %s", user.getName() ) ), BorderLayout.NORTH );
add( label = new JLabel( strf( "Generating passwords for: %s", user.getUserName() ) ), BorderLayout.NORTH );
label.setFont( Res.exoRegular().deriveFont( 12f ) );
label.setAlignmentX( LEFT_ALIGNMENT );
// Site
@@ -49,6 +50,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
// Site Name
sitePanel.add( label = new JLabel( "Site Name:", JLabel.LEADING ) );
label.setFont( Res.exoRegular().deriveFont( 12f ) );
label.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteNameField = new JTextField() {
@@ -57,6 +59,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
} );
siteNameField.setFont( Res.exoRegular().deriveFont( 12f ) );
siteNameField.setAlignmentX( LEFT_ALIGNMENT );
siteNameField.getDocument().addDocumentListener( this );
siteNameField.addActionListener( new ActionListener() {
@@ -71,7 +74,13 @@ public class PasswordFrame extends JFrame implements DocumentListener {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
dispose();
passwordField.setText( null );
siteNameField.setText( null );
if (getDefaultCloseOperation() == WindowConstants.EXIT_ON_CLOSE)
System.exit( 0 );
else
dispose();
}
} );
}
@@ -92,6 +101,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
} );
siteSettings.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteSettings );
siteTypeField.setFont( Res.exoRegular().deriveFont( 12f ) );
siteTypeField.setAlignmentX( LEFT_ALIGNMENT );
siteTypeField.setAlignmentY( CENTER_ALIGNMENT );
siteTypeField.setSelectedItem( MPElementType.GeneratedLong );
@@ -102,6 +112,7 @@ public class PasswordFrame extends JFrame implements DocumentListener {
}
} );
siteCounterField.setFont( Res.exoRegular().deriveFont( 12f ) );
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
siteCounterField.setAlignmentY( CENTER_ALIGNMENT );
siteCounterField.addChangeListener( new ChangeListener() {
@@ -112,9 +123,18 @@ public class PasswordFrame extends JFrame implements DocumentListener {
} );
// Password
add( passwordLabel = new JLabel( " ", JLabel.CENTER ), BorderLayout.SOUTH );
passwordLabel.setAlignmentX( LEFT_ALIGNMENT );
passwordLabel.setFont( Res.sourceCodeProBlack().deriveFont( 40f ) );
passwordField = new JTextField( " " );
passwordField.setFont( Res.sourceCodeProBlack().deriveFont( 40f ) );
passwordField.setHorizontalAlignment( JTextField.CENTER );
passwordField.setAlignmentX( Component.CENTER_ALIGNMENT );
passwordField.setEditable( false );
// Tip
tipLabel = new JLabel( " ", JLabel.CENTER );
tipLabel.setFont( Res.exoThin().deriveFont( 9f ) );
tipLabel.setAlignmentX( Component.CENTER_ALIGNMENT );
add( Components.boxLayout( BoxLayout.PAGE_AXIS, passwordField, tipLabel ), BorderLayout.SOUTH );
pack();
setMinimumSize( getSize() );
@@ -131,22 +151,26 @@ public class PasswordFrame extends JFrame implements DocumentListener {
final int siteCounter = (Integer) siteCounterField.getValue();
if (siteType.getTypeClass() != MPElementTypeClass.Generated || siteName == null || siteName.isEmpty() || !user.hasKey()) {
passwordLabel.setText( null );
passwordField.setText( null );
tipLabel.setText( null );
return;
}
Res.execute( new Runnable() {
@Override
public void run() {
final String sitePassword = MasterPassword.generateContent( siteType, siteName, user.getKey(), siteCounter );
if (callback != null) {
final String sitePassword = user.getKey().encode( siteName, siteType, siteCounter );
if (callback != null)
callback.passwordGenerated( siteName, sitePassword );
}
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
passwordLabel.setText( sitePassword );
if (!siteName.equals( siteNameField.getText() ))
return;
passwordField.setText( sitePassword );
tipLabel.setText( "Press [Enter] to copy the password." );
}
} );
}

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
@@ -26,6 +26,10 @@ public abstract class Res {
private static final Logger logger = Logger.get( Res.class );
private static Font sourceCodeProBlack;
private static Font exoBold;
private static Font exoExtraBold;
private static Font exoRegular;
private static Font exoThin;
public static void execute(final Runnable job) {
executor.submit( new Runnable() {
@@ -61,6 +65,54 @@ public abstract class Res {
}
}
public static Font exoBold() {
try {
URL resource = Resources.getResource( "fonts/Exo2.0-Bold.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return exoBold != null? exoBold: //
(exoBold = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
public static Font exoExtraBold() {
try {
URL resource = Resources.getResource( "fonts/Exo2.0-ExtraBold.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return exoExtraBold != null? exoExtraBold: //
(exoExtraBold = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
public static Font exoRegular() {
try {
URL resource = Resources.getResource( "fonts/Exo2.0-Regular.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return exoRegular != null? exoRegular: //
(exoRegular = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
public static Font exoThin() {
try {
URL resource = Resources.getResource( "fonts/Exo2.0-Thin.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return exoThin != null? exoThin: //
(exoThin = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
private static final class RetinaIcon extends ImageIcon {
private static final Pattern scalePattern = Pattern.compile(".*@(\\d+)x.[^.]+$");

View File

@@ -1,4 +1,4 @@
package com.lyndir.lhunath.masterpassword;
package com.lyndir.masterpassword;
import java.awt.*;
import java.awt.event.ActionEvent;

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