2
0

Fancy master password input screen.

[ADDED]     Fancy master password input screen.
[FIXED]     Key size of stored passwords.
[FIXED]     Several UI fixes.
[FIXED]     The counter wasn't correctly added to the cipherKey.
[IMPROVED]  Site style improvements.
[UPDATED]   Site algorithm explanation update.
This commit is contained in:
Maarten Billemont 2012-02-25 15:30:23 +01:00
parent ad9c52896d
commit 039ec9b082
29 changed files with 572 additions and 169 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

After

Width:  |  Height:  |  Size: 172 KiB

View File

@ -19,6 +19,16 @@
DA41A40B14DB3BF100638533 /* guide_page_0.png in Resources */ = {isa = PBXBuildFile; fileRef = DA41A40914DB3BF100638533 /* guide_page_0.png */; };
DA41A40C14DB3BF100638533 /* guide_page_0@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA41A40A14DB3BF100638533 /* guide_page_0@2x.png */; };
DA55B2A214B4EB47001131B7 /* MPSearchDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA55B2A114B4EB46001131B7 /* MPSearchDelegate.m */; };
DA566D2914F8EAF200A6EB2E /* lock_blue.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2014F8EAF200A6EB2E /* lock_blue.png */; };
DA566D2A14F8EAF200A6EB2E /* lock_blue@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2114F8EAF200A6EB2E /* lock_blue@2x.png */; };
DA566D2B14F8EAF200A6EB2E /* lock_green.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2214F8EAF200A6EB2E /* lock_green.png */; };
DA566D2C14F8EAF200A6EB2E /* lock_green@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2314F8EAF200A6EB2E /* lock_green@2x.png */; };
DA566D2D14F8EAF200A6EB2E /* lock_idle.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2414F8EAF200A6EB2E /* lock_idle.png */; };
DA566D2E14F8EAF200A6EB2E /* lock_idle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2514F8EAF200A6EB2E /* lock_idle@2x.png */; };
DA566D2F14F8EAF200A6EB2E /* lock_red.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2614F8EAF200A6EB2E /* lock_red.png */; };
DA566D3014F8EAF200A6EB2E /* lock_red@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D2714F8EAF200A6EB2E /* lock_red@2x.png */; };
DA566D3514F8EB0700A6EB2E /* background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D3314F8EB0700A6EB2E /* background@2x.png */; };
DA566D3714F8EB3B00A6EB2E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = DA566D3614F8EB3B00A6EB2E /* background.png */; };
DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; };
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
@ -671,8 +681,6 @@
DAC781331482AAD800BCF976 /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC780F01482AAD700BCF976 /* WebViewController.m */; };
DADC3C4D14C62B350091CB4D /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DADC3C4C14C62B350091CB4D /* Settings.bundle */; };
DAE2C648148247E500BA6B10 /* MPTypeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE2C646148247E500BA6B10 /* MPTypeViewController.m */; };
DAE998D214C1D2A0002D7C22 /* Content-Backdrop.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9987914C1D2A0002D7C22 /* Content-Backdrop.png */; };
DAE998D314C1D2A0002D7C22 /* Content-Backdrop@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9987A14C1D2A0002D7C22 /* Content-Backdrop@2x.png */; };
DAE998D414C1D2A0002D7C22 /* Bold_Lines.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9987C14C1D2A0002D7C22 /* Bold_Lines.png */; };
DAE998D514C1D2A0002D7C22 /* Box.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9987D14C1D2A0002D7C22 /* Box.png */; };
DAE998D614C1D2A0002D7C22 /* Dashed_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9987E14C1D2A0002D7C22 /* Dashed_Divider.png */; };
@ -711,6 +719,8 @@
DAE998F714C1D2A0002D7C22 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE9989F14C1D2A0002D7C22 /* Icon.png */; };
DAE998F814C1D2A0002D7C22 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE998A014C1D2A0002D7C22 /* Icon@2x.png */; };
DAE998F914C1D2A0002D7C22 /* iTunesArtwork.png in Resources */ = {isa = PBXBuildFile; fileRef = DAE998A114C1D2A0002D7C22 /* iTunesArtwork.png */; };
DAEBC45114F5A4E800987BF6 /* MPUnlockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEBC45014F5A4E800987BF6 /* MPUnlockViewController.m */; };
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEBC45214F6364500987BF6 /* QuartzCore.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -783,6 +793,16 @@
DA41A40A14DB3BF100638533 /* guide_page_0@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "guide_page_0@2x.png"; sourceTree = "<group>"; };
DA55B2A014B4EB46001131B7 /* MPSearchDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSearchDelegate.h; sourceTree = "<group>"; };
DA55B2A114B4EB46001131B7 /* MPSearchDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSearchDelegate.m; sourceTree = "<group>"; };
DA566D2014F8EAF200A6EB2E /* lock_blue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lock_blue.png; sourceTree = "<group>"; };
DA566D2114F8EAF200A6EB2E /* lock_blue@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "lock_blue@2x.png"; sourceTree = "<group>"; };
DA566D2214F8EAF200A6EB2E /* lock_green.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lock_green.png; sourceTree = "<group>"; };
DA566D2314F8EAF200A6EB2E /* lock_green@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "lock_green@2x.png"; sourceTree = "<group>"; };
DA566D2414F8EAF200A6EB2E /* lock_idle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lock_idle.png; sourceTree = "<group>"; };
DA566D2514F8EAF200A6EB2E /* lock_idle@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "lock_idle@2x.png"; sourceTree = "<group>"; };
DA566D2614F8EAF200A6EB2E /* lock_red.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lock_red.png; sourceTree = "<group>"; };
DA566D2714F8EAF200A6EB2E /* lock_red@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "lock_red@2x.png"; sourceTree = "<group>"; };
DA566D3314F8EB0700A6EB2E /* background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "background@2x.png"; sourceTree = "<group>"; };
DA566D3614F8EB3B00A6EB2E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = "<group>"; };
DA5BFA44147E415C00F98B1E /* MasterPassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MasterPassword.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@ -1442,8 +1462,6 @@
DAC780F01482AAD700BCF976 /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = "<group>"; };
DADC3C4C14C62B350091CB4D /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
DAE2C646148247E500BA6B10 /* MPTypeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTypeViewController.m; sourceTree = "<group>"; };
DAE9987914C1D2A0002D7C22 /* Content-Backdrop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Content-Backdrop.png"; path = "Resources/Content-Backdrop.png"; sourceTree = "<group>"; };
DAE9987A14C1D2A0002D7C22 /* Content-Backdrop@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Content-Backdrop@2x.png"; path = "Resources/Content-Backdrop@2x.png"; sourceTree = "<group>"; };
DAE9987C14C1D2A0002D7C22 /* Bold_Lines.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Bold_Lines.png; sourceTree = "<group>"; };
DAE9987D14C1D2A0002D7C22 /* Box.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Box.png; sourceTree = "<group>"; };
DAE9987E14C1D2A0002D7C22 /* Dashed_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dashed_Divider.png; sourceTree = "<group>"; };
@ -1482,6 +1500,9 @@
DAE9989F14C1D2A0002D7C22 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon.png; path = Resources/Icon.png; sourceTree = "<group>"; };
DAE998A014C1D2A0002D7C22 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon@2x.png"; path = "Resources/Icon@2x.png"; sourceTree = "<group>"; };
DAE998A114C1D2A0002D7C22 /* iTunesArtwork.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = iTunesArtwork.png; path = Resources/iTunesArtwork.png; sourceTree = "<group>"; };
DAEBC44F14F5A4E800987BF6 /* MPUnlockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUnlockViewController.h; sourceTree = "<group>"; };
DAEBC45014F5A4E800987BF6 /* MPUnlockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUnlockViewController.m; sourceTree = "<group>"; };
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -1489,6 +1510,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DAEBC45314F6364500987BF6 /* QuartzCore.framework in Frameworks */,
DA95D5F214DF0B2C008D1B94 /* MessageUI.framework in Frameworks */,
DA95D5ED14DF08AF008D1B94 /* libInAppSettingsKit.a in Frameworks */,
DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */,
@ -1900,6 +1922,32 @@
name = Products;
sourceTree = "<group>";
};
DA566D1E14F8EAF200A6EB2E /* Lock */ = {
isa = PBXGroup;
children = (
DA566D2014F8EAF200A6EB2E /* lock_blue.png */,
DA566D2114F8EAF200A6EB2E /* lock_blue@2x.png */,
DA566D2214F8EAF200A6EB2E /* lock_green.png */,
DA566D2314F8EAF200A6EB2E /* lock_green@2x.png */,
DA566D2414F8EAF200A6EB2E /* lock_idle.png */,
DA566D2514F8EAF200A6EB2E /* lock_idle@2x.png */,
DA566D2614F8EAF200A6EB2E /* lock_red.png */,
DA566D2714F8EAF200A6EB2E /* lock_red@2x.png */,
);
name = Lock;
path = Resources/Lock;
sourceTree = "<group>";
};
DA566D3114F8EB0700A6EB2E /* Background */ = {
isa = PBXGroup;
children = (
DA566D3614F8EB3B00A6EB2E /* background.png */,
DA566D3314F8EB0700A6EB2E /* background@2x.png */,
);
name = Background;
path = Resources/Background;
sourceTree = "<group>";
};
DA5BFA39147E415C00F98B1E = {
isa = PBXGroup;
children = (
@ -1931,6 +1979,7 @@
DA5BFA47147E415C00F98B1E /* Frameworks */ = {
isa = PBXGroup;
children = (
DAEBC45214F6364500987BF6 /* QuartzCore.framework */,
DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */,
DAC632871486D95D0075AEA5 /* Security.framework */,
DA5BFA48147E415C00F98B1E /* UIKit.framework */,
@ -1945,8 +1994,10 @@
isa = PBXGroup;
children = (
DA8E8E4714DDA62D0044257E /* MasterPassword.entitlements */,
DA5BFA51147E415C00F98B1E /* Supporting Files */,
DA7C28A214AF02A000491972 /* Models */,
DA7C28A314AF02B100491972 /* Data */,
DADC3C4C14C62B350091CB4D /* Settings.bundle */,
DA5BFA59147E415C00F98B1E /* MPAppDelegate.h */,
DA5BFA5A147E415C00F98B1E /* MPAppDelegate.m */,
DA5BFA65147E415C00F98B1E /* MPMainViewController.h */,
@ -1957,12 +2008,12 @@
DA55B2A114B4EB46001131B7 /* MPSearchDelegate.m */,
DA95D5FC14DF295F008D1B94 /* MPTypeViewController.h */,
DAE2C646148247E500BA6B10 /* MPTypeViewController.m */,
DAEBC44F14F5A4E800987BF6 /* MPUnlockViewController.h */,
DAEBC45014F5A4E800987BF6 /* MPUnlockViewController.m */,
DA007F5014B24DCC00251337 /* MPConfig.h */,
DA95D5F914DF295E008D1B94 /* MPConfig.m */,
DA95D5FA14DF295E008D1B94 /* MPTypes.h */,
DA95D5FB14DF295F008D1B94 /* MPTypes.m */,
DADC3C4C14C62B350091CB4D /* Settings.bundle */,
DA5BFA51147E415C00F98B1E /* Supporting Files */,
);
path = MasterPassword;
sourceTree = "<group>";
@ -1970,6 +2021,8 @@
DA5BFA51147E415C00F98B1E /* Supporting Files */ = {
isa = PBXGroup;
children = (
DA566D3114F8EB0700A6EB2E /* Background */,
DA566D1E14F8EAF200A6EB2E /* Lock */,
DA8E8E4514DD7C1D0044257E /* logo-bare.png */,
DA6556F714D730B700841C99 /* Guide */,
DAA3B80414CDBBC600F35AF6 /* jquery-1.6.1.min.js */,
@ -1977,8 +2030,6 @@
DA0B951214C37486001D4EB1 /* Insignia */,
DA0B951014C2D69E001D4EB1 /* help.html */,
DAE998FA14C1D3F9002D7C22 /* Automaton */,
DAE9987914C1D2A0002D7C22 /* Content-Backdrop.png */,
DAE9987A14C1D2A0002D7C22 /* Content-Backdrop@2x.png */,
DAE9987B14C1D2A0002D7C22 /* Dividers */,
DAE9989B14C1D2A0002D7C22 /* Icon-72.png */,
DAE9989C14C1D2A0002D7C22 /* Icon-Small-50.png */,
@ -2671,7 +2722,7 @@
DA5BFA3B147E415C00F98B1E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0420;
LastUpgradeCheck = 0430;
ORGANIZATIONNAME = Lyndir;
};
buildConfigurationList = DA5BFA3E147E415C00F98B1E /* Build configuration list for PBXProject "MasterPassword" */;
@ -2738,8 +2789,6 @@
DA007F5514B25EE100251337 /* ciphers.plist in Resources */,
DA5DB7A614BE4B19002DD256 /* Default.png in Resources */,
DA5DB7A814BE4B4B002DD256 /* Default@2x.png in Resources */,
DAE998D214C1D2A0002D7C22 /* Content-Backdrop.png in Resources */,
DAE998D314C1D2A0002D7C22 /* Content-Backdrop@2x.png in Resources */,
DAE998D414C1D2A0002D7C22 /* Bold_Lines.png in Resources */,
DAE998D514C1D2A0002D7C22 /* Box.png in Resources */,
DAE998D614C1D2A0002D7C22 /* Dashed_Divider.png in Resources */,
@ -3299,6 +3348,16 @@
DA95D5F614DF0B9F008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib in Resources */,
DA95D5F714DF0B9F008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib in Resources */,
DA95D5F814DF0B9F008D1B94 /* IASKSpecifierValuesView.xib in Resources */,
DA566D2914F8EAF200A6EB2E /* lock_blue.png in Resources */,
DA566D2A14F8EAF200A6EB2E /* lock_blue@2x.png in Resources */,
DA566D2B14F8EAF200A6EB2E /* lock_green.png in Resources */,
DA566D2C14F8EAF200A6EB2E /* lock_green@2x.png in Resources */,
DA566D2D14F8EAF200A6EB2E /* lock_idle.png in Resources */,
DA566D2E14F8EAF200A6EB2E /* lock_idle@2x.png in Resources */,
DA566D2F14F8EAF200A6EB2E /* lock_red.png in Resources */,
DA566D3014F8EAF200A6EB2E /* lock_red@2x.png in Resources */,
DA566D3514F8EB0700A6EB2E /* background@2x.png in Resources */,
DA566D3714F8EB3B00A6EB2E /* background.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3315,8 +3374,8 @@
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = "/usr/bin/env bash";
shellScript = "PATH+=:/usr/libexec\nset -e\n\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n\n PlistBuddy -c \"Set :$key $value\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :$key\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n\n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\nbuild=$(git describe --tags --always --dirty --long)\ntag=$(git describe --tags | sed 's/-[^-]*-[^-]*$//')\n\nsetPlistWithKey CFBundleVersion \"$build\"\nsetPlistWithKey CFBundleShortVersionString \"$tag\"\n\nsetSettingWithTitle \"Build\" \"$build\"\nsetSettingWithTitle \"Version\" \"$tag\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n";
shellPath = "/bin/bash -e";
shellScript = "PATH+=:/usr/libexec\n\nsetPlistWithKey() {\n local key=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n\n PlistBuddy -c \"Set :$key $value\" \"$plist\"\n}\ngetPlistWithKey() {\n local key=$1 plist=${2:-\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"}\n \n PlistBuddy -c \"Print :$key\" \"$plist\"\n}\nsetSettingWithTitle() {\n local i title=$1 value=$2 plist=${3:-\"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Settings.bundle/Root.plist\"}\n \n for (( i=0; 1; ++i )); do\n PlistBuddy -c \"Print :PreferenceSpecifiers:$i\" \"$plist\" &>/dev/null || break\n echo \"Checking preference specifier $i\"\n \n [[ $(PlistBuddy -c \"Print :PreferenceSpecifiers:$i:Title\" \"$plist\" 2>/dev/null) = $title ]] || continue\n\n echo \"Correct title, setting value.\"\n PlistBuddy -c \"Set :PreferenceSpecifiers:$i:DefaultValue $value\" \"$plist\"\n break\n done\n}\n\nbuild=$(git describe --tags --always --dirty --long)\ntag=$(git describe --tags | sed 's/-\\([^-]*\\)-[^-]*$/.\\1/')\n\nsetPlistWithKey CFBundleVersion \"$build\"\nsetPlistWithKey CFBundleShortVersionString \"$tag\"\n\nsetSettingWithTitle \"Build\" \"$build\"\nsetSettingWithTitle \"Version\" \"$tag\"\nsetSettingWithTitle \"Copyright\" \"$(getPlistWithKey NSHumanReadableCopyright)\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -3339,6 +3398,7 @@
DA65570614D731F000841C99 /* MPGuideViewController.m in Sources */,
DA95D5FD14DF295F008D1B94 /* MPConfig.m in Sources */,
DA95D5FE14DF295F008D1B94 /* MPTypes.m in Sources */,
DAEBC45114F5A4E800987BF6 /* MPUnlockViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -39,11 +40,12 @@
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Production"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -39,11 +40,12 @@
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
@ -56,6 +58,11 @@
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
<AdditionalOption
key = "NSZombieEnabled"
value = "YES"
isEnabled = "YES">
</AdditionalOption>
</AdditionalOptions>
</LaunchAction>
<ProfileAction

View File

@ -26,6 +26,8 @@
- (void)showGuide;
- (void)loadKeyPhrase;
- (void)forgetKeyPhrase;
- (NSData *)keyPhraseWithLength:(NSUInteger)keyLength;
- (BOOL)tryMasterPassword:(NSString *)tryPassword;
@end

View File

@ -20,7 +20,6 @@
+ (NSDictionary *)keyPhraseQuery;
+ (NSDictionary *)keyPhraseHashQuery;
- (void)forgetKeyPhrase;
- (void)loadStoredKeyPhrase;
- (void)askKeyPhrase;
@ -202,6 +201,11 @@
dbg(@"Deleting master key phrase and hash from key chain.");
[KeyChain deleteItemForQuery:[MPAppDelegate keyPhraseQuery]];
[KeyChain deleteItemForQuery:[MPAppDelegate keyPhraseHashQuery]];
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
#ifndef PRODUCTION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPForgotten];
#endif
}
[self loadKeyPhrase];
@ -234,62 +238,7 @@
- (void)askKeyPhrase {
dispatch_async(dispatch_get_main_queue(), ^{
NSData *keyPhraseHash = [KeyChain dataOfItemForQuery:[MPAppDelegate keyPhraseHashQuery]];
dbg(@"Key phrase hash %@.", keyPhraseHash? @"known": @"NOT known");
[AlertViewController showAlertWithTitle:@"Master Password"
message:keyPhraseHash? @"Unlock with your master password:": @"Choose your master password:"
viewStyle:UIAlertViewStyleSecureTextInput
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
exit(0);
NSString *answer = [alert textFieldAtIndex:0].text;
if (![answer length]) {
// User didn't enter a key phrase.
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:@"No master password entered."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
exit(0);
} cancelTitle:@"Quit" otherTitles:nil];
}
NSData *answerKeyPhrase = keyPhraseForPassword(answer);
NSData *answerHash = keyPhraseHashForKeyPhrase(answerKeyPhrase);
if (keyPhraseHash)
// A key phrase hash is known -> a key phrase is set.
// Make sure the user's entered key phrase matches it.
if (![keyPhraseHash isEqual:answerHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyPhraseHash, answerHash);
#ifndef PRODUCTION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
#endif
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:
@"Incorrect master password.\n\n"
@"If you are trying to use the app with a different master password, "
@"flip the 'Change my password' option in Settings."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
exit(0);
} cancelTitle:@"Quit" otherTitles:nil];
return;
}
#ifndef PRODUCTION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPAsked];
#endif
self.keyPhrase = answerKeyPhrase;
} cancelTitle:@"Quit" otherTitles:@"Unlock", nil];
});
[self.navigationController presentViewController:[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"] animated:NO completion:nil];
}
- (void)applicationWillResignActive:(UIApplication *)application {
@ -337,10 +286,45 @@
}];
}
- (BOOL)tryMasterPassword:(NSString *)tryPassword {
NSData *keyPhraseHash = [KeyChain dataOfItemForQuery:[MPAppDelegate keyPhraseHashQuery]];
dbg(@"Key phrase hash %@.", keyPhraseHash? @"known": @"NOT known");
if (![tryPassword length])
return NO;
NSData *tryKeyPhrase = keyPhraseForPassword(tryPassword);
NSData *tryKeyPhraseHash = keyPhraseHashForKeyPhrase(tryKeyPhrase);
if (keyPhraseHash)
// A key phrase hash is known -> a key phrase is set.
// Make sure the user's entered key phrase matches it.
if (![keyPhraseHash isEqual:tryKeyPhraseHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyPhraseHash, tryKeyPhraseHash);
#ifndef PRODUCTION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPMismatch];
#endif
return NO;
}
#ifndef PRODUCTION
[TestFlight passCheckpoint:MPTestFlightCheckpointMPAsked];
#endif
self.keyPhrase = tryKeyPhrase;
return YES;
}
- (void)setKeyPhrase:(NSData *)keyPhrase {
_keyPhrase = keyPhrase;
if (keyPhrase)
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeySet object:self];
else
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyUnset object:self];
if (keyPhrase) {
self.keyPhraseHash = keyPhraseHashForKeyPhrase(keyPhrase);
self.keyPhraseHashHex = [self.keyPhraseHash encodeHex];

View File

@ -46,7 +46,7 @@
- (void)setContent:(id)content {
NSData *encryptedContent = [[content description] encryptWithSymmetricKey:[MPAppDelegate get].keyPhrase
NSData *encryptedContent = [[content description] encryptWithSymmetricKey:[[MPAppDelegate get] keyPhraseWithLength:kCipherKeySize]
usePadding:YES];
if (self.type == MPElementTypeStoredDevicePrivate) {

View File

@ -114,6 +114,9 @@
}
}];
self.alertBody.text = nil;
self.contentTipEditIcon.alpha = 0;
[super viewDidLoad];
}
@ -167,7 +170,7 @@
self.contentField.enabled = NO;
if ([self.activeElement isKindOfClass:[MPElementGeneratedEntity class]])
self.passwordCounter.text = [NSString stringWithFormat:@"%d", ((MPElementGeneratedEntity *) self.activeElement).counter];
self.passwordCounter.text = [NSString stringWithFormat:@"%u", ((MPElementGeneratedEntity *) self.activeElement).counter];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *description = self.activeElement.description;
@ -194,7 +197,7 @@
if (hidden) {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 373);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 415);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 416);
[MPConfig get].helpHidden = [NSNumber numberWithBool:YES];
} else {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 175);
@ -296,7 +299,7 @@
[self updateAnimated:YES];
// Show new and old password.
if (oldPassword && ![oldPassword isEqualToString:newPassword])
if ([oldPassword length] && ![oldPassword isEqualToString:newPassword])
[self showAlertWithTitle:@"Password Changed!" message:l(@"The password for %@ has changed.\n\n"
@"Don't forget to update the site with your new password! "
@"Your old password was:\n"

View File

@ -49,6 +49,7 @@ typedef enum {
#define MPTestFlightCheckpointDeactivated @"MPTestFlightCheckpointDeactivated"
#define MPTestFlightCheckpointTerminated @"MPTestFlightCheckpointTerminated"
#define MPTestFlightCheckpointShowGuide @"MPTestFlightCheckpointShowGuide"
#define MPTestFlightCheckpointMPForgotten @"MPTestFlightCheckpointMPForgotten"
#define MPTestFlightCheckpointMPChanged @"MPTestFlightCheckpointMPChanged"
#define MPTestFlightCheckpointMPUnstored @"MPTestFlightCheckpointMPUnstored"
#define MPTestFlightCheckpointMPMismatch @"MPTestFlightCheckpointMPMismatch"
@ -57,6 +58,10 @@ typedef enum {
#define MPTestFlightCheckpointSetKeyphraseLength @"MPTestFlightCheckpointSetKeyphraseLength_%d"
#endif
#define MPNotificationKeySet @"MPNotificationKeySet"
#define MPNotificationKeyUnset @"MPNotificationKeyUnset"
#define MPNotificationKeyForgotten @"MPNotificationKeyForgotten"
NSData *keyPhraseForPassword(NSString *password);
NSData *keyPhraseHashForPassword(NSString *password);
NSData *keyPhraseHashForKeyPhrase(NSData *keyPhrase);

View File

@ -14,11 +14,12 @@
#define MP_N 16384
#define MP_r 8
#define MP_p 1
#define MP_dkLen 64
#define MP_hash PearlDigestSHA256
NSData *keyPhraseForPassword(NSString *password) {
return [SCrypt deriveKeyWithLength:64 fromPassword:[password dataUsingEncoding:NSUTF8StringEncoding]
return [SCrypt deriveKeyWithLength:MP_dkLen fromPassword:[password dataUsingEncoding:NSUTF8StringEncoding]
usingSalt:MP_salt N:MP_N r:MP_r p:MP_p];
}
NSData *keyPhraseHashForPassword(NSString *password) {
@ -109,10 +110,11 @@ NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *keyPhra
// Determine the hash whose bytes will be used for calculating a password: md4(name-keyPhrase)
assert(name && keyPhrase);
uint16_t ncounter = htons(counter);
NSData *keyHash = [[NSData dataByConcatenatingWithDelimitor:'-' datas:
[name dataUsingEncoding:NSUTF8StringEncoding],
keyPhrase,
htonl(counter),
[NSData dataWithBytes:&ncounter length:sizeof(ncounter)],
nil] hashWith:PearlDigestSHA1];
const char *keyBytes = keyHash.bytes;

View File

@ -0,0 +1,21 @@
//
// MBUnlockViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 22/02/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface MPUnlockViewController : UIViewController <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *lock;
@property (weak, nonatomic) IBOutlet UIImageView *spinner;
@property (weak, nonatomic) IBOutlet UITextField *field;
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
@property (weak, nonatomic) IBOutlet UIView *changeMPView;
- (IBAction)changeMP;
@end

View File

@ -0,0 +1,198 @@
//
// MBUnlockViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 22/02/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import "MPUnlockViewController.h"
#import "MPAppDelegate.h"
typedef enum {
MPLockscreenIdle,
MPLockscreenError,
MPLockscreenSuccess,
MPLockscreenProgress,
} MPLockscreen;
@interface MPUnlockViewController ()
@end
@implementation MPUnlockViewController
@synthesize lock;
@synthesize spinner;
@synthesize field;
@synthesize messageLabel;
@synthesize changeMPView;
- (void)showMessage:(NSString *)message state:(MPLockscreen)state {
__block void(^showMessageAnimation)(void) = ^{
self.lock.alpha = 0.0f;
switch (state) {
case MPLockscreenIdle:
[self.lock setImage:[UIImage imageNamed:@"lockscreen_idle"]];
break;
case MPLockscreenError:
[self.lock setImage:[UIImage imageNamed:@"lockscreen_red"]];
break;
case MPLockscreenSuccess:
[self.lock setImage:[UIImage imageNamed:@"lockscreen_green"]];
break;
case MPLockscreenProgress:
[self.lock setImage:[UIImage imageNamed:@"lockscreen_blue"]];
break;
}
self.lock.alpha = 0.0f;
[UIView animateWithDuration:1.0f animations:^{
self.lock.alpha = 1.0f;
} completion:^(BOOL finished) {
if (finished)
[UIView animateWithDuration:1.0f delay:0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{
self.lock.alpha = 0.5f;
} completion:nil];
}];
[UIView animateWithDuration:0.5f animations:^{
self.messageLabel.alpha = 1.0f;
self.messageLabel.text = message;
}];
};
if (self.messageLabel.alpha)
[UIView animateWithDuration:0.3f animations:^{
self.messageLabel.alpha = 0.0f;
} completion:^(BOOL finished) {
if (finished)
showMessageAnimation();
}];
else
showMessageAnimation();
}
- (void)hideMessage {
[UIView animateWithDuration:0.5f animations:^{
self.messageLabel.alpha = 0.0f;
}];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)viewDidLoad {
self.messageLabel.text = nil;
self.messageLabel.alpha = 0;
self.changeMPView.alpha = 0;
self.spinner.alpha = 0;
self.field.text = nil;
[[NSNotificationCenter defaultCenter] addObserverForName:MPNotificationKeyForgotten
object:nil queue:nil usingBlock:^(NSNotification *note) {
[self.field becomeFirstResponder];
}];
[super viewDidLoad];
}
- (void)viewDidUnload {
[self setSpinner:nil];
[self setField:nil];
[self setMessageLabel:nil];
[self setLock:nil];
[self setChangeMPView:nil];
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:YES
withAnimation:animated? UIStatusBarAnimationSlide: UIStatusBarAnimationNone];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:animated? UIStatusBarAnimationSlide: UIStatusBarAnimationNone];
[super viewWillDisappear:animated];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([textField.text length]) {
[textField resignFirstResponder];
return YES;
}
return NO;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@try {
dispatch_async(dispatch_get_main_queue(), ^{
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
rotate.fromValue = [NSNumber numberWithFloat:0];
rotate.toValue = [NSNumber numberWithFloat:2 * M_PI];
rotate.repeatCount = MAXFLOAT;
rotate.duration = 3.0;
[self.spinner.layer removeAllAnimations];
[self.spinner.layer addAnimation:rotate forKey:@"transform"];
[UIView animateWithDuration:0.3f animations:^{
self.spinner.alpha = 1.0f;
}];
[self showMessage:@"Checking password..." state:MPLockscreenProgress];
});
if ([[MPAppDelegate get] tryMasterPassword:textField.text])
dispatch_async(dispatch_get_main_queue(), ^{
[self showMessage:@"Success!" state:MPLockscreenSuccess];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 1.5f), dispatch_get_main_queue(), ^{
[self dismissModalViewControllerAnimated:YES];
});
});
else
dispatch_async(dispatch_get_main_queue(), ^{
[self showMessage:@"Not valid." state:MPLockscreenError];
[UIView animateWithDuration:0.5f animations:^{
self.changeMPView.alpha = 1.0f;
}];
});
}
@finally {
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3f animations:^{
self.spinner.alpha = 0.0f;
} completion:^(BOOL finished) {
[self.spinner.layer removeAllAnimations];
}];
});
}
});
}
- (IBAction)changeMP {
[[MPAppDelegate get] forgetKeyPhrase];
}
@end

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1938" systemVersion="11D50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.1" toolsVersion="2177" systemVersion="11D50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
<dependencies>
<development defaultVersion="4200" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="933"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1173"/>
</dependencies>
<scenes>
<!--Type View Controller - Type-->
<scene sceneID="WkW-SR-cr2">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="jZj-N1-rhF" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -52,9 +53,9 @@
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 14 characters, contains symbols." lineBreakMode="tailTruncation" minimumFontSize="10" id="6iu-aM-lJA">
<rect key="frame" x="20" y="184" width="280" height="20"/>
<rect key="frame" x="20" y="183" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -96,9 +97,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 8 characters, contains symbols." lineBreakMode="tailTruncation" minimumFontSize="10" id="MI2-JM-j4b">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<rect key="frame" x="20" y="23" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -129,9 +130,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 4 characters." lineBreakMode="tailTruncation" minimumFontSize="10" id="Zi3-26-3iq">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<rect key="frame" x="20" y="23" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -162,9 +163,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="8 characters." lineBreakMode="tailTruncation" minimumFontSize="10" id="CYQ-D8-vNS">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<rect key="frame" x="20" y="23" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -195,9 +196,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="4 numbers." lineBreakMode="tailTruncation" minimumFontSize="10" id="5Zm-AH-bAe">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<rect key="frame" x="20" y="23" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -251,9 +252,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="AES-encrypted, iTunes backup, iCloud sync." lineBreakMode="tailTruncation" minimumFontSize="10" id="vNa-Yq-XIJ">
<rect key="frame" x="20" y="144" width="280" height="20"/>
<rect key="frame" x="20" y="143" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -284,9 +285,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="AES-encrypted, stays on this device only." lineBreakMode="tailTruncation" minimumFontSize="10" id="6S8-9Y-pzj">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<rect key="frame" x="20" y="23" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
@ -308,6 +309,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
</objects>
<point key="canvasLocation" x="996" y="182"/>
</scene>
<!--Main View Controller - Master Password-->
<scene sceneID="U26-Zf-euQ">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -340,7 +342,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<rect key="frame" x="0.0" y="43" width="320" height="175"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="Content-Backdrop.png" id="enb-OH-DVZ">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="bottom" image="background.png" id="enb-OH-DVZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="175"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
@ -373,7 +375,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.50000000000000011" contentMode="left" text="apple.com" lineBreakMode="tailTruncation" minimumFontSize="10" id="gSK-aB-wNI">
<rect key="frame" x="25" y="20" width="270" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
@ -383,7 +385,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<rect key="frame" x="20" y="46" width="280" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="textColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="Optima-ExtraBlack" family="Optima" pointSize="26"/>
<fontDescription key="fontDescription" name="Copperplate-Bold" family="Copperplate" pointSize="26"/>
<textInputTraits key="textInputTraits" autocorrectionType="no"/>
<connections>
<outlet property="delegate" destination="PQa-Xl-A3x" id="qOM-gq-c6g"/>
@ -392,7 +394,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.50000000000000011" contentMode="left" text="1" textAlignment="right" lineBreakMode="tailTruncation" minimumFontSize="10" id="Iuf-np-e9C">
<rect key="frame" x="240" y="27" width="40" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Optima-ExtraBlack" family="Optima" pointSize="17"/>
<fontDescription key="fontDescription" name="Copperplate-Bold" family="Copperplate" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
@ -415,7 +417,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
</connections>
</button>
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9FS-fS-xH6">
<rect key="frame" x="275" y="18.5" width="37" height="37"/>
<rect key="frame" x="274.5" y="18.5" width="37.5" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
@ -433,9 +435,9 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" lineBreakMode="middleTruncation" id="Cei-5z-uWE">
<rect key="frame" x="10" y="115" width="300" height="46"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<fontDescription key="fontDescription" name="Helvetica-Bold" family="Helvetica" pointSize="15"/>
<size key="titleShadowOffset" width="0.0" height="1"/>
<state key="normal" title="Long" backgroundImage="ui_button_standard_large.png">
<state key="normal" title="Long Password" backgroundImage="ui_button_standard_large.png">
<color key="titleColor" cocoaTouchSystemColor="lightTextColor"/>
<color key="titleShadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</state>
@ -461,7 +463,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="icon_edit.png" id="KEn-n3-qhX">
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="icon_edit.png" id="KEn-n3-qhX">
<rect key="frame" x="48.5" y="6.5" width="24" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
@ -471,7 +473,7 @@ The passwords aren't saved anywhere. This is a major advantage: if you loose yo
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view clipsSubviews="YES" alpha="0.60000000000000009" contentMode="scaleToFill" id="61G-By-qLB">
<view clipsSubviews="YES" contentMode="scaleToFill" id="61G-By-qLB">
<rect key="frame" x="0.0" y="216" width="320" height="200"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -601,6 +603,7 @@ L4m3P4sSw0rD</string>
</objects>
<point key="canvasLocation" x="455" y="182"/>
</scene>
<!--Guide View Controller-->
<scene sceneID="Rt1-b4-sUB">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="7yf-G7-kVy" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -669,6 +672,113 @@ L4m3P4sSw0rD</string>
</objects>
<point key="canvasLocation" x="455" y="785"/>
</scene>
<!--Unlock View Controller-->
<scene sceneID="HkH-JR-Fhy">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="OGA-5j-IcQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
<viewController storyboardIdentifier="MPUnlockViewController" modalTransitionStyle="flipHorizontal" id="Nbn-Rv-sP1" customClass="MPUnlockViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="PHH-XC-9QQ">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="top" image="background.png" id="QWe-Gw-rD3">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view contentMode="scaleToFill" id="OP6-72-eij">
<rect key="frame" x="0.0" y="157" width="320" height="130"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="center" image="lock_idle.png" id="tyv-qJ-bKR">
<rect key="frame" x="110" y="15" width="100" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" alpha="0.0" contentMode="center" image="lock_idle.png" id="Lpf-KA-3CV">
<rect key="frame" x="110" y="15" width="100" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" id="27q-lX-0vy">
<rect key="frame" x="122" y="28" width="75" height="75"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Checking password..." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="oU9-lf-nnJ">
<rect key="frame" x="20" y="115" width="280" height="15"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate-Bold" family="Copperplate" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_textfield.png" id="ivR-Xl-NrT">
<rect key="frame" x="20" y="89" width="280" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<rect key="contentStretch" x="0.25" y="0.25" width="0.49999999999999961" height="0.49999999999999961"/>
</imageView>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" clearsOnBeginEditing="YES" minimumFontSize="17" id="rTR-7Q-X8o">
<rect key="frame" x="20" y="89" width="280" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="36"/>
<textInputTraits key="textInputTraits" secureTextEntry="YES"/>
<connections>
<outlet property="delegate" destination="Nbn-Rv-sP1" id="Y0T-cI-gF1"/>
</connections>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your master password:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="RhX-bA-EhC">
<rect key="frame" x="32" y="61" width="256" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Copperplate" family="Copperplate" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" id="Wu7-Mg-9SD">
<rect key="frame" x="0.0" y="391" width="320" height="89"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Trying to log in with a different master password?" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="vnS-n6-NZI">
<rect key="frame" x="0.0" y="0.0" width="320" height="15"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="Copperplate-Bold" family="Copperplate" pointSize="11"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" lineBreakMode="middleTruncation" id="wad-V1-K3f">
<rect key="frame" x="10" y="23" width="300" height="46"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<size key="titleShadowOffset" width="0.0" height="1"/>
<state key="normal" title="Change master password" backgroundImage="ui_button_standard_large.png">
<color key="titleColor" cocoaTouchSystemColor="lightTextColor"/>
<color key="titleShadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="changeMP" destination="Nbn-Rv-sP1" eventType="touchUpInside" id="7RI-hu-SiS"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<nil key="simulatedStatusBarMetrics"/>
<connections>
<outlet property="changeMPView" destination="Wu7-Mg-9SD" id="84H-HT-5ml"/>
<outlet property="field" destination="rTR-7Q-X8o" id="DHg-gg-MVD"/>
<outlet property="lock" destination="Lpf-KA-3CV" id="6cE-2g-4XQ"/>
<outlet property="messageLabel" destination="oU9-lf-nnJ" id="Ahc-hl-KnJ"/>
<outlet property="spinner" destination="27q-lX-0vy" id="jUx-GK-Lgf"/>
</connections>
</viewController>
</objects>
<point key="canvasLocation" x="455" y="1425"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="8r0-wA-Zre">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="Lcz-JH-B5B" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -690,8 +800,9 @@ L4m3P4sSw0rD</string>
</scene>
</scenes>
<resources>
<image name="Content-Backdrop.png" width="480" height="480"/>
<image name="Content-Backdrop.png" width="16" height="16"/>
<image name="Square-bottom.png" width="551" height="58"/>
<image name="background.png" width="480" height="480"/>
<image name="guide_page_0.png" width="320" height="480"/>
<image name="guide_page_1.png" width="320" height="480"/>
<image name="guide_page_2.png" width="320" height="480"/>
@ -702,6 +813,7 @@ L4m3P4sSw0rD</string>
<image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/>
<image name="lock_idle.png" width="100" height="100"/>
<image name="tip_alert_black.png" width="235" height="81"/>
<image name="tip_basic_black.png" width="210" height="60"/>
<image name="ui_button_green_large.png" width="300" height="46"/>
@ -711,6 +823,8 @@ L4m3P4sSw0rD</string>
<image name="ui_list_middle.png" width="300" height="34"/>
<image name="ui_panel_container.png" width="300" height="87"/>
<image name="ui_panel_display.png" width="300" height="86"/>
<image name="ui_spinner.png" width="75" height="75"/>
<image name="ui_textfield.png" width="158" height="34"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -15,6 +15,7 @@ cd "${0%/*}/../MasterPassword/Resources"
for size in "${!icons[@]}"; do
file=${icons[size]}
[[ iTunesArtwork.png -nt $file ]] || continue
emit "$file ($size px)" --
convert "iTunesArtwork.png" -resize "${size}x${size}" "$file"
@ -24,8 +25,9 @@ done
echo
emit "Converting @2x artwork"
for file in ./{,Guide/}*@2x.png; do
for file in ./{,Guide,Lock,Background}/*@2x.png; do
inArray "${file##*/}" "${icons[@]}" && continue
[[ $file -nt ${file/@2x} ]] || continue
emit "${file/@2x}" --
convert "$file" -filter box -resize 50% -unsharp 0x1 "${file/@2x}"

View File

@ -10,16 +10,16 @@ body {
color: black;
font: 120% ExoLight, sans-serif;
font: 120% Exo, sans-serif;
font-weight: 100;
}
h1, h2, h3, h4 {
text-shadow: #FFF 0 -1px 1px, #AAA 0 0 5px;
font-family: ExoBold;
font-weight: 600;
}
strong {
font-family: ExoDemiBold;
font-weight: 400;
}
h1 .sub {
font-size: 0.5em;
@ -37,20 +37,18 @@ p {
text-align: justify;
}
ul {
font-family: ExoDemiBold;
font-size: 90%;
font-weight: 500;
font-weight: 400;
}
blockquote {
font-family: ExoDemiBold;
font-size: 90%;
font-weight: bold;
font-weight: 400;
}
a, .link, :link {
color: inherit;
text-decoration: underline;
cursor: pointer;
font-weight: 500;
font-weight: 400;
}
a:hover, .link:hover {
text-decoration: none;
@ -130,7 +128,6 @@ blockquote:before {
position: absolute;
margin: -0.5ex 0 0 -1em;
font-size: 300%;
font-family: ExoLight;
font-weight: 100;
}
@ -182,21 +179,20 @@ section.active {
a.previous, a.next {
display: block;
position: absolute;
width: 100%;
margin: -2.5em 0 0 0;
font-size: 150%;
font-family: ExoDemiBold;
font-weight: 400;
text-decoration: none;
}
a.previous {
margin-left: -3em;
left: 0;
}
a.previous:before {
content: "< ";
}
a.next {
margin-left: 3em;
right: 0;
text-align: right;
}

View File

@ -9,9 +9,7 @@
<link rel="shortcut icon" href="images/resources/favicon.png" type="image/x-png" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="css/sprites/glossy-black/sprites.css" />
<link rel="stylesheet" type="text/css" href="css/sprites/silk/sprites.css" />
<link rel="stylesheet" type="text/css" href="fnt/Exo/stylesheet.css" />
<link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Exo:100,400,600,900,100italic,400italic,600italic' />
<link rel="stylesheet" type="text/css" href="css/screen.css" />
<script src="js/jquery-1.6.1.min.js" type="text/javascript"></script>
@ -67,7 +65,7 @@
</p>
<p>
It aims to secure your online (and offline!) life by changing the way you deal with passwords.
It aims to secure your online (and offline!) life by <em>changing the way you deal with passwords</em>.
</p>
<hr />
@ -76,20 +74,20 @@
<p>
You already know the problem:<br />
Passwords are confidential information between you and a site. They should never be shared with anyone else, definitely not other sites. Yet that's exactly what happens with most of us: Hundereds of online accounts to manage and authenticate, we can't help but reuse one, two or five passwords that we can remember. Maybe we keep a paper stuck to our monitor with a list of passwords on them, because we realize the truth:
Passwords are confidential information between you and a site. They should never be shared with anyone else, definitely not other sites. Yet that's exactly what happens with most of us: Hundereds of online accounts to manage and authenticate, <strong>we can't help but reuse one, two or five passwords that we can remember</strong>. Maybe we keep a paper stuck to our monitor with a list of passwords on them, because we realize the truth:
</p>
<blockquote>It is impossible to remember a secure password for each of our accounts and still keep those passwords both <em>exclusive</em> and <em>confidential</em>.</blockquote>
<p>
Multiple solutions exist:<br />
Sites that realize that passwords aren't the end-all of authentication usually implement some sort of alternative authentication mechanism: OpenID, SAML, some form of mobile authentication, secure tokens, etc.<br />
Sites that realize that passwords aren't the end-all of authentication usually implement some sort of alternative authentication mechanism: <em>OpenID, SAML, some form of mobile authentication, secure tokens, etc</em>.<br />
The problem here is that these solutions only work for the select few sites that have chosen to implement them; and then you, the user, are stuck with whatever mechanism the site has chosen for you.
</p>
<p>
To solve the problem for other sites, there are programs that remember our passwords for us.<br />
The problem with these is that they do not actually help us with setting exclusive and confidential passwords for our accounts. They just offload the work of remembering passwords, and at a great expense: If you loose your data, you loose your online identity and are locked out of everything.
To solve the problem for other sites, there are <em>programs that remember our passwords for us</em>.<br />
The problem with these is that they do not actually help us with setting exclusive and confidential passwords for our accounts. They just offload the work of remembering passwords, and at a great expense: <strong>If you loose your data, you loose your online identity and are locked out of everything</strong>.
</p>
<hr />
@ -98,7 +96,7 @@
<p>
Master Password aims to turn the tables in favor of the user, you.<br />
In the end, <em>what we really want</em> is a way of dealing with passwords in an exclusive and confidential way without having to remember them, and without running the risk of losing our online identity to fraudsters.
In the end, <em>what we really want</em> is a way of dealing with passwords in an exclusive and confidential way <em>without having to remember</em> them, and <em>without running the risk of losing our online identity</em> to fraudsters.
</p>
<p>
@ -119,7 +117,7 @@
</li>
<li>For those cases where you cannot change your account's password, the application will encrypt passwords with your master password and store them securely (as explained, stored passwords can get lost).</li>
<li>Integrates with iCloud to synchronize and back up your site history and stored passwords.</li>
<li>For those that care to know, the password generation algorithm is open and documented within the application.</li>
<li>For those that care to know, the password generation algorithm is open and fully documented, so you aren't tied down to this application.</li>
</ul>
<hr />
@ -134,7 +132,7 @@
Participation in the beta is free of charge, but does come with the expectation that you will contribute. Comment constructively, report issues and propose improvements.
</p>
<p>
Post-beta, Master Password is expected to sell for somewhere around 7 USD. The most helpful testers will receive the final version (and all future updates) free of charge.
Post-beta, Master Password is expected to sell for somewhere around 10 USD. The most helpful testers will receive the final version (and all future updates) free of charge.
</p>
</section>
@ -158,22 +156,31 @@
Alright, let's describe the process in detail. This part will likely make sense to you only if you're well versed in computer security jargon. If you're the kind of person who likes to know how the clock ticks before deciding that it can be trusted to keep ticking, read on.
</p>
<p>
The user chooses a single master password, preferably sufficiently long to harden against brute-force attacks. When the user requests a password be generated for a site, the application composes a string consisting of the site name, the master password, and a password counter, delimited in that order by a dash character, and hashes those <code>UTF-8</code> bytes using the <code>SHA-1</code> algorithm. The bytes resulting from this hashing operation are called the <code>keyBytes</code> in the next steps.
The user chooses a single master password, preferably sufficiently long to harden against brute-force attacks. Before usage, a <code>masterKey</code> is derived from this master password using the <a href="http://www.tarsnap.com/scrypt.html">scrypt key derivation function</a>. This makes it impossibly expensive and time-consuming to attempt brute-forcing a properly sized master password.
</p>
<code><pre>
keyBytes = sha1( site name "-" master password "-" password counter )
masterKey = scrypt( P, S, N, r, p, dkLen )
where
P = master password
S = &lt;empty&gt;
N = 16384
r = 8
p = 1
dkLen = 64
</pre></code>
<p>
When the user requests a password be generated for a site, the application composes a byte string consisting of the site name, the master key, and a password counter, delimited in that order by a dash character (characters are UTF-8 encoded, numbers in 32-bit network byte order), and hashes it using the <code>SHA-1</code> algorithm. The result is called the <code>cipherKey</code>.
</p>
<code><pre>
cipherKey = sha1( site name "-" masterKey "-" password counter )
</pre></code>
<p>
Next, we need the password type that the user has chosen to use for the site. Password types determine the
<q>cipher</q> that will be used to encrypt <code>keyBytes</code> into a readable password. For
instance, the standard password type <q>Long Password</q> activates one of three pre-set ciphers:
<code>CvcvCvcvnoCvcv</code>, <code>CvcvnoCvcvCvcv</code> or <code>CvcvCvcvCvcvno</code>. Which of those
will be used, depends on the first of the <code>keyBytes</code>. Take the byte value modulo the amount of
pre-set ciphers (in this case, three), and the result tells you which of the three ciphers to use.
Next up is to merge this key with the password type that the user has chosen to use for the site. Password types determine the <q>cipher</q> that will be used to encrypt <code>cipherKey</code> bytes into a readable password. For instance, the standard password type <q>Long Password</q> activates one of three pre-set ciphers: <code>CvcvCvcvnoCvcv</code>, <code>CvcvnoCvcvCvcv</code> or <code>CvcvCvcvCvcvno</code>. Which of those will be used, depends on the first byte of the <code>cipherKey</code>. Take the byte value modulo the amount of pre-set ciphers (in this case, three), and the result tells you which of the pre-set ciphers to use.
</p>
<code><pre>
ciphers = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno" ]
cipher = ciphers[ keyBytes[0] % count( ciphers ) ]
cipher = ciphers[ cipherKey[0] % count( ciphers ) ]
</pre></code>
<p>
Now that we know what cipher to use for building our final password, all that's left is to iterate the
@ -181,13 +188,13 @@
character in the cipher represents a set of possible output characters (<code>passChars</code>). For instance, a <code>C</code>
character in the cipher indicates that we need to choose a capital consonant character. An <code>o</code>
character in the cipher indicates that we need to choose an <q>other</q> (symbol) character. Exactly which
character to choose in that set for the password output depends on the next byte from <code>keyBytes</code>.
Like before, take the next unused <code>keyByte</code>'s byte value modulo the amount of characters in the
character to choose in that set for the password output depends on the next byte from the <code>cipherKey</code>.
Like before, take the next unused <code>cipherKey</code> byte value modulo the amount of characters in the
set of possible output characters for the cipher iteration and use the result to choose the output
character (<code>passChar</code>). Repeat until you've iterated the whole cipher.
</p>
<code><pre>
passChar = passChars[ keyBytes[i + 1] % count( passChars ) ]
passChar = passChars[ cipherKey[i + 1] % count( passChars ) ]
passWord += passChar
</pre></code>