Compare commits
No commits in common. "master" and "2.1-appstore-mac1" have entirely different histories.
master
...
2.1-appsto
@ -1,28 +0,0 @@
|
||||
# OS-Specific junk.
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# Xcode IDE
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
|
||||
# Generated
|
||||
/platform-darwin/Resources/Media/Images.xcassets/
|
||||
/platform-darwin/Podfile.lock
|
||||
/platform-darwin/Pods/
|
||||
|
||||
# Gradle
|
||||
build
|
||||
.gradle
|
||||
local.properties
|
||||
/builds
|
||||
/platform-android/.externalNativeBuild
|
||||
|
||||
# Git
|
||||
.git
|
46
.gitignore
vendored
@ -1,29 +1,41 @@
|
||||
# OS-Specific junk.
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*~
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
/MasterPassword/Java/.idea
|
||||
/.idea/*
|
||||
!/.idea/encodings.xml
|
||||
!/.idea/inspectionProfiles
|
||||
!/.idea/projectCodeStyle.xml
|
||||
!/.idea/validation.xml
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
out
|
||||
/*.ipr
|
||||
/*.iws
|
||||
|
||||
# Xcode IDE
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
/DerivedData/
|
||||
|
||||
# Generated
|
||||
/platform-darwin/Resources/Media/Images.xcassets/
|
||||
/platform-darwin/Podfile.lock
|
||||
/platform-darwin/Pods/
|
||||
MasterPassword/Resources/Media/Images.xcassets/
|
||||
|
||||
# Gradle
|
||||
build
|
||||
.gradle
|
||||
local.properties
|
||||
/builds
|
||||
/platform-android/.externalNativeBuild
|
||||
.cxx
|
||||
# Media
|
||||
Press/Background.png
|
||||
Press/Front-Page.png
|
||||
Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
|
||||
|
||||
# IPA
|
||||
/sendipa/*
|
||||
!/sendipa/sendipa.conf
|
||||
|
||||
# Java
|
||||
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
|
||||
|
@ -1,20 +0,0 @@
|
||||
variables:
|
||||
GIT_DEPTH: 3
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
build_project:
|
||||
stage: build
|
||||
script:
|
||||
- "( brew bundle )"
|
||||
- "( ./lib/bin/build_libsodium-macos clean && ./lib/bin/build_libsodium-macos )"
|
||||
- "( ./lib/bin/build_libjson-c-macos clean && ./lib/bin/build_libjson-c-macos )"
|
||||
- "( cd ./platform-independent/c/cli && ./clean && targets=all ./build && ./mpw-tests && ./mpw-cli-tests )"
|
||||
- "( ./gradlew --stacktrace --info clean test )"
|
||||
- "( cd platform-darwin && pod install )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Release' -scheme 'MasterPassword iOS' -sdk iphonesimulator clean build )"
|
||||
- "( xcodebuild -workspace platform-darwin/MasterPassword.xcworkspace -configuration 'Release' -scheme 'MasterPassword macOS' clean build )"
|
||||
tags:
|
||||
- brew
|
||||
- java
|
||||
- cocoapods
|
||||
- xcode
|
33
.gitmodules
vendored
@ -1,20 +1,21 @@
|
||||
[submodule "External/Pearl"]
|
||||
path = platform-darwin/External/Pearl
|
||||
path = External/Pearl
|
||||
url = git://github.com/Lyndir/Pearl.git
|
||||
[submodule "External/InAppSettingsKit"]
|
||||
path = External/InAppSettingsKit
|
||||
url = git://github.com/lhunath/InAppSettingsKit.git
|
||||
[submodule "External/KCOrderedAccessorFix"]
|
||||
path = External/KCOrderedAccessorFix
|
||||
url = https://github.com/CFKevinRef/KCOrderedAccessorFix.git
|
||||
[submodule "External/AttributedMarkdown"]
|
||||
path = platform-darwin/External/AttributedMarkdown
|
||||
path = External/AttributedMarkdown
|
||||
url = https://github.com/dreamwieber/AttributedMarkdown.git
|
||||
[submodule "MasterPassword/Web/js/mpw-js"]
|
||||
path = platform-independent/web/js/mpw-js
|
||||
url = https://github.com/tmthrgd/mpw-js.git
|
||||
[submodule "lib/libsodium"]
|
||||
path = lib/libsodium
|
||||
url = https://github.com/jedisct1/libsodium.git
|
||||
[submodule "lib/libjson-c"]
|
||||
path = lib/libjson-c
|
||||
url = https://github.com/json-c/json-c.git
|
||||
[submodule "public/site"]
|
||||
path = public/site
|
||||
url = https://gitlab.com/MasterPassword/MasterPassword.git
|
||||
branch = gh-pages
|
||||
shallow = true
|
||||
[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
|
||||
|
5
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
17
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0" is_locked="false">
|
||||
<option name="myName" value="Project Default" />
|
||||
<option name="myLocal" value="false" />
|
||||
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="SignednessMismatch" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnavailableInDeploymentTarget" enabled="true" level="INFO" enabled_by_default="true" />
|
||||
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
7
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Project Default" />
|
||||
<option name="USE_PROJECT_PROFILE" value="true" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
9
.idea/projectCodeStyle.xml
generated
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CodeStyleSettingsManager">
|
||||
<option name="PER_PROJECT_SETTINGS">
|
||||
<value />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
|
6
.travis.yml
Normal file
@ -0,0 +1,6 @@
|
||||
language: objective-c
|
||||
xcode_project: MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj
|
||||
xcode_scheme: MasterPassword iOS (Development)
|
||||
xcode_sdk: iphonesimulator
|
||||
git:
|
||||
submodules: true
|
6
Brewfile
@ -1,6 +0,0 @@
|
||||
brew "libsodium"
|
||||
brew "json-c"
|
||||
|
||||
brew "libtool"
|
||||
brew "automake"
|
||||
brew "autoconf"
|
12
Dockerfile
@ -1,12 +0,0 @@
|
||||
# Set up a container for doing gradle cross-compiling.
|
||||
#
|
||||
# docker build -t lhunath/mp-gradle --file Dockerfile /var/empty
|
||||
FROM debian:stable-slim
|
||||
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
|
||||
RUN mkdir -p /usr/share/man/man1
|
||||
|
||||
RUN apt-get update && apt-get install -y default-jdk-headless git-core bash libtool automake autoconf make g++-multilib
|
||||
RUN git clone --depth=3 $(: --shallow-submodules) --recurse-submodules https://gitlab.com/MasterPassword/MasterPassword.git /mpw
|
||||
RUN cd /mpw && ./gradlew -i clean
|
||||
RUN cd /mpw && git pull && git log -1 && ./gradlew -i check
|
1
External/AttributedMarkdown
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d598fb4f5e29f5aaa66e7e880a9857019865881b
|
1
External/InAppSettingsKit
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b58b72563acecb727da1f7ca151798a911229593
|
1
External/KCOrderedAccessorFix
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 1b8f8b79ad12b70976c7a417ff1a9d29e8c0ed73
|
1
External/Mac/Crashlytics.framework/Crashlytics
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Crashlytics
|
1
External/Mac/Crashlytics.framework/Headers
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Headers
|
1
External/Mac/Crashlytics.framework/Modules
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Modules
|
1
External/Mac/Crashlytics.framework/Resources
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Resources
|
BIN
External/Mac/Crashlytics.framework/Versions/A/Crashlytics
vendored
Normal file
220
External/Mac/Crashlytics.framework/Versions/A/Headers/Crashlytics.h
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
//
|
||||
// Crashlytics.h
|
||||
// Crashlytics
|
||||
//
|
||||
// Copyright 2013 Crashlytics, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
|
||||
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
|
||||
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
|
||||
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
|
||||
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
|
||||
*
|
||||
* Example output:
|
||||
* -[AppDelegate login:] line 134 $ login start
|
||||
*
|
||||
* If you would like to change this macro, create a new header file, unset our define and then define
|
||||
* your own version. Make sure this new header file is imported after the Crashlytics header file.
|
||||
*
|
||||
* #undef CLS_LOG
|
||||
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
|
||||
*
|
||||
**/
|
||||
#ifdef DEBUG
|
||||
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
|
||||
* and will only be visible in your Crashlytics dashboard.
|
||||
*
|
||||
**/
|
||||
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);
|
||||
|
||||
/**
|
||||
*
|
||||
* Add logging that will be sent with your crash data. This logging will show up in the system.log
|
||||
* and your Crashlytics dashboard. It is not recommended for Release builds.
|
||||
*
|
||||
**/
|
||||
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;
|
||||
|
||||
@interface Crashlytics : NSObject
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *apiKey;
|
||||
@property (nonatomic, readonly, copy) NSString *version;
|
||||
@property (nonatomic, assign) BOOL debugMode;
|
||||
|
||||
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
|
||||
|
||||
/**
|
||||
*
|
||||
* The recommended way to install Crashlytics into your application is to place a call
|
||||
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
|
||||
*
|
||||
* This delay defaults to 1 second in order to generally give the application time to
|
||||
* fully finish launching.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
/**
|
||||
*
|
||||
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
|
||||
* these convenience methods to activate the framework and set the delegate in one call.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
/**
|
||||
*
|
||||
* Access the singleton Crashlytics instance.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)sharedInstance;
|
||||
|
||||
/**
|
||||
*
|
||||
* The easiest way to cause a crash - great for testing!
|
||||
*
|
||||
**/
|
||||
- (void)crash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Many of our customers have requested the ability to tie crashes to specific end-users of their
|
||||
* application in order to facilitate responses to support requests or permit the ability to reach
|
||||
* out for more information. We allow you to specify up to three separate values for display within
|
||||
* the Crashlytics UI - but please be mindful of your end-user's privacy.
|
||||
*
|
||||
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
|
||||
* in your system. This could be a database id, hash, or other value that is meaningless to a
|
||||
* third-party observer but can be indexed and queried by you.
|
||||
*
|
||||
* Optionally, you may also specify the end-user's name or username, as well as email address if you
|
||||
* do not have a system that works well with obscured identifiers.
|
||||
*
|
||||
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
|
||||
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
|
||||
* contact information, we strongly recommend that you disclose this in your application's privacy
|
||||
* policy. Data privacy is of our utmost concern.
|
||||
*
|
||||
**/
|
||||
- (void)setUserIdentifier:(NSString *)identifier;
|
||||
- (void)setUserName:(NSString *)name;
|
||||
- (void)setUserEmail:(NSString *)email;
|
||||
|
||||
+ (void)setUserIdentifier:(NSString *)identifier;
|
||||
+ (void)setUserName:(NSString *)name;
|
||||
+ (void)setUserEmail:(NSString *)email;
|
||||
|
||||
/**
|
||||
*
|
||||
* Set a value for a key to be associated with your crash data.
|
||||
*
|
||||
**/
|
||||
- (void)setObjectValue:(id)value forKey:(NSString *)key;
|
||||
- (void)setIntValue:(int)value forKey:(NSString *)key;
|
||||
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
|
||||
- (void)setFloatValue:(float)value forKey:(NSString *)key;
|
||||
|
||||
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
|
||||
+ (void)setIntValue:(int)value forKey:(NSString *)key;
|
||||
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
|
||||
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
|
||||
* to delegate methods. If you want these values or the entire object to stay in memory retain
|
||||
* them or copy them.
|
||||
**/
|
||||
@protocol CLSCrashReport <NSObject>
|
||||
@required
|
||||
|
||||
/**
|
||||
* Returns the session identifier for the crash report.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *identifier;
|
||||
|
||||
/**
|
||||
* Returns the custom key value data for the crash report.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSDictionary *customKeys;
|
||||
|
||||
/**
|
||||
* Returns the CFBundleVersion of the application that crashed.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *bundleVersion;
|
||||
|
||||
/**
|
||||
* Returns the CFBundleShortVersionString of the application that crashed.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *bundleShortVersionString;
|
||||
|
||||
/**
|
||||
* Returns the date that the application crashed at.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSDate *crashedOnDate;
|
||||
|
||||
/**
|
||||
* Returns the os version that the application crashed on.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *OSVersion;
|
||||
|
||||
/**
|
||||
* Returns the os build version that the application crashed on.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *OSBuildVersion;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
*
|
||||
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
|
||||
* action on events that occur in the Crashlytics crash reporting system. You can make
|
||||
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
|
||||
* or through the convenience startWithAPIKey:delegate:... methods.
|
||||
*
|
||||
**/
|
||||
@protocol CrashlyticsDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
*
|
||||
* Called once a Crashlytics instance has determined that the last execution of the
|
||||
* application ended in a crash. This is called some time after the crash reporting
|
||||
* process has begun. If you have specified a delay in one of the
|
||||
* startWithAPIKey:... calls, this will take at least that long to be invoked.
|
||||
*
|
||||
**/
|
||||
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
|
||||
|
||||
/**
|
||||
*
|
||||
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
|
||||
* called once a Crashlytics instance has determined that the last execution of the
|
||||
* application ended in a crash. A CLSCrashReport is passed back that contains data about
|
||||
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
|
||||
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
|
||||
*
|
||||
**/
|
||||
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
|
||||
|
||||
@end
|
6
External/Mac/Crashlytics.framework/Versions/A/Modules/module.modulemap
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
framework module Crashlytics {
|
||||
umbrella header "Crashlytics.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
30
External/Mac/Crashlytics.framework/Versions/A/Resources/Info.plist
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Crashlytics</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.crashlytics.sdk.mac</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Crashlytics</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.5</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>macosx</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>39</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>macosx</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>10.6</string>
|
||||
</dict>
|
||||
</plist>
|
1
External/Mac/Crashlytics.framework/Versions/Current
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
A
|
BIN
External/Mac/Crashlytics.framework/run
vendored
Executable file
1
External/Pearl
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 2237aaf4295f74627b63040c4c246cddff339958
|
1
External/iOS/Crashlytics.framework/Crashlytics
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Crashlytics
|
1
External/iOS/Crashlytics.framework/Headers
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Headers
|
6
External/iOS/Crashlytics.framework/Modules/module.modulemap
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
framework module Crashlytics {
|
||||
umbrella header "Crashlytics.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
1
External/iOS/Crashlytics.framework/Resources
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Resources
|
BIN
External/iOS/Crashlytics.framework/Versions/A/Crashlytics
vendored
Normal file
220
External/iOS/Crashlytics.framework/Versions/A/Headers/Crashlytics.h
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
//
|
||||
// Crashlytics.h
|
||||
// Crashlytics
|
||||
//
|
||||
// Copyright 2013 Crashlytics, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
|
||||
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
|
||||
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
|
||||
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
|
||||
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
|
||||
*
|
||||
* Example output:
|
||||
* -[AppDelegate login:] line 134 $ login start
|
||||
*
|
||||
* If you would like to change this macro, create a new header file, unset our define and then define
|
||||
* your own version. Make sure this new header file is imported after the Crashlytics header file.
|
||||
*
|
||||
* #undef CLS_LOG
|
||||
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
|
||||
*
|
||||
**/
|
||||
#ifdef DEBUG
|
||||
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
|
||||
* and will only be visible in your Crashlytics dashboard.
|
||||
*
|
||||
**/
|
||||
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);
|
||||
|
||||
/**
|
||||
*
|
||||
* Add logging that will be sent with your crash data. This logging will show up in the system.log
|
||||
* and your Crashlytics dashboard. It is not recommended for Release builds.
|
||||
*
|
||||
**/
|
||||
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;
|
||||
|
||||
@interface Crashlytics : NSObject
|
||||
|
||||
@property (nonatomic, readonly, copy) NSString *apiKey;
|
||||
@property (nonatomic, readonly, copy) NSString *version;
|
||||
@property (nonatomic, assign) BOOL debugMode;
|
||||
|
||||
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
|
||||
|
||||
/**
|
||||
*
|
||||
* The recommended way to install Crashlytics into your application is to place a call
|
||||
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
|
||||
*
|
||||
* This delay defaults to 1 second in order to generally give the application time to
|
||||
* fully finish launching.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
/**
|
||||
*
|
||||
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
|
||||
* these convenience methods to activate the framework and set the delegate in one call.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
|
||||
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
|
||||
|
||||
/**
|
||||
*
|
||||
* Access the singleton Crashlytics instance.
|
||||
*
|
||||
**/
|
||||
+ (Crashlytics *)sharedInstance;
|
||||
|
||||
/**
|
||||
*
|
||||
* The easiest way to cause a crash - great for testing!
|
||||
*
|
||||
**/
|
||||
- (void)crash;
|
||||
|
||||
/**
|
||||
*
|
||||
* Many of our customers have requested the ability to tie crashes to specific end-users of their
|
||||
* application in order to facilitate responses to support requests or permit the ability to reach
|
||||
* out for more information. We allow you to specify up to three separate values for display within
|
||||
* the Crashlytics UI - but please be mindful of your end-user's privacy.
|
||||
*
|
||||
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
|
||||
* in your system. This could be a database id, hash, or other value that is meaningless to a
|
||||
* third-party observer but can be indexed and queried by you.
|
||||
*
|
||||
* Optionally, you may also specify the end-user's name or username, as well as email address if you
|
||||
* do not have a system that works well with obscured identifiers.
|
||||
*
|
||||
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
|
||||
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
|
||||
* contact information, we strongly recommend that you disclose this in your application's privacy
|
||||
* policy. Data privacy is of our utmost concern.
|
||||
*
|
||||
**/
|
||||
- (void)setUserIdentifier:(NSString *)identifier;
|
||||
- (void)setUserName:(NSString *)name;
|
||||
- (void)setUserEmail:(NSString *)email;
|
||||
|
||||
+ (void)setUserIdentifier:(NSString *)identifier;
|
||||
+ (void)setUserName:(NSString *)name;
|
||||
+ (void)setUserEmail:(NSString *)email;
|
||||
|
||||
/**
|
||||
*
|
||||
* Set a value for a key to be associated with your crash data.
|
||||
*
|
||||
**/
|
||||
- (void)setObjectValue:(id)value forKey:(NSString *)key;
|
||||
- (void)setIntValue:(int)value forKey:(NSString *)key;
|
||||
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
|
||||
- (void)setFloatValue:(float)value forKey:(NSString *)key;
|
||||
|
||||
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
|
||||
+ (void)setIntValue:(int)value forKey:(NSString *)key;
|
||||
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
|
||||
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
|
||||
* to delegate methods. If you want these values or the entire object to stay in memory retain
|
||||
* them or copy them.
|
||||
**/
|
||||
@protocol CLSCrashReport <NSObject>
|
||||
@required
|
||||
|
||||
/**
|
||||
* Returns the session identifier for the crash report.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *identifier;
|
||||
|
||||
/**
|
||||
* Returns the custom key value data for the crash report.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSDictionary *customKeys;
|
||||
|
||||
/**
|
||||
* Returns the CFBundleVersion of the application that crashed.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *bundleVersion;
|
||||
|
||||
/**
|
||||
* Returns the CFBundleShortVersionString of the application that crashed.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *bundleShortVersionString;
|
||||
|
||||
/**
|
||||
* Returns the date that the application crashed at.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSDate *crashedOnDate;
|
||||
|
||||
/**
|
||||
* Returns the os version that the application crashed on.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *OSVersion;
|
||||
|
||||
/**
|
||||
* Returns the os build version that the application crashed on.
|
||||
**/
|
||||
@property (nonatomic, readonly) NSString *OSBuildVersion;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
*
|
||||
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
|
||||
* action on events that occur in the Crashlytics crash reporting system. You can make
|
||||
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
|
||||
* or through the convenience startWithAPIKey:delegate:... methods.
|
||||
*
|
||||
**/
|
||||
@protocol CrashlyticsDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
*
|
||||
* Called once a Crashlytics instance has determined that the last execution of the
|
||||
* application ended in a crash. This is called some time after the crash reporting
|
||||
* process has begun. If you have specified a delay in one of the
|
||||
* startWithAPIKey:... calls, this will take at least that long to be invoked.
|
||||
*
|
||||
**/
|
||||
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
|
||||
|
||||
/**
|
||||
*
|
||||
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
|
||||
* called once a Crashlytics instance has determined that the last execution of the
|
||||
* application ended in a crash. A CLSCrashReport is passed back that contains data about
|
||||
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
|
||||
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
|
||||
*
|
||||
**/
|
||||
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
|
||||
|
||||
@end
|
30
External/iOS/Crashlytics.framework/Versions/A/Resources/Info.plist
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Crashlytics</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.crashlytics.ios</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Crashlytics</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.5</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>40</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>iphoneos</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>4.0</string>
|
||||
</dict>
|
||||
</plist>
|
1
External/iOS/Crashlytics.framework/Versions/Current
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
A
|
BIN
External/iOS/Crashlytics.framework/run
vendored
Executable file
BIN
External/iOS/Crashlytics.framework/submit
vendored
Executable file
1
External/iOS/Reveal.framework/Headers
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Headers
|
1
External/iOS/Reveal.framework/Reveal
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
Versions/Current/Reveal
|
17
External/iOS/Reveal.framework/Versions/A/Headers/IBARevealLoader.h
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright (c) 2013 Itty Bitty Apps. All rights reserved.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString * const IBARevealLoaderRequestStartNotification;
|
||||
extern NSString * const IBARevealLoaderRequestStopNotification;
|
||||
|
||||
extern NSString * const IBARevealLoaderSetOptionsNotification;
|
||||
extern NSString * const IBARevealLoaderOptionsLogLevelMaskKey;
|
||||
|
||||
@interface IBARevealLoader : NSObject
|
||||
|
||||
+ (void)startServer;
|
||||
+ (void)stopServer;
|
||||
|
||||
@end
|
57
External/iOS/Reveal.framework/Versions/A/Headers/IBARevealLogger.h
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2013 Itty Bitty Apps Pty Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
CF_EXTERN_C_BEGIN
|
||||
|
||||
/*!
|
||||
\brief The Reveal Log level bit flags.
|
||||
\discussion These flags are additive. i.e. you should bitwise OR them together.
|
||||
|
||||
\seealso IBARevealLoggerSetLevelMask
|
||||
\seealso IBARevealLoggerGetLevelMask
|
||||
|
||||
Example:
|
||||
|
||||
// Enable Error, Warning and Info logger levels.
|
||||
IBARevealLoggerSetLevelMask(IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo);
|
||||
|
||||
*/
|
||||
typedef NS_OPTIONS(int32_t, IBARevealLogLevel)
|
||||
{
|
||||
IBARevealLogLevelNone = 0,
|
||||
IBARevealLogLevelDebug = (1 << 0),
|
||||
IBARevealLogLevelInfo = (1 << 1),
|
||||
IBARevealLogLevelWarn = (1 << 2),
|
||||
IBARevealLogLevelError = (1 << 3)
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Set the Reveal logger level mask.
|
||||
\param mask A bit mask which is a combination of the IBARevealLogLevel enum options.
|
||||
|
||||
\discussion If you do not wish to see log messages from Reveal you should call this function with an appropriate level mask as early in your application's lifecycle as possible. For example in your application's main() function.
|
||||
|
||||
Example:
|
||||
|
||||
// Enable Error, Warning and Info logger levels.
|
||||
IBARevealLoggerSetLevelMask(IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo);
|
||||
|
||||
*/
|
||||
CF_EXPORT void IBARevealLoggerSetLevelMask(int32_t mask);
|
||||
|
||||
/*!
|
||||
\brief Get the current Reveal logger level mask.
|
||||
\return A bit mask representing the levels at which Reveal is currently logging.
|
||||
\discussion The default Reveal Logger level mask is IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo.
|
||||
|
||||
Example:
|
||||
|
||||
// Turn off the Info log level.
|
||||
IBARevealLoggerSetLevelMask(IBARevealLoggerGetLevelMask() & ~IBARevealLogLevelInfo);
|
||||
|
||||
*/
|
||||
CF_EXPORT int32_t IBARevealLoggerGetLevelMask(void);
|
||||
|
||||
CF_EXTERN_C_END
|
5
External/iOS/Reveal.framework/Versions/A/Headers/Reveal.h
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2013 Itty Bitty Apps Pty Ltd. All rights reserved.
|
||||
//
|
||||
|
||||
#import "IBARevealLogger.h"
|
||||
#import "IBARevealLoader.h"
|
BIN
External/iOS/Reveal.framework/Versions/A/Reveal
vendored
Normal file
1
External/iOS/Reveal.framework/Versions/Current
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
A
|
1
External/jrswizzle
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 98d18aee73329321c320a2df85bacdb9f08a34a6
|
1
External/uicolor-utilities
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ae96212a4903a2b9e1df1e3542c9962f0d64a74b
|
10
MasterPassword.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
@ -27,7 +27,7 @@
|
||||
|
||||
# ______________________________________________________________________
|
||||
# | |
|
||||
# | .: TABLE OF CONTENTS :. |
|
||||
# | .:: TABLE OF CONTENTS ::. |
|
||||
# |______________________________________________________________________|
|
||||
#
|
||||
# chr decimal
|
||||
@ -66,6 +66,12 @@
|
||||
# readwhile command [args]
|
||||
# Outputs the characters typed by the user into the terminal's input buffer while running the given command.
|
||||
#
|
||||
# pushqueue element ...
|
||||
# Pushes the given arguments as elements onto the queue.
|
||||
#
|
||||
# popqueue
|
||||
# Pops one element off the queue.
|
||||
#
|
||||
# log [format] [arguments...]
|
||||
# Log an event at a certain importance level.
|
||||
# The event is expressed as a printf(1) format argument.
|
||||
@ -79,7 +85,7 @@
|
||||
# reverse [-0|-d delimitor] [elements ...] [<<< elements]
|
||||
# Reverse the order of the given elements.
|
||||
#
|
||||
# order [-0|-d char] [-[cC] comparator|-n] [-t number] [elements ...] [<<< elements]
|
||||
# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [elements ...] [<<< elements]
|
||||
# Orders the elements in ascending order.
|
||||
#
|
||||
# mutex file
|
||||
@ -126,7 +132,7 @@ _tocHash=71e13f42e1ea82c1c7019b27a3bc71f3
|
||||
|
||||
# ______________________________________________________________________
|
||||
# | |
|
||||
# | .: GLOBAL CONFIGURATION :. |
|
||||
# | .:: GLOBAL CONFIGURATION ::. |
|
||||
# |______________________________________________________________________|
|
||||
|
||||
# Unset all exported functions. Exported functions are evil.
|
||||
@ -171,12 +177,9 @@ genToc() {
|
||||
|
||||
# ______________________________________________________________________
|
||||
# | |
|
||||
# | .: GLOBAL DECLARATIONS :. |
|
||||
# | .:: GLOBAL DECLARATIONS ::. |
|
||||
# |______________________________________________________________________|
|
||||
|
||||
# Environment
|
||||
TMPDIR=${TMPDIR:-/tmp} TMPDIR=${TMPDIR%/}
|
||||
|
||||
# Variables for convenience sequences.
|
||||
bobber=( '.' 'o' 'O' 'o' )
|
||||
spinner=( '-' \\ '|' '/' )
|
||||
@ -187,8 +190,8 @@ runner=( '> >' \
|
||||
|
||||
# Variables for terminal requests.
|
||||
[[ -t 2 && $TERM != dumb ]] && {
|
||||
COLUMNS=$({ tput cols || tput co;} 2>&3) # Columns in a line
|
||||
LINES=$({ tput lines || tput li;} 2>&3) # Lines on screen
|
||||
COLUMNS=$( tput cols || tput co ) # Columns in a line
|
||||
LINES=$( tput lines || tput li ) # Lines on screen
|
||||
alt=$( tput smcup || tput ti ) # Start alt display
|
||||
ealt=$( tput rmcup || tput te ) # End alt display
|
||||
hide=$( tput civis || tput vi ) # Hide cursor
|
||||
@ -227,7 +230,7 @@ runner=( '> >' \
|
||||
tput eA; tput as;
|
||||
tput ac; tput ae; } ) # Drawing characters
|
||||
back=$'\b'
|
||||
} 3>&2 2>/dev/null ||:
|
||||
} 2>/dev/null ||:
|
||||
|
||||
|
||||
|
||||
@ -235,7 +238,7 @@ runner=( '> >' \
|
||||
|
||||
# ______________________________________________________________________
|
||||
# | |
|
||||
# | .: FUNCTION DECLARATIONS :. |
|
||||
# | .:: FUNCTION DECLARATIONS ::. |
|
||||
# |______________________________________________________________________|
|
||||
|
||||
|
||||
@ -261,10 +264,7 @@ chr() {
|
||||
# Outputs the decimal ASCII value of the given character.
|
||||
#
|
||||
ord() {
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%d' "'${str:s:1}"
|
||||
done
|
||||
printf '%d' "'$1"
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@ -277,10 +277,7 @@ ord() {
|
||||
# Outputs the hexadecimal ASCII value of the given character.
|
||||
#
|
||||
hex() {
|
||||
local str=$1 s
|
||||
for (( s=0; s < ${#str}; ++s )); do
|
||||
printf '%02X' "'${str:s:1}"
|
||||
done
|
||||
printf '%x' "'$1"
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@ -293,10 +290,7 @@ hex() {
|
||||
# Outputs the character that has the given hexadecimal ASCII value.
|
||||
#
|
||||
unhex() {
|
||||
local hex=$1 h
|
||||
for (( h=0; h < ${#hex}; h+=2 )); do
|
||||
printf "\\x${hex:h:2}"
|
||||
done
|
||||
printf "\\x$1"
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
@ -335,26 +329,6 @@ min() {
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ si ________________________________________________________________|
|
||||
#
|
||||
# si number
|
||||
#
|
||||
# Output a human-readable version of the number using SI units.
|
||||
#
|
||||
si() {
|
||||
local number=$1
|
||||
|
||||
if (( number >= 1000000000000000 )); then printf '%dM' "$((number / 1000000000000000))"
|
||||
elif (( number >= 1000000000000 )); then printf '%dM' "$((number / 1000000000000))"
|
||||
elif (( number >= 1000000000 )); then printf '%dM' "$((number / 1000000000))"
|
||||
elif (( number >= 1000000 )); then printf '%dM' "$((number / 1000000))"
|
||||
elif (( number >= 1000 )); then printf '%dk' "$((number / 1000))"
|
||||
else printf '%d' "$number"; fi
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ totime ____________________________________________________________|
|
||||
#
|
||||
@ -491,6 +465,23 @@ readwhile() {
|
||||
|
||||
|
||||
|
||||
# __________________________________________________________________________
|
||||
# |__ popqueue ______________________________________________________________|
|
||||
#
|
||||
# popqueue
|
||||
#
|
||||
# Pops one element off the queue.
|
||||
# If no elements are available on the queue, this command fails with exit code 1.
|
||||
#
|
||||
popqueue() {
|
||||
local REPLY
|
||||
[[ $_queue ]] && read -t0 <&"${_queue[0]}" || return
|
||||
IFS= read -r -d '' <&"${_queue[0]}"
|
||||
printf %s "$REPLY"
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Latest ____________________________________________________________|
|
||||
#
|
||||
@ -554,50 +545,6 @@ iterate() (
|
||||
fi
|
||||
) # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# _______________________________________________________________________
|
||||
# |__ csvline ____________________________________________________________|
|
||||
#
|
||||
# csvline [-d delimiter] [-D line-delimiter]
|
||||
#
|
||||
# Parse a CSV record from standard input, storing the fields in the CSVLINE array.
|
||||
#
|
||||
# By default, a single line of input is read and parsed into comma-delimited fields.
|
||||
# Fields can optionally contain double-quoted data, including field delimiters.
|
||||
#
|
||||
# A different field delimiter can be specified using -d. You can use -D
|
||||
# to change the definition of a "record" (eg. to support NULL-delimited records).
|
||||
#
|
||||
csvline() {
|
||||
CSVLINE=()
|
||||
local line field quoted=0 delimiter=, lineDelimiter=$'\n' c
|
||||
local OPTIND=1 arg
|
||||
while getopts :d: arg; do
|
||||
case $arg in
|
||||
d) delimiter=$OPTARG ;;
|
||||
esac
|
||||
done
|
||||
|
||||
IFS= read -d "$lineDelimiter" -r line || return
|
||||
while IFS= read -rn1 c; do
|
||||
case $c in
|
||||
\")
|
||||
(( quoted = !quoted ))
|
||||
continue ;;
|
||||
$delimiter)
|
||||
if (( ! quoted )); then
|
||||
CSVLINE+=( "$field" ) field=
|
||||
continue
|
||||
fi ;;
|
||||
esac
|
||||
field+=$c
|
||||
done <<< "$line"
|
||||
[[ $field ]] && CSVLINE+=( "$field" ) ||:
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Logging ___________________________________________________________|
|
||||
#
|
||||
@ -621,11 +568,11 @@ csvline() {
|
||||
# The closing statement also takes a format and arguments, which are displayed in the spinner.
|
||||
#
|
||||
log() {
|
||||
local exitcode=$? result=0 level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler=
|
||||
local exitcode=$? level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler=
|
||||
|
||||
# Handle options.
|
||||
local OPTIND=1
|
||||
while getopts :tpuPrR:d:nx arg; do
|
||||
while getopts :tpuPrR:d:n arg; do
|
||||
case $arg in
|
||||
p)
|
||||
end='.. '
|
||||
@ -643,14 +590,13 @@ log() {
|
||||
end=$OPTARG ;;
|
||||
n)
|
||||
end= ;;
|
||||
x)
|
||||
result=$exitcode ;;
|
||||
t)
|
||||
date=$(date +"${_logDate:-%H:%M}") ;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
format=$1 args=( "${@:2}" )
|
||||
(( ! ${#args[@]} )) && [[ $format ]] && { args=("$format") format=%s; local bold=; }
|
||||
date=${_logDate+$(date +"${_logDate:-%H:%M}")}
|
||||
|
||||
# Level-specific settings.
|
||||
local logLevelColor
|
||||
@ -671,17 +617,17 @@ log() {
|
||||
log FTL 'Log level %s does not exist' "$level"
|
||||
exit 1 ;;
|
||||
esac
|
||||
(( ! supported )) && return "$result"
|
||||
(( ! supported )) && return "$exitcode"
|
||||
local logColor=${_logColor:+$logLevelColor}
|
||||
|
||||
# Generate the log message.
|
||||
case $type in
|
||||
msg|startProgress)
|
||||
printf -v logMsg "${date:+%s }${_logLevel:+%-3s }$format$end" ${date:+"$date"} ${_logLevel:+"$level"} "${args[@]}"
|
||||
printf -v logMsg "[${date:+%s }%-3s] $format$end" ${date:+"$date"} "$level" "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$_logAttributes$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$_logAttributes$bold$logColor&$reset$_logAttributes$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$_logAttributes$bold$logColor}")
|
||||
printf -v conMsg "$reset$_logAttributes${date:+%s }${_logLevel:+$logColor$bold%-3s$reset $_logAttributes}$logColor$colorFormat$reset$_logAttributes$black\$$reset$end$save" ${date:+"$date"} ${_logLevel:+"$level"} "${colorArgs[@]}"
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
|
||||
printf -v conMsg "$reset[${date:+%s }$logColor$bold%-3s$reset] $logColor$colorFormat$reset$black\$$reset$end$save" ${date:+"$date"} "$level" "${colorArgs[@]}"
|
||||
else
|
||||
conMsg=$logMsg
|
||||
fi
|
||||
@ -690,17 +636,15 @@ log() {
|
||||
updateProgress)
|
||||
printf -v logMsg printf " [$format]" "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$_logAttributes$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$_logAttributes$bold$logColor&$reset$_logAttributes$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$_logAttributes$bold$logColor}")
|
||||
printf -v conMsg "$load$eel$blue$bold[$reset$_logAttributes$logColor$colorFormat$reset$_logAttributes$blue$bold]$reset$end" "${colorArgs[@]}"
|
||||
colorFormat=$(sed ${reset:+-e "s/$(requote "$reset")/$reset$logColor/g"} -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format")
|
||||
colorArgs=("${args[@]//$reset/$reset$bold$logColor}")
|
||||
printf -v conMsg "$load$eel$blue$bold[$reset$logColor$colorFormat$reset$blue$bold]$reset$end" "${colorArgs[@]}"
|
||||
else
|
||||
conMsg=$logMsg
|
||||
fi
|
||||
;;
|
||||
|
||||
stopProgress)
|
||||
kill -0 "$_logSpinner" 2>/dev/null || return
|
||||
|
||||
case $exitcode in
|
||||
0) printf -v logMsg "done${format:+ ($format)}.\n" "${args[@]}"
|
||||
if (( _logColor )); then
|
||||
@ -726,17 +670,15 @@ log() {
|
||||
|
||||
# Create the log file.
|
||||
if [[ $_logFile && ! -e $_logFile ]]; then
|
||||
[[ $_logFile = */* ]] || _logFile=./$_logFile
|
||||
[[ $_logFile = */* ]] || $_logFile=./$logFile
|
||||
mkdir -p "${_logFile%/*}" && touch "$_logFile"
|
||||
fi
|
||||
|
||||
# Stop the spinner.
|
||||
if [[ $type = stopProgress && $_logSpinner ]]; then
|
||||
{
|
||||
kill "$_logSpinner" ||:
|
||||
wait "$_logSpinner" ||:
|
||||
unset _logSpinner
|
||||
} 2>/dev/null
|
||||
kill "$_logSpinner"
|
||||
wait "$_logSpinner" 2>/dev/null
|
||||
unset _logSpinner
|
||||
fi
|
||||
|
||||
# Output the ruler.
|
||||
@ -760,10 +702,9 @@ log() {
|
||||
while printf >&2 "$eel$blue$bold[$reset%s$reset$blue$bold]$reset\b\b\b" "${spinner[s++ % ${#spinner[@]}]}" && sleep .1
|
||||
do :; done
|
||||
} & _logSpinner=$!
|
||||
addtrap EXIT 'level=%q _logSpinner=%q golp' "$level" "$_logSpinner"
|
||||
fi
|
||||
|
||||
return $result
|
||||
return $exitcode
|
||||
}
|
||||
trc() { level=TRC log "$@"; }
|
||||
dbg() { level=DBG log "$@"; }
|
||||
@ -794,8 +735,6 @@ rrep() { level=ERR golp "$@"; }
|
||||
ltfp() { level=FTL golp "$@"; }
|
||||
_logColor=${_logColor:-$([[ -t 2 ]] && echo 1)} _logVerbosity=2
|
||||
_logTrcColor=$grey _logDbgColor=$blue _logInfColor=$white _logWrnColor=$yellow _logErrColor=$red _logFtlColor=$bold$red
|
||||
#_logDate=%H:%M # Set this to enable date output in log messages.
|
||||
#_logLevel=1 # Set this to enable level output in log messages.
|
||||
# _______________________________________________________________________
|
||||
|
||||
|
||||
@ -872,10 +811,10 @@ ask() {
|
||||
printf '%s' "$muteChar" >&$fd
|
||||
done
|
||||
REPLY=$reply
|
||||
[[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd
|
||||
else
|
||||
read -u8 -e ${options:+-n1} ${silent:+-s}
|
||||
fi
|
||||
[[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd
|
||||
|
||||
# Evaluate the reply.
|
||||
while true; do
|
||||
@ -964,7 +903,7 @@ reverse() {
|
||||
# ______________________________________________________________________
|
||||
# |__ Order _____________________________________________________________|
|
||||
#
|
||||
# order [-0|-d char] [-[fF] isDesired] [-[cC] comparator|-n|-R|-t] [-r] [-T number] [-a array|elements ...] [<<< elements]
|
||||
# order [-0|-d char] [-[fF] isDesired] [-[cC] isAscending|-n|-r|-t] [-T number] [-a array|elements ...] [<<< elements]
|
||||
#
|
||||
# Orders the elements in ascending order.
|
||||
# Elements are read from command arguments or standard input if no element
|
||||
@ -973,23 +912,21 @@ reverse() {
|
||||
#
|
||||
# By default, the elements will be ordered using lexicographic comparison.
|
||||
# If the -n option is given, the elements will be ordered numerically.
|
||||
# If the -R option is given, the elements will be ordered randomly.
|
||||
# If the -t option is given, the elements are ordered by file mtime.
|
||||
# If the -r option is given, the elements will be ordered randomly.
|
||||
# If the -f option is given, the command name following it will be used
|
||||
# as a filter.
|
||||
# If the -c option is given, the command name following it will be used
|
||||
# as a comparator.
|
||||
# If the -C option is given, the bash code following it will be used
|
||||
# as a comparator.
|
||||
# If the -r option is given, the ordering will be reversed.
|
||||
# If the -T option is given, only the first number results are returned.
|
||||
# If the -t option is given, only the first number results are returned.
|
||||
# If the -a option is given, the elements in array are ordered instead and
|
||||
# array is mutated to contain the result.
|
||||
# If number is 0, all results are returned.
|
||||
#
|
||||
# isDesired is a command name which will get one parameter. The parameter
|
||||
# is an element which will only be included if the command exits successfully.
|
||||
# comparator is a command name which will be executed for each element
|
||||
# isAscending is a command name which will be executed for each element
|
||||
# comparison and will be passed two element arguments. The command should
|
||||
# succeed if the first argument is less than the second argument for the
|
||||
# purpose of this sort.
|
||||
@ -1004,61 +941,59 @@ reverse() {
|
||||
order() {
|
||||
|
||||
# Initialize the vars.
|
||||
local _delimitor=$'\n' _i _j _isDesired=true _comparator=string_ascends _comparator_ascends=1 _top=0 _arrayName= _array=
|
||||
local delimitor=$'\n' i isDesired=true isAscending=string_ascends top=0 arrayName= array=
|
||||
|
||||
# Parse the options.
|
||||
local OPTIND=1
|
||||
while getopts :0nrRd:f:F:c:C:tT:a: opt; do
|
||||
while getopts :0nrd:f:F:c:C:tT:a: opt; do
|
||||
case $opt in
|
||||
0) _delimitor=$'\0' ;;
|
||||
d) _delimitor=$OPTARG ;;
|
||||
n) _comparator=number_ascends ;;
|
||||
R) _comparator=random_ascends ;;
|
||||
t) _comparator=mtime_ascends ;;
|
||||
f) _isDesired=$OPTARG ;;
|
||||
F) _isDesired=bash_desired _bash_desired_code=$OPTARG ;;
|
||||
c) _comparator=$OPTARG ;;
|
||||
C) _comparator=bash_ascends _bash_ascends_code=$OPTARG ;;
|
||||
r) _comparator_ascends=0 ;;
|
||||
T) _top=$OPTARG ;;
|
||||
a) _arrayName=$OPTARG _array=$_arrayName[@] ;;
|
||||
0) delimitor=$'\0' ;;
|
||||
d) delimitor=$OPTARG ;;
|
||||
n) isAscending=number_ascends ;;
|
||||
r) isAscending=random_ascends ;;
|
||||
t) isAscending=mtime_ascends ;;
|
||||
f) isDesired=$OPTARG ;;
|
||||
F) isDesired=bash_desired bash_desired_code=$OPTARG ;;
|
||||
c) isAscending=$OPTARG ;;
|
||||
C) isAscending=bash_ascends bash_ascends_code=$OPTARG ;;
|
||||
T) top=$OPTARG ;;
|
||||
a) arrayName=$OPTARG array=$arrayName[@] ;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
# Get the elements.
|
||||
local _elements=() _element
|
||||
if [[ $_arrayName ]]; then
|
||||
for _element in "${!_array}"; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
local elements=() element
|
||||
if [[ $arrayName ]]; then
|
||||
for element in "${!array}"; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
done
|
||||
elif (( $# )); then
|
||||
for _element; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
for element; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
done
|
||||
else
|
||||
while IFS= read -r -d "$_delimitor" _element; do
|
||||
"$_isDesired" "$_element" && _elements+=("$_element")
|
||||
while IFS= read -r -d "$delimitor" element; do
|
||||
"$isDesired" "$element" && elements+=("$element")
|
||||
done
|
||||
fi
|
||||
|
||||
# Iterate in reverse order.
|
||||
for (( _i = 1; _i < ${#_elements[@]}; ++_i )); do
|
||||
for (( _j = _i; _j > 0; --_j )); do
|
||||
_element=${_elements[_j]}
|
||||
if ( (( _comparator_ascends )) && "$_comparator" "$_element" "${_elements[_j-1]}" ) ||
|
||||
( (( ! _comparator_ascends )) && ! "$_comparator" "$_element" "${_elements[_j-1]}" ); then
|
||||
_elements[_j]=${_elements[_j-1]}
|
||||
_elements[_j-1]=$_element
|
||||
for (( i = 1; i < ${#elements[@]}; ++i )); do
|
||||
for (( j = i; j > 0; --j )); do
|
||||
element=${elements[j]}
|
||||
if "$isAscending" "$element" "${elements[j-1]}"; then
|
||||
elements[j]=${elements[j-1]}
|
||||
elements[j-1]=$element
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
(( _top )) || _top=${#_elements[@]}
|
||||
if [[ $_array ]]; then
|
||||
declare -ga "$_array=($(printf '%q ' "${_elements[@]:0:_top}"))"
|
||||
(( top )) || top=${#elements[@]}
|
||||
if [[ $array ]]; then
|
||||
declare -ga "$array=($(printf '%q ' "${elements[@]:0:top}"))"
|
||||
else
|
||||
printf "%s${_delimitor:-\0}" "${_elements[@]:0:_top}"
|
||||
printf "%s${delimitor:-\0}" "${elements[@]:0:top}"
|
||||
fi
|
||||
} # _____________________________________________________________________
|
||||
string_ascends() { [[ $1 < $2 ]]; }
|
||||
@ -1069,28 +1004,8 @@ exists_desired() { [[ -e $1 ]]; }
|
||||
line_desired() { [[ $1 ]]; }
|
||||
code_desired() { line_desired "$1" && ! comment_desired "$1"; }
|
||||
comment_desired() { line_desired "$1" && [[ $1 = @(#|//|/\*)* ]]; }
|
||||
bash_desired() { bash -c "$_bash_desired_code" -- "$@"; }
|
||||
bash_ascends() { bash -c "$_bash_ascends_code" -- "$@"; }
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ AddTrap _____________________________________________________________|
|
||||
#
|
||||
# addtrap signal command-format [args...]
|
||||
#
|
||||
# Add a command to the current commands executed when a signal is received by the bash process.
|
||||
#
|
||||
# The command-format is a printf-style format for the command to execute. The optional
|
||||
# args are interpolated into the command-format by bash's built-in printf.
|
||||
#
|
||||
addtrap() {
|
||||
local signal=$1 cmd=$2; shift 2
|
||||
printf -v cmd "$cmd" "$@"
|
||||
|
||||
read _ _ oldtrap <<< "$(trap -p "$signal")"
|
||||
eval "declare oldtrap=${oldtrap% *}"
|
||||
trap "$oldtrap${oldtrap:+; }$cmd" "$signal"
|
||||
}
|
||||
bash_desired() { bash -c "$bash_desired_code" -- "$@"; }
|
||||
bash_ascends() { bash -c "$bash_ascends_code" -- "$@"; }
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
@ -1316,17 +1231,18 @@ showHelp() {
|
||||
shquote() {
|
||||
|
||||
# Initialize the defaults.
|
||||
local OPTIND=1 arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single always=0
|
||||
local arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single always=0
|
||||
|
||||
# Parse the options.
|
||||
while getopts :eda arg; do
|
||||
case $arg in
|
||||
e) type=escape ;;
|
||||
d) type=double ;;
|
||||
a) always=1 ;;
|
||||
while [[ $1 = -* ]]; do
|
||||
case $1 in
|
||||
-e) type=escape ;;
|
||||
-d) type=double ;;
|
||||
-a) always=1 ;;
|
||||
--) shift; break ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
# Print out each argument, quoting it properly.
|
||||
for arg; do
|
||||
@ -1431,29 +1347,6 @@ shorten() {
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ CdSource ________________________________________________________________|
|
||||
#
|
||||
# cdsource [file]
|
||||
#
|
||||
# Change the current directory into the directory where the file is located, resolving symlinks.
|
||||
#
|
||||
cdsource() {
|
||||
local source=${1:-${BASH_SOURCE[1]}}
|
||||
|
||||
while [[ $source ]]; do
|
||||
[[ $source = */* ]] && cd "${source%/*}"
|
||||
|
||||
if [[ -L ${source##*/} ]]; then
|
||||
source=$(readlink "${source##*/}")
|
||||
else
|
||||
source=
|
||||
fi
|
||||
done
|
||||
} # _____________________________________________________________________
|
||||
|
||||
|
||||
|
||||
# ______________________________________________________________________
|
||||
# |__ Up ________________________________________________________________|
|
||||
#
|
||||
@ -1673,7 +1566,7 @@ stackTrace() {
|
||||
|
||||
# ______________________________________________________________________
|
||||
# | |
|
||||
# | .: ENTRY POINT :. |
|
||||
# | .:: ENTRY POINT ::. |
|
||||
# |______________________________________________________________________|
|
||||
|
||||
# Make sure this file is sourced and not executed.
|
||||
@ -1693,6 +1586,6 @@ stackTrace() {
|
||||
}
|
||||
|
||||
:
|
||||
: .: END SOURCING :.
|
||||
: .:: END SOURCING ::.
|
||||
: ______________________________________________________________________
|
||||
:
|
264
MasterPassword/C/build
Executable file
@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
### CONFIGURATION
|
||||
|
||||
# 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
@ -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"
|
@ -23,7 +23,7 @@ bindir=$(ask -d "$bindir" "What bin directory should I install to?")
|
||||
[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit
|
||||
|
||||
# Install Master Password.
|
||||
install -m555 mpw "$bindir"
|
||||
install mpw "$bindir"
|
||||
[[ ! -e "$bindir/bashlib" ]] && install bashlib "$bindir" ||:
|
||||
|
||||
# Convenience bash function.
|
||||
@ -45,20 +45,9 @@ fi
|
||||
echo
|
||||
|
||||
inf "You can also save your user name in ~/.bashrc. Leave blank to skip this step."
|
||||
if MPW_FULLNAME=$(ask "Your full name:") && [[ $MPW_FULLNAME ]] ; then
|
||||
printf 'export MPW_FULLNAME=%q\n' "$MPW_FULLNAME" >> ~/.bashrc
|
||||
fi
|
||||
inf "If you have an askpass program you'd like to use, you can specify it here."
|
||||
inf "An askpass program provides a graphical interface for entering things like your master password."
|
||||
inf "Leave blank to skip this step and enter passwords using the terminal."
|
||||
if [[ ! $MPW_ASKPASS ]] && hash ssh-askpass 2>/dev/null; then
|
||||
MPW_ASKPASS=ssh-askpass
|
||||
fi
|
||||
if MPW_ASKPASS=$(ask +"$MPW_ASKPASS" "askpass program:") && [[ $MPW_ASKPASS ]] ; then
|
||||
printf 'export MPW_ASKPASS=%q\n' "$MPW_ASKPASS" >> ~/.bashrc
|
||||
if MP_USERNAME=$(ask "Your full name:") && [[ $MP_USERNAME ]] ; then
|
||||
printf 'export MP_USERNAME=%q\n' "$MP_USERNAME" >> ~/.bashrc
|
||||
fi
|
||||
echo
|
||||
|
||||
inf "Shell features installed."
|
||||
inf "To load these convenience features into your already running shell, type: source ~/.bashrc"
|
||||
inf "To begin using Master Password, type: mpw -h or mpw my-site-name"
|
||||
inf "To begin using Master Password, type: mpw [site name]"
|
3
MasterPassword/C/lib/bcrypt/.source
Normal 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
|
38
MasterPassword/C/lib/scrypt-osx.patch
Normal file
@ -0,0 +1,38 @@
|
||||
diff -ruN /Users/lhunath/.src/scrypt/Makefile ./Makefile
|
||||
--- /Users/lhunath/.src/scrypt/Makefile 2014-05-02 11:28:58.000000000 -0400
|
||||
+++ ./Makefile 2014-05-02 12:07:27.000000000 -0400
|
||||
@@ -2,11 +2,11 @@
|
||||
VER?= nosse
|
||||
SRCS= main.c
|
||||
LDADD+= -lcrypto
|
||||
-WARNS?= 6
|
||||
+WARNS?= 0
|
||||
|
||||
# We have a config file for FreeBSD
|
||||
CFLAGS += -I .
|
||||
-CFLAGS += -DCONFIG_H_FILE=\"config_freebsd.h\"
|
||||
+CFLAGS += -DCONFIG_H_FILE=\"config_osx.h\"
|
||||
|
||||
# Include all possible object files containing built scrypt code.
|
||||
CLEANFILES += crypto_scrypt-ref.o
|
||||
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
|
||||
--- /Users/lhunath/.src/scrypt/lib/util/memlimit.c 2014-05-02 11:28:58.000000000 -0400
|
||||
+++ ./lib/util/memlimit.c 2014-05-02 11:52:42.000000000 -0400
|
||||
@@ -75,7 +75,7 @@
|
||||
* have returned to us.
|
||||
*/
|
||||
if (usermemlen == sizeof(uint64_t))
|
||||
- usermem = *(uint64_t *)usermembuf;
|
||||
+ usermem = *(uint64_t *)(void *)usermembuf;
|
||||
else if (usermemlen == sizeof(uint32_t))
|
||||
usermem = SIZE_MAX;
|
||||
else
|
||||
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
|
||||
--- /Users/lhunath/.src/scrypt/config_osx.h 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ config_osx.h 2014-05-02 12:06:55.000000000 -0400
|
||||
@@ -0,0 +1,5 @@
|
||||
+/* A default configuration for FreeBSD, used if there is no config.h. */
|
||||
+
|
||||
+#define HAVE_POSIX_MEMALIGN 1
|
||||
+#define HAVE_SYSCTL_HW_USERMEM 1
|
||||
+#define HAVE_SYS_PARAM_H 1
|
4
MasterPassword/C/lib/scrypt/.source
Normal file
@ -0,0 +1,4 @@
|
||||
home=https://code.google.com/p/scrypt/
|
||||
svn=http://scrypt.googlecode.com/svn
|
||||
pkg=http://masterpasswordapp.com/libscrypt-b12b554.tar.gz
|
||||
pkg_sha256=c726daec68a345e420896f005394a948dc5a6924713ed94b684c856d4c247f0b
|
187
MasterPassword/C/mpw-bench.c
Normal 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;
|
||||
}
|
@ -5,7 +5,7 @@ mpw() {
|
||||
if hash pbcopy 2>/dev/null; then
|
||||
pbcopy
|
||||
elif hash xclip 2>/dev/null; then
|
||||
xclip -selection clip
|
||||
xclip
|
||||
else
|
||||
cat; echo 2>/dev/null
|
||||
return
|
||||
@ -17,8 +17,8 @@ mpw() {
|
||||
:| _copy 2>/dev/null
|
||||
|
||||
# Ask for the user's name and password if not yet known.
|
||||
MPW_FULLNAME=${MPW_FULLNAME:-$(ask 'Your Full Name:')}
|
||||
MP_USERNAME=${MP_USERNAME:-$(ask 'Your Full Name:')}
|
||||
|
||||
# Start Master Password and copy the output.
|
||||
printf %s "$(MPW_FULLNAME=$MPW_FULLNAME command mpw "$@")" | _copy
|
||||
printf %s "$(MP_USERNAME=$MP_USERNAME command mpw "$@")" | _copy
|
||||
}
|
298
MasterPassword/C/mpw.c
Normal file
@ -0,0 +1,298 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__linux__)
|
||||
#include <linux/fs.h>
|
||||
#elif defined(__CYGWIN__)
|
||||
#include <cygwin/fs.h>
|
||||
#else
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#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 "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
|
||||
#define MP_dkLen 64
|
||||
#define MP_hash PearlHashSHA256
|
||||
|
||||
#define MP_env_username "MP_USERNAME"
|
||||
#define MP_env_sitetype "MP_SITETYPE"
|
||||
#define MP_env_sitecounter "MP_SITECOUNTER"
|
||||
|
||||
void usage() {
|
||||
fprintf(stderr, "Usage: mpw [-u name] [-t type] [-c counter] site\n\n");
|
||||
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' 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"
|
||||
" 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);
|
||||
}
|
||||
|
||||
char *homedir(const char *filename) {
|
||||
char *homedir = NULL;
|
||||
#if defined(__CYGWIN__)
|
||||
homedir = getenv("USERPROFILE");
|
||||
if (!homedir) {
|
||||
const char *homeDrive = getenv("HOMEDRIVE");
|
||||
const char *homePath = getenv("HOMEPATH");
|
||||
homedir = char[strlen(homeDrive) + strlen(homePath) + 1];
|
||||
sprintf(homedir, "%s/%s", homeDrive, homePath);
|
||||
}
|
||||
#else
|
||||
struct passwd* passwd = getpwuid(getuid());
|
||||
if (passwd)
|
||||
homedir = passwd->pw_dir;
|
||||
if (!homedir)
|
||||
homedir = getenv("HOME");
|
||||
#endif
|
||||
if (!homedir)
|
||||
homedir = getcwd(NULL, 0);
|
||||
|
||||
char *homefile = NULL;
|
||||
asprintf(&homefile, "%s/%s", homedir, filename);
|
||||
return homefile;
|
||||
}
|
||||
|
||||
int main(int argc, char *const argv[]) {
|
||||
|
||||
if (argc < 2)
|
||||
usage();
|
||||
|
||||
// Read the environment.
|
||||
const char *userName = getenv( MP_env_username );
|
||||
const char *masterPassword = NULL;
|
||||
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.
|
||||
for (int opt; (opt = getopt(argc, argv, "u:t:c:v:C:h")) != -1;)
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
userName = optarg;
|
||||
break;
|
||||
case 't':
|
||||
siteTypeString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
siteVariantString = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
siteContextString = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case '?':
|
||||
switch (optopt) {
|
||||
case 'u':
|
||||
fprintf(stderr, "Missing user name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 't':
|
||||
fprintf(stderr, "Missing type name to option: -%c\n", optopt);
|
||||
break;
|
||||
case 'c':
|
||||
fprintf(stderr, "Missing counter value to option: -%c\n", optopt);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option: -%c\n", optopt);
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if (optind < argc)
|
||||
siteName = argv[optind];
|
||||
|
||||
// Convert and validate input.
|
||||
if (!userName) {
|
||||
fprintf(stderr, "Missing user name.\n");
|
||||
return 1;
|
||||
}
|
||||
trc("userName: %s\n", userName);
|
||||
if (!siteName) {
|
||||
fprintf(stderr, "Missing site name.\n");
|
||||
return 1;
|
||||
}
|
||||
trc("siteName: %s\n", siteName);
|
||||
if (siteCounterString)
|
||||
siteCounter = atoi( siteCounterString );
|
||||
if (siteCounter < 1) {
|
||||
fprintf(stderr, "Invalid site counter: %d\n", siteCounter);
|
||||
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);
|
||||
|
||||
// Read the master password.
|
||||
char *mpwConfigPath = homedir(".mpw");
|
||||
if (!mpwConfigPath) {
|
||||
fprintf(stderr, "Couldn't resolve path for configuration file: %d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
trc("mpwConfigPath: %s\n", mpwConfigPath);
|
||||
FILE *mpwConfig = fopen(mpwConfigPath, "r");
|
||||
free(mpwConfigPath);
|
||||
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.
|
||||
const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
|
||||
trc("key scope: %s\n", mpKeyScope);
|
||||
const uint32_t n_userNameLength = htonl(strlen(userName));
|
||||
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, 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)
|
||||
abort();
|
||||
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
|
||||
|
||||
// Calculate the master key.
|
||||
uint8_t *masterKey = (uint8_t *)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);
|
||||
trc("masterPassword Hex: %s\n", Hex(masterPassword, strlen(masterPassword)));
|
||||
trc("masterPassword ID: %s\n", IDForBuf(masterPassword, strlen(masterPassword)));
|
||||
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);
|
||||
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, 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, %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];
|
||||
HMAC_SHA256_Buf(masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed);
|
||||
memset(masterKey, 0, MP_dkLen);
|
||||
memset(sitePasswordInfo, 0, sitePasswordInfoLength);
|
||||
free(masterKey);
|
||||
free(sitePasswordInfo);
|
||||
trc("sitePasswordSeed ID: %s\n", IDForBuf(sitePasswordSeed, 32));
|
||||
|
||||
// Determine the cipher.
|
||||
const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
|
||||
trc("type %s, cipher: %s\n", siteTypeString, cipher);
|
||||
if (strlen(cipher) > 32)
|
||||
abort();
|
||||
|
||||
// Encode the password from the seed using the cipher.
|
||||
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]);
|
||||
}
|
||||
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
|
||||
|
||||
// Output the password.
|
||||
fprintf( stdout, "%s\n", sitePassword );
|
||||
return 0;
|
||||
}
|
190
MasterPassword/C/types.c
Normal file
@ -0,0 +1,190 @@
|
||||
//
|
||||
// MPTypes.h
|
||||
// MasterPassword
|
||||
//
|
||||
// Created by Maarten Billemont on 02/01/12.
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <alg/sha256.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
const MPElementType TypeWithName(const char *typeName) {
|
||||
char lowerTypeName[strlen(typeName)];
|
||||
strcpy(lowerTypeName, typeName);
|
||||
for (char *tN = lowerTypeName; *tN; ++tN)
|
||||
*tN = tolower(*tN);
|
||||
|
||||
if (0 == strcmp(lowerTypeName, "x") || 0 == strcmp(lowerTypeName, "max") || 0 == strcmp(lowerTypeName, "maximum"))
|
||||
return MPElementTypeGeneratedMaximum;
|
||||
if (0 == strcmp(lowerTypeName, "l") || 0 == strcmp(lowerTypeName, "long"))
|
||||
return MPElementTypeGeneratedLong;
|
||||
if (0 == strcmp(lowerTypeName, "m") || 0 == strcmp(lowerTypeName, "med") || 0 == strcmp(lowerTypeName, "medium"))
|
||||
return MPElementTypeGeneratedMedium;
|
||||
if (0 == strcmp(lowerTypeName, "b") || 0 == strcmp(lowerTypeName, "basic"))
|
||||
return MPElementTypeGeneratedBasic;
|
||||
if (0 == strcmp(lowerTypeName, "s") || 0 == strcmp(lowerTypeName, "short"))
|
||||
return MPElementTypeGeneratedShort;
|
||||
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();
|
||||
}
|
||||
|
||||
const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
if (!(type & MPElementTypeClassGenerated)) {
|
||||
fprintf(stderr, "Not a generated type: %d", type);
|
||||
abort();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MPElementTypeGeneratedMaximum: {
|
||||
const char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
|
||||
return ciphers[seedByte % 2];
|
||||
}
|
||||
case MPElementTypeGeneratedLong: {
|
||||
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: {
|
||||
const char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
|
||||
return ciphers[seedByte % 2];
|
||||
}
|
||||
case MPElementTypeGeneratedBasic: {
|
||||
const char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
|
||||
return ciphers[seedByte % 3];
|
||||
}
|
||||
case MPElementTypeGeneratedShort: {
|
||||
return "Cvcn";
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
case 'V': {
|
||||
classCharacters = "AEIOU";
|
||||
break;
|
||||
}
|
||||
case 'C': {
|
||||
classCharacters = "BCDFGHJKLMNPQRSTVWXYZ";
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
classCharacters = "aeiou";
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
classCharacters = "bcdfghjklmnpqrstvwxyz";
|
||||
break;
|
||||
}
|
||||
case 'A': {
|
||||
classCharacters = "AEIOUBCDFGHJKLMNPQRSTVWXYZ";
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
classCharacters = "0123456789";
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
classCharacters = "@&%?,=[]_:-+*$#!'^~;()/.";
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()";
|
||||
break;
|
||||
}
|
||||
case ' ': {
|
||||
classCharacters = " ";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown character class: %c", characterClass);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return classCharacters[seedByte % strlen(classCharacters)];
|
||||
}
|
||||
const char *IDForBuf(const void *buf, size_t length) {
|
||||
uint8_t hash[32];
|
||||
SHA256_Buf(buf, length, hash);
|
||||
|
||||
char *id = (char *)calloc(65, sizeof(char));
|
||||
for (int kH = 0; kH < 32; kH++)
|
||||
sprintf(&(id[kH * 2]), "%02X", hash[kH]);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
const char *Hex(const void *buf, size_t length) {
|
||||
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;
|
||||
}
|
59
MasterPassword/C/types.h
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// MPTypes.h
|
||||
// MasterPassword
|
||||
//
|
||||
// Created by Maarten Billemont on 02/01/12.
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
/** 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. */
|
||||
MPElementTypeClassGenerated = 1 << 4,
|
||||
/** Store the password. */
|
||||
MPElementTypeClassStored = 1 << 5,
|
||||
} MPElementTypeClass;
|
||||
|
||||
typedef enum {
|
||||
/** Export the key-protected content data. */
|
||||
MPElementFeatureExportContent = 1 << 10,
|
||||
/** Never export content. */
|
||||
MPElementFeatureDevicePrivate = 1 << 11,
|
||||
} MPElementFeature;
|
||||
|
||||
typedef enum {
|
||||
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
|
||||
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,
|
||||
} MPElementType;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define trc(...) fprintf(stderr, __VA_ARGS__)
|
||||
#else
|
||||
#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);
|
||||
const char *IDForBuf(const void *buf, size_t length);
|
||||
const char *Hex(const void *buf, size_t length);
|
||||
|
0
MasterPassword/Java/.mvn-tools
Normal file
49
MasterPassword/Java/masterpassword-algorithm/pom.xml
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Algorithm Implementation</name>
|
||||
<description>The implementation of the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-system</artifactId>
|
||||
<version>1.6-p6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-crypto</artifactId>
|
||||
<version>1.6-p6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>net.sf.plist</groupId>
|
||||
<artifactId>property-list</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>scrypt</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,14 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementFeature {
|
||||
|
||||
/** Export the key-protected content data. */
|
||||
ExportContent,
|
||||
/** Never export content. */
|
||||
DevicePrivate,
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementType {
|
||||
|
||||
GeneratedMaximum( "Maximum Security Password", "Maximum", "20 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedLong( "Long Password", "Long", "Copy-friendly, 14 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedMedium( "Medium Password", "Medium", "Copy-friendly, 8 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedBasic( "Basic Password", "Basic", "8 characters, no symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedShort( "Short Password", "Short", "Copy-friendly, 4 characters, no symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedPIN( "PIN", "PIN", "4 numbers.", MPElementTypeClass.Generated ),
|
||||
|
||||
StoredPersonal( "Personal Password", "Personal", "AES-encrypted, exportable.", MPElementTypeClass.Stored,
|
||||
MPElementFeature.ExportContent ),
|
||||
StoredDevicePrivate( "Device Private Password", "Private", "AES-encrypted, not exported.", MPElementTypeClass.Stored,
|
||||
MPElementFeature.DevicePrivate );
|
||||
|
||||
static final Logger logger = Logger.get( MPElementType.class );
|
||||
|
||||
private final MPElementTypeClass typeClass;
|
||||
private final Set<MPElementFeature> typeFeatures;
|
||||
private final String name;
|
||||
private final String shortName;
|
||||
private final String description;
|
||||
|
||||
MPElementType(final String name, final String shortName, final String description, final MPElementTypeClass typeClass,
|
||||
final MPElementFeature... typeFeatures) {
|
||||
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
this.typeClass = typeClass;
|
||||
this.description = description;
|
||||
|
||||
ImmutableSet.Builder<MPElementFeature> typeFeaturesBuilder = ImmutableSet.builder();
|
||||
for (final MPElementFeature typeFeature : typeFeatures) {
|
||||
typeFeaturesBuilder.add( typeFeature );
|
||||
}
|
||||
this.typeFeatures = typeFeaturesBuilder.build();
|
||||
}
|
||||
|
||||
public MPElementTypeClass getTypeClass() {
|
||||
|
||||
return typeClass;
|
||||
}
|
||||
|
||||
public Set<MPElementFeature> getTypeFeatures() {
|
||||
|
||||
return typeFeatures;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name The full or short name of the type we want to look up. It is matched case insensitively.
|
||||
*
|
||||
* @return The type with the given name.
|
||||
*/
|
||||
public static MPElementType forName(final String 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param typeClass The class for which we look up types.
|
||||
*
|
||||
* @return All types that support the given class.
|
||||
*/
|
||||
public static ImmutableList<MPElementType> forClass(final MPElementTypeClass typeClass) {
|
||||
|
||||
ImmutableList.Builder<MPElementType> types = ImmutableList.builder();
|
||||
for (final MPElementType type : values())
|
||||
if (type.getTypeClass() == typeClass)
|
||||
types.add( type );
|
||||
|
||||
return types.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.lyndir.masterpassword.entity.*;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementTypeClass {
|
||||
|
||||
Generated(MPElementGeneratedEntity.class),
|
||||
Stored(MPElementStoredEntity.class);
|
||||
|
||||
private final Class<? extends MPElementEntity> entityClass;
|
||||
|
||||
MPElementTypeClass(final Class<? extends MPElementEntity> entityClass) {
|
||||
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
public Class<? extends MPElementEntity> getEntityClass() {
|
||||
|
||||
return entityClass;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplate extends MetaObject {
|
||||
|
||||
private final List<MPTemplateCharacterClass> template;
|
||||
|
||||
public MPTemplate(final String template, final Map<Character, MPTemplateCharacterClass> characterClasses) {
|
||||
|
||||
ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.<MPTemplateCharacterClass>builder();
|
||||
for (int i = 0; i < template.length(); ++i)
|
||||
builder.add( characterClasses.get( template.charAt( i ) ) );
|
||||
|
||||
this.template = builder.build();
|
||||
}
|
||||
|
||||
public MPTemplate(final List<MPTemplateCharacterClass> template) {
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public MPTemplateCharacterClass getCharacterClassAtIndex(final int index) {
|
||||
|
||||
return template.get( index );
|
||||
}
|
||||
|
||||
public int length() {
|
||||
|
||||
return template.size();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import com.lyndir.lhunath.opal.system.util.ObjectMeta;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplateCharacterClass extends MetaObject {
|
||||
|
||||
private final char identifier;
|
||||
@ObjectMeta(useFor = { })
|
||||
private final char[] characters;
|
||||
|
||||
public MPTemplateCharacterClass(final char identifier, final char[] characters) {
|
||||
|
||||
this.identifier = identifier;
|
||||
this.characters = characters;
|
||||
}
|
||||
|
||||
public char getIdentifier() {
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public char getCharacterAtRollingIndex(final int index) {
|
||||
|
||||
return characters[index % characters.length];
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.sf.plist.*;
|
||||
import net.sf.plist.io.PropertyListException;
|
||||
import net.sf.plist.io.PropertyListParser;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplates extends MetaObject {
|
||||
|
||||
static final Logger logger = Logger.get( MPTemplates.class );
|
||||
|
||||
private final Map<MPElementType, List<MPTemplate>> templates;
|
||||
|
||||
public MPTemplates(final Map<MPElementType, List<MPTemplate>> templates) {
|
||||
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
public static MPTemplates load() {
|
||||
|
||||
return loadFromPList( "ciphers.plist" );
|
||||
}
|
||||
|
||||
public static MPTemplates loadFromPList(final String templateResource) {
|
||||
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
|
||||
Preconditions.checkNotNull( templateStream, "Not found: %s", templateResource );
|
||||
try {
|
||||
NSObject plistObject = PropertyListParser.parse( templateStream );
|
||||
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
|
||||
NSDictionary plist = (NSDictionary) plistObject;
|
||||
|
||||
NSDictionary characterClassesDict = (NSDictionary) plist.get( "MPCharacterClasses" );
|
||||
NSDictionary templatesDict = (NSDictionary) plist.get( "MPElementGeneratedEntity" );
|
||||
|
||||
ImmutableMap.Builder<Character, MPTemplateCharacterClass> characterClassesBuilder = ImmutableMap.builder();
|
||||
for (final Map.Entry<String, NSObject> characterClassEntry : characterClassesDict.entrySet()) {
|
||||
String key = characterClassEntry.getKey();
|
||||
NSObject value = characterClassEntry.getValue();
|
||||
Preconditions.checkState( key.length() == 1 );
|
||||
Preconditions.checkState( NSString.class.isAssignableFrom( value.getClass() ));
|
||||
|
||||
char character = key.charAt( 0 );
|
||||
char[] characterClass = ((NSString)value).getValue().toCharArray();
|
||||
characterClassesBuilder.put( character, new MPTemplateCharacterClass( character, characterClass ) );
|
||||
}
|
||||
ImmutableMap<Character, MPTemplateCharacterClass> characterClasses = characterClassesBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<MPElementType, List<MPTemplate>> templatesBuilder = ImmutableMap.builder();
|
||||
for (final Map.Entry<String, NSObject> template : templatesDict.entrySet()) {
|
||||
String key = template.getKey();
|
||||
NSObject value = template.getValue();
|
||||
Preconditions.checkState( NSArray.class.isAssignableFrom( value.getClass() ) );
|
||||
|
||||
MPElementType type = MPElementType.forName( key );
|
||||
List<NSObject> templateStrings = ((NSArray) value).getValue();
|
||||
|
||||
ImmutableList.Builder<MPTemplate> typeTemplatesBuilder = ImmutableList.<MPTemplate>builder();
|
||||
for (final NSObject templateString : templateStrings)
|
||||
typeTemplatesBuilder.add( new MPTemplate( ((NSString) templateString).getValue(), characterClasses ) );
|
||||
|
||||
templatesBuilder.put( type, typeTemplatesBuilder.build() );
|
||||
}
|
||||
ImmutableMap<MPElementType, List<MPTemplate>> templates = templatesBuilder.build();
|
||||
|
||||
return new MPTemplates( templates );
|
||||
}
|
||||
catch (PropertyListException e) {
|
||||
logger.err( e, "Could not parse templates from: %s", templateResource );
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.err( e, "Could not read templates from: %s", templateResource );
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
finally {
|
||||
Closeables.closeQuietly( templateStream );
|
||||
}
|
||||
}
|
||||
|
||||
public MPTemplate getTemplateForTypeAtRollingIndex(final MPElementType type, final int templateIndex) {
|
||||
|
||||
List<MPTemplate> typeTemplates = templates.get( type );
|
||||
|
||||
return typeTemplates.get( templateIndex % typeTemplates.size() );
|
||||
}
|
||||
|
||||
public static void main(final String... arguments) {
|
||||
|
||||
load();
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
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;
|
||||
import com.lyndir.lhunath.opal.system.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MasterKey {
|
||||
|
||||
@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;
|
||||
private static final int MP_dkLen = 64;
|
||||
private static final Charset MP_charset = Charsets.UTF_8;
|
||||
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
private static final MessageDigests MP_hash = MessageDigests.SHA256;
|
||||
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
|
||||
private static final MPTemplates templates = MPTemplates.load();
|
||||
|
||||
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[] userNameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
|
||||
.order( MP_byteOrder )
|
||||
.putInt( userName.length() )
|
||||
.array();
|
||||
byte[] salt = Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
|
||||
userNameLengthBytes, userName.getBytes( MP_charset ) );
|
||||
|
||||
try {
|
||||
key = SCrypt.scrypt( masterPassword.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
valid = true;
|
||||
|
||||
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 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 String encode(final String name, final MPElementType type, int counter) {
|
||||
|
||||
Preconditions.checkState( valid );
|
||||
Preconditions.checkArgument( type.getTypeClass() == MPElementTypeClass.Generated );
|
||||
Preconditions.checkArgument( !name.isEmpty() );
|
||||
|
||||
if (counter == 0)
|
||||
counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
|
||||
|
||||
byte[] nameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( name.length() ).array();
|
||||
byte[] counterBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( counter ).array();
|
||||
logger.trc( "seed from: hmac-sha256(%s, 'com.lyndir.masterpassword' | %s | %s | %s)", CryptUtils.encodeBase64( key ),
|
||||
CodeUtils.encodeHex( nameLengthBytes ), name, CodeUtils.encodeHex( counterBytes ) );
|
||||
byte[] seed = MP_mac.of( key, Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
|
||||
nameLengthBytes, //
|
||||
name.getBytes( MP_charset ), //
|
||||
counterBytes ) );
|
||||
logger.trc( "seed is: %s", CryptUtils.encodeBase64( seed ) );
|
||||
|
||||
Preconditions.checkState( seed.length > 0 );
|
||||
int templateIndex = seed[0] & 0xFF; // Mask the integer's sign.
|
||||
MPTemplate template = templates.getTemplateForTypeAtRollingIndex( type, templateIndex );
|
||||
logger.trc( "type: %s, template: %s", type, template );
|
||||
|
||||
StringBuilder password = new StringBuilder( template.length() );
|
||||
for (int i = 0; i < template.length(); ++i) {
|
||||
int characterIndex = seed[i + 1] & 0xFF; // Mask the integer's sign.
|
||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||
logger.trc( "class: %s, index: %d, byte: 0x%02X, chosen password character: %s", characterClass, characterIndex, seed[i + 1],
|
||||
passwordCharacter );
|
||||
|
||||
password.append( passwordCharacter );
|
||||
}
|
||||
|
||||
return password.toString();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
|
||||
valid = false;
|
||||
Arrays.fill( key, (byte) 0 );
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementEntity {
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementGeneratedEntity extends MPElementEntity {
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementStoredEntity extends MPElementEntity {
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
../../../../../../MasterPassword/Resources/Data/ciphers.plist
|
@ -1,23 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.lyndir.masterpassword">
|
||||
package="com.lyndir.masterpassword"
|
||||
android:versionCode="1"
|
||||
android:versionName="GIT-SNAPSHOT">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="19" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name">
|
||||
<activity
|
||||
android:name=".EmergencyActivity"
|
||||
android:theme="@style/MPTheme">
|
||||
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=".TestActivity"
|
||||
android:theme="@style/MPTheme" />
|
||||
<activity android:name=".UsersActivity" />
|
||||
</application>
|
||||
|
||||
|
||||
</manifest>
|
||||
|
@ -0,0 +1,3 @@
|
||||
# File used by Eclipse to determine the target system
|
||||
# Project target.
|
||||
target=android-16
|
@ -0,0 +1,8 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
|
||||
public final class BuildConfig {
|
||||
public final static boolean DEBUG = Boolean.parseBoolean(null);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
|
||||
public final class Manifest {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
|
||||
public final class R {
|
||||
}
|
126
MasterPassword/Java/masterpassword-android/pom.xml
Normal file
@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Android</name>
|
||||
<description>An Android application to the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-android</artifactId>
|
||||
<packaging>apk</packaging>
|
||||
|
||||
<!-- BUILD CONFIGURATION -->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
|
||||
<configuration>
|
||||
<zipalign>
|
||||
<verbose>true</verbose>
|
||||
<skip>false</skip>
|
||||
</zipalign>
|
||||
<sdk>
|
||||
<platform>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.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.jakewharton</groupId>
|
||||
<artifactId>butterknife</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<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>android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
</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>
|
||||
|
||||
</project>
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |