Compare commits
31 Commits
2.1-appsto
...
2.1-cli1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10f100186c | ||
|
|
2af2351ebf | ||
|
|
49b3fe7913 | ||
|
|
9d926be8ae | ||
|
|
c3474de2ff | ||
|
|
68b9b4e09a | ||
|
|
b810c1032b | ||
|
|
a4ab3c7bc9 | ||
|
|
039547b735 | ||
|
|
6f741f6f2f | ||
|
|
38d4b761b7 | ||
|
|
18f8ebb9dc | ||
|
|
794d064a99 | ||
|
|
090b274363 | ||
|
|
25ba87f119 | ||
|
|
f0b659a0c7 | ||
|
|
7736788920 | ||
|
|
e3be98f3ad | ||
|
|
d9b1b44de0 | ||
|
|
c3c2de5d14 | ||
|
|
6aa50bac04 | ||
|
|
5268039c3d | ||
|
|
0d66d4660e | ||
|
|
e981df3c8b | ||
|
|
543ebd4bac | ||
|
|
e6d21e1c1d | ||
|
|
a3ebcf0608 | ||
|
|
556d1d3d58 | ||
|
|
979d3a2a5a | ||
|
|
480e7f192a | ||
|
|
a18793b161 |
3
.gitignore
vendored
@@ -32,7 +32,10 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
|
||||
MasterPassword/Java/**/target
|
||||
|
||||
# C
|
||||
MasterPassword/C/VERSION
|
||||
MasterPassword/C/*.o
|
||||
MasterPassword/C/mpw-*.tar.gz
|
||||
MasterPassword/C/mpw
|
||||
MasterPassword/C/mpw-bench
|
||||
MasterPassword/C/lib/*/*
|
||||
!MasterPassword/C/lib/*/.source
|
||||
|
||||
6
.gitmodules
vendored
@@ -13,3 +13,9 @@
|
||||
[submodule "External/AttributedMarkdown"]
|
||||
path = External/AttributedMarkdown
|
||||
url = https://github.com/dreamwieber/AttributedMarkdown.git
|
||||
[submodule "External/uicolor-utilities"]
|
||||
path = External/uicolor-utilities
|
||||
url = git://github.com/lhunath/uicolor-utilities.git
|
||||
[submodule "External/jrswizzle"]
|
||||
path = External/jrswizzle
|
||||
url = git://github.com/jonmarimba/jrswizzle.git
|
||||
|
||||
2
External/Pearl
vendored
1
External/jrswizzle
vendored
Submodule
1
External/uicolor-utilities
vendored
Submodule
@@ -1,9 +1,258 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run with -DDEBUG to enable trace-level output.
|
||||
#
|
||||
# TROUBLESHOOTING
|
||||
# - To enable verbose algorithm/implementation debugging, use ./build -DDEBUG
|
||||
# - If you see 'undefined reference to `clock_gettime'', try ./build -lrt instead
|
||||
#
|
||||
# BUGS
|
||||
# masterpassword@lyndir.com
|
||||
#
|
||||
# AUTHOR
|
||||
# Maarten Billemont
|
||||
#
|
||||
cd "${BASH_SOURCE%/*}"
|
||||
shopt -s extglob
|
||||
set -e
|
||||
|
||||
[[ -e lib/scrypt/scryptenc.o ]] || { echo >&2 "Missing scrypt. First get and build the scrypt source in lib/scrypt from <$(<lib/scrypt/.source)>.\n"; exit 1; }
|
||||
|
||||
deps=( -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"crypto" -L"." -L"lib/scrypt" )
|
||||
### CONFIGURATION
|
||||
|
||||
gcc "${deps[@]}" -Qunused-arguments -c types.c -o types.o "$@"
|
||||
gcc "${deps[@]}" -Qunused-arguments -l"types.o" mpw.c -o mpw "$@"
|
||||
# Targets to build.
|
||||
if [[ $targets ]]; then
|
||||
read -ra targets <<< "$targets"
|
||||
else
|
||||
# Default targets.
|
||||
# Modify here or override using targets='mpw mpw-bench' ./build
|
||||
targets=(
|
||||
mpw # C CLI version of Master Password.
|
||||
#mpw-bench # C CLI Master Password benchmark utility.
|
||||
)
|
||||
fi
|
||||
|
||||
|
||||
### DEPENDENCIES
|
||||
|
||||
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"
|
||||
[[ $(openssl sha < "$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_sha"
|
||||
}
|
||||
|
||||
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_sha"
|
||||
}
|
||||
|
||||
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"
|
||||
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_sha=7253c86c8fe890e67ec782749f95ce3f1517b065
|
||||
@@ -1 +1,4 @@
|
||||
https://code.google.com/p/scrypt/
|
||||
home=https://code.google.com/p/scrypt/
|
||||
svn=http://scrypt.googlecode.com/svn
|
||||
pkg=http://masterpasswordapp.com/libscrypt-b12b554.tar.gz
|
||||
pkg_sha=a86445c3e031392d20652f4163adfd3fb0b1994e
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#define _WITH_GETLINE
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
@@ -23,6 +24,12 @@
|
||||
#include <crypto/crypto_scrypt.h>
|
||||
#include "types.h"
|
||||
|
||||
#if defined(READLINE)
|
||||
#include <readline/readline.h>
|
||||
#elif defined(EDITLINE)
|
||||
#include <histedit.h>
|
||||
#endif
|
||||
|
||||
#define MP_N 32768
|
||||
#define MP_r 8
|
||||
#define MP_p 2
|
||||
@@ -52,7 +59,14 @@ void usage() {
|
||||
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\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);
|
||||
}
|
||||
|
||||
@@ -94,27 +108,30 @@ int main(int argc, char *const argv[]) {
|
||||
const char *siteTypeString = getenv( MP_env_sitetype );
|
||||
MPElementVariant siteVariant = MPElementVariantPassword;
|
||||
const char *siteVariantString = NULL;
|
||||
const char *siteContextString = NULL;
|
||||
uint32_t siteCounter = 1;
|
||||
const char *siteCounterString = getenv( MP_env_sitecounter );
|
||||
|
||||
// Read the options.
|
||||
char opt;
|
||||
while ((opt = getopt(argc, argv, "u:t:c:v:h")) != -1)
|
||||
for (int opt; (opt = getopt(argc, argv, "u:t:c:v:C:h")) != -1;)
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'u':
|
||||
userName = optarg;
|
||||
break;
|
||||
case 't':
|
||||
siteTypeString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
siteVariantString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
case 'C':
|
||||
siteContextString = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case '?':
|
||||
switch (optopt) {
|
||||
@@ -160,6 +177,8 @@ int main(int argc, char *const argv[]) {
|
||||
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);
|
||||
@@ -172,31 +191,27 @@ int main(int argc, char *const argv[]) {
|
||||
}
|
||||
trc("mpwConfigPath: %s\n", mpwConfigPath);
|
||||
FILE *mpwConfig = fopen(mpwConfigPath, "r");
|
||||
if (!mpwConfig) {
|
||||
fprintf(stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
|
||||
return 1;
|
||||
}
|
||||
free(mpwConfigPath);
|
||||
char *line = NULL;
|
||||
size_t linecap = 0;
|
||||
ssize_t linelen;
|
||||
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
|
||||
if (strcmp(strsep(&line, ":"), userName) == 0) {
|
||||
masterPassword = strsep(&line, "\n");
|
||||
break;
|
||||
}
|
||||
if (!masterPassword) {
|
||||
fprintf(stderr, "Missing master password for user: %s\n", userName);
|
||||
return 1;
|
||||
if (mpwConfig) {
|
||||
char *line = NULL;
|
||||
size_t linecap = 0;
|
||||
ssize_t linelen;
|
||||
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
|
||||
if (strcmp(strsep(&line, ":"), userName) == 0) {
|
||||
masterPassword = strsep(&line, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!masterPassword)
|
||||
masterPassword = getpass( "Your master password: " );
|
||||
trc("masterPassword: %s\n", masterPassword);
|
||||
|
||||
// Calculate the master key salt.
|
||||
const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
|
||||
trc("key scope: %s\n", mpKeyScope);
|
||||
const uint32_t n_userNameLength = htonl(strlen(userName));
|
||||
size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
|
||||
char *masterKeySalt = malloc( masterKeySaltLength );
|
||||
const size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
|
||||
char *masterKeySalt = (char *)malloc( masterKeySaltLength );
|
||||
if (!masterKeySalt) {
|
||||
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
|
||||
return 1;
|
||||
@@ -211,7 +226,7 @@ int main(int argc, char *const argv[]) {
|
||||
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
|
||||
|
||||
// Calculate the master key.
|
||||
uint8_t *masterKey = malloc( MP_dkLen );
|
||||
uint8_t *masterKey = (uint8_t *)malloc( MP_dkLen );
|
||||
if (!masterKey) {
|
||||
fprintf(stderr, "Could not allocate master key: %d\n", errno);
|
||||
return 1;
|
||||
@@ -228,11 +243,14 @@ int main(int argc, char *const argv[]) {
|
||||
|
||||
// Calculate the site seed.
|
||||
const char *mpSiteScope = ScopeForVariant(siteVariant);
|
||||
trc("site scope: %s\n", mpSiteScope);
|
||||
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);
|
||||
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
|
||||
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;
|
||||
@@ -243,9 +261,13 @@ int main(int argc, char *const argv[]) {
|
||||
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)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
|
||||
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)), Hex(&n_siteContextLength, sizeof(n_siteContextLength)), siteContextString);
|
||||
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
|
||||
|
||||
uint8_t sitePasswordSeed[32];
|
||||
@@ -263,7 +285,7 @@ int main(int argc, char *const argv[]) {
|
||||
abort();
|
||||
|
||||
// Encode the password from the seed using the cipher.
|
||||
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
|
||||
char *sitePassword = (char *)calloc(strlen(cipher) + 1, sizeof(char));
|
||||
for (int c = 0; c < strlen(cipher); ++c) {
|
||||
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
|
||||
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
|
||||
|
||||
@@ -50,19 +50,19 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
|
||||
switch (type) {
|
||||
case MPElementTypeGeneratedMaximum: {
|
||||
char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
|
||||
const char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
|
||||
return ciphers[seedByte % 2];
|
||||
}
|
||||
case MPElementTypeGeneratedLong: {
|
||||
char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
|
||||
const char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
|
||||
return ciphers[seedByte % 21];
|
||||
}
|
||||
case MPElementTypeGeneratedMedium: {
|
||||
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
|
||||
const char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
|
||||
return ciphers[seedByte % 2];
|
||||
}
|
||||
case MPElementTypeGeneratedBasic: {
|
||||
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
|
||||
const char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
|
||||
return ciphers[seedByte % 3];
|
||||
}
|
||||
case MPElementTypeGeneratedShort: {
|
||||
@@ -75,7 +75,7 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
return "cvccvcvcv";
|
||||
}
|
||||
case MPElementTypeGeneratedPhrase: {
|
||||
char *ciphers[] = { "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" };
|
||||
const char *ciphers[] = { "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" };
|
||||
return ciphers[seedByte % 3];
|
||||
}
|
||||
default: {
|
||||
@@ -95,6 +95,8 @@ const MPElementVariant VariantWithName(const char *variantName) {
|
||||
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();
|
||||
@@ -108,6 +110,9 @@ const char *ScopeForVariant(MPElementVariant variant) {
|
||||
case MPElementVariantLogin: {
|
||||
return "com.lyndir.masterpassword.login";
|
||||
}
|
||||
case MPElementVariantAnswer: {
|
||||
return "com.lyndir.masterpassword.answer";
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown variant: %d", variant);
|
||||
abort();
|
||||
@@ -170,7 +175,7 @@ const char *IDForBuf(const void *buf, size_t length) {
|
||||
uint8_t hash[32];
|
||||
SHA256_Buf(buf, length, hash);
|
||||
|
||||
char *id = calloc(65, sizeof(char));
|
||||
char *id = (char *)calloc(65, sizeof(char));
|
||||
for (int kH = 0; kH < 32; kH++)
|
||||
sprintf(&(id[kH * 2]), "%02X", hash[kH]);
|
||||
|
||||
@@ -178,7 +183,7 @@ const char *IDForBuf(const void *buf, size_t length) {
|
||||
}
|
||||
|
||||
const char *Hex(const void *buf, size_t length) {
|
||||
char *id = calloc(length*2+1, sizeof(char));
|
||||
char *id = (char *)calloc(length*2+1, sizeof(char));
|
||||
for (int kH = 0; kH < length; kH++)
|
||||
sprintf(&(id[kH * 2]), "%02X", ((const uint8_t*)buf)[kH]);
|
||||
return id;
|
||||
|
||||
@@ -11,6 +11,8 @@ typedef enum {
|
||||
MPElementVariantPassword,
|
||||
/** Generate the login name to log in as. */
|
||||
MPElementVariantLogin,
|
||||
/** Generate the answer to a security question. */
|
||||
MPElementVariantAnswer,
|
||||
} MPElementVariant;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -41,6 +41,6 @@
|
||||
@property(nonatomic) IBOutlet UITextField *questionField;
|
||||
@property(nonatomic) IBOutlet UITextField *answerField;
|
||||
|
||||
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site;
|
||||
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site inVC:(MPAnswersViewController *)VC;
|
||||
|
||||
@end
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
if (!_multiple)
|
||||
return 0;
|
||||
|
||||
return MAX( 2, [[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].questions count] );
|
||||
return [[self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]].questions count] + 1;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
@@ -118,7 +118,7 @@
|
||||
MPSiteQuestionEntity *question = nil;
|
||||
if ([site.questions count] > indexPath.item)
|
||||
question = site.questions[indexPath.item];
|
||||
[cell setQuestion:question forSite:site];
|
||||
[cell setQuestion:question forSite:site inVC:self];
|
||||
|
||||
return cell;
|
||||
}
|
||||
@@ -217,6 +217,17 @@
|
||||
} );
|
||||
}
|
||||
|
||||
- (void)didAddQuestion:(MPSiteQuestionEntity *)question toSite:(MPSiteEntity *)site {
|
||||
|
||||
NSUInteger newQuestionRow = [site.questions count];
|
||||
PearlMainQueue( ^{
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ [NSIndexPath indexPathForRow:newQuestionRow inSection:1] ]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView endUpdates];
|
||||
} );
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MPGlobalAnswersCell
|
||||
@@ -247,14 +258,16 @@
|
||||
@implementation MPAnswersQuestionCell {
|
||||
NSManagedObjectID *_siteOID;
|
||||
NSManagedObjectID *_questionOID;
|
||||
__weak MPAnswersViewController *_answersVC;
|
||||
}
|
||||
|
||||
#pragma mark - State
|
||||
|
||||
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site {
|
||||
- (void)setQuestion:(MPSiteQuestionEntity *)question forSite:(MPSiteEntity *)site inVC:(MPAnswersViewController *)answersVC {
|
||||
|
||||
_siteOID = site.objectID;
|
||||
_questionOID = question.objectID;
|
||||
_answersVC = answersVC;
|
||||
|
||||
[self updateAnswerForQuestion:question ofSite:site];
|
||||
}
|
||||
@@ -272,9 +285,11 @@
|
||||
|
||||
NSString *keyword = textField.text;
|
||||
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
|
||||
BOOL didAddQuestionObject = NO;
|
||||
MPSiteEntity *site = [MPSiteEntity existingObjectWithID:_siteOID inContext:context];
|
||||
MPSiteQuestionEntity *question = [MPSiteQuestionEntity existingObjectWithID:_questionOID inContext:context];
|
||||
if (!question) {
|
||||
didAddQuestionObject = YES;
|
||||
[site addQuestionsObject:question = [MPSiteQuestionEntity insertNewObjectInContext:context]];
|
||||
question.site = site;
|
||||
}
|
||||
@@ -291,6 +306,9 @@
|
||||
|
||||
_questionOID = question.objectID;
|
||||
[self updateAnswerForQuestion:question ofSite:site];
|
||||
|
||||
if (didAddQuestionObject)
|
||||
[_answersVC didAddQuestion:question toSite:site];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ const long MPAvatarAdd = 10000;
|
||||
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarSizeConstraint;
|
||||
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarToTopConstraint;
|
||||
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *avatarRaisedConstraint;
|
||||
@property(strong, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;
|
||||
|
||||
@end
|
||||
|
||||
@@ -66,6 +67,12 @@ const long MPAvatarAdd = 10000;
|
||||
[self observeKeyPath:@"highlighted" withBlock:^(id from, id to, NSKeyValueChange cause, MPAvatarCell *_self) {
|
||||
[_self updateAnimated:_self.superview != nil];
|
||||
}];
|
||||
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPAvatarCell *self, NSNotification *note) {
|
||||
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGFloat keyboardHeight = CGRectGetHeight( self.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
|
||||
CABasicAnimation *toShadowOpacityAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
|
||||
toShadowOpacityAnimation.toValue = @0.2f;
|
||||
@@ -99,6 +106,7 @@ const long MPAvatarAdd = 10000;
|
||||
- (void)dealloc {
|
||||
|
||||
[self removeKeyPathObservers];
|
||||
PearlRemoveNotificationObservers();
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
@@ -264,7 +272,7 @@ const long MPAvatarAdd = 10000;
|
||||
case MPAvatarModeRaisedAndMinimized: {
|
||||
[self.avatarSizeConstraint updateConstant:36];
|
||||
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2];
|
||||
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh];
|
||||
self.nameContainer.alpha = 0;
|
||||
self.nameContainer.backgroundColor = [UIColor blackColor];
|
||||
|
||||
@@ -516,7 +516,7 @@
|
||||
TimeToCrack timeToCrack;
|
||||
NSString *timeToCrackString = nil;
|
||||
id<MPAlgorithm> algorithm = site.algorithm?: MPAlgorithmDefault;
|
||||
MPAttacker attackHardware = [[MPConfig get].siteAttacker unsignedIntegerValue];
|
||||
MPAttacker attackHardware = [[MPConfig get].siteAttacker integerValue];
|
||||
if ([algorithm timeToCrack:&timeToCrack passwordOfType:site.type byAttacker:attackHardware] ||
|
||||
[algorithm timeToCrack:&timeToCrack passwordString:password byAttacker:attackHardware])
|
||||
timeToCrackString = NSStringFromTimeToCrack( timeToCrack );
|
||||
|
||||
@@ -89,9 +89,14 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
MPStoreProductCell *cell = (MPStoreProductCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
if (cell.contentView.translatesAutoresizingMaskIntoConstraints) {
|
||||
cell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[cell addConstraint:
|
||||
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual
|
||||
toItem:cell.contentView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]];
|
||||
[cell addConstraints:@[
|
||||
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
|
||||
toItem:cell.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:0],
|
||||
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
|
||||
toItem:cell.contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0],
|
||||
[NSLayoutConstraint constraintWithItem:cell attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
|
||||
toItem:cell.contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0],
|
||||
]];
|
||||
}
|
||||
|
||||
if (indexPath.section == 0)
|
||||
@@ -119,7 +124,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
|
||||
[cell layoutIfNeeded];
|
||||
[cell layoutIfNeeded];
|
||||
|
||||
dbg_return_tr( cell.contentView.bounds.size.height, @ );
|
||||
dbg_return_tr( cell.contentView.bounds.size.height, @, indexPath );
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
@property(weak, nonatomic) IBOutlet UIView *thanksTipContainer;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *nextAvatarButton;
|
||||
@property(weak, nonatomic) IBOutlet UIButton *previousAvatarButton;
|
||||
@property(weak, nonatomic) IBOutlet NSLayoutConstraint *keyboardHeightConstraint;
|
||||
|
||||
@property(assign, nonatomic, readonly) BOOL active;
|
||||
|
||||
|
||||
@@ -649,6 +649,12 @@ referenceSizeForFooterInSection:(NSInteger)section {
|
||||
self.userSelectionContainer.alpha = 1;
|
||||
}];
|
||||
} );
|
||||
PearlAddNotificationObserver( UIKeyboardWillShowNotification, nil, [NSOperationQueue mainQueue],
|
||||
^(MPUsersViewController *self, NSNotification *note) {
|
||||
CGRect keyboardRect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGFloat keyboardHeight = CGRectGetHeight( self.view.window.screen.bounds ) - CGRectGetMinY( keyboardRect );
|
||||
[self.keyboardHeightConstraint updateConstant:keyboardHeight];
|
||||
} );
|
||||
|
||||
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
|
||||
@@ -2599,8 +2599,6 @@
|
||||
DAFE45FC15039823003ABA7C /* Pearl-Crypto */,
|
||||
DAFE460715039823003ABA7C /* Pearl-UIKit */,
|
||||
DAC77CB1148291A600BCF976 /* Pearl-Prefix.pch */,
|
||||
DACA29751705E2BD002C6C22 /* jrswizzle */,
|
||||
DACA29B41705E2DE002C6C22 /* uicolor-utilities */,
|
||||
);
|
||||
path = Pearl;
|
||||
sourceTree = "<group>";
|
||||
@@ -2612,6 +2610,8 @@
|
||||
DA32D03719D111EB004F3F0E /* KCOrderedAccessorFix */,
|
||||
DAA141181922FED80032B392 /* iOS */,
|
||||
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */,
|
||||
DACA29751705E2BD002C6C22 /* jrswizzle */,
|
||||
DACA29B41705E2DE002C6C22 /* uicolor-utilities */,
|
||||
DAC77CAF148291A600BCF976 /* Pearl */,
|
||||
);
|
||||
name = External;
|
||||
@@ -2653,8 +2653,7 @@
|
||||
DACA29771705E2BD002C6C22 /* JRSwizzle.h */,
|
||||
DACA298C1705E2BD002C6C22 /* JRSwizzle.m */,
|
||||
);
|
||||
name = jrswizzle;
|
||||
path = External/jrswizzle;
|
||||
path = jrswizzle;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DACA29B41705E2DE002C6C22 /* uicolor-utilities */ = {
|
||||
@@ -2665,8 +2664,7 @@
|
||||
DACA29BA1705E2DE002C6C22 /* UIColor+Expanded.m */,
|
||||
DACA29BB1705E2DE002C6C22 /* UIColor+HSV.m */,
|
||||
);
|
||||
name = "uicolor-utilities";
|
||||
path = "External/uicolor-utilities";
|
||||
path = "uicolor-utilities";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAFC5662172C57EC00CB5CC5 /* InAppSettingsKit */ = {
|
||||
@@ -3932,7 +3930,7 @@
|
||||
Reveal,
|
||||
);
|
||||
PROVISIONING_PROFILE = "";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "78fbee53-abe7-4a47-b917-c223df3a6952";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "3251b7d3-04df-4c8e-a410-d020ffc92d10";
|
||||
SKIP_INSTALL = NO;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
@@ -3958,7 +3956,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
PROVISIONING_PROFILE = "";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "d02e889e-2701-47eb-b843-4f16c431b284";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "59b587d0-3ef3-4691-9f12-c48f7f283002";
|
||||
SKIP_INSTALL = NO;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
@@ -4065,7 +4063,7 @@
|
||||
"$(inherited)",
|
||||
);
|
||||
PROVISIONING_PROFILE = "";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "48f9bae8-b80e-41c7-8792-663102bed54f";
|
||||
"PROVISIONING_PROFILE[sdk=iphoneos*]" = "a1d8cfc8-b8db-4544-af34-28cc75e46c40";
|
||||
SKIP_INSTALL = NO;
|
||||
STRIP_INSTALLED_PRODUCT = YES;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
|
||||
@@ -126,7 +126,7 @@ To see a site's password anyway, tap and hold your finger down for a while
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
<string>3</string>
|
||||
<integer>3</integer>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
|
||||
@@ -133,7 +133,6 @@
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="216" id="GcG-kq-fq2"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="216" id="yUb-JQ-gv0"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rWM-08-aab" userLabel="Users Root">
|
||||
@@ -173,10 +172,10 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_spinner.png" translatesAutoresizingMaskIntoConstraints="NO" id="y4j-ds-HM7" userLabel="Spinner">
|
||||
<rect key="frame" x="52" y="-13" width="110" height="110"/>
|
||||
<rect key="frame" x="52" y="216" width="110" height="110"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="avatar-0.png" translatesAutoresizingMaskIntoConstraints="NO" id="Aca-he-7Qi" userLabel="Avatar">
|
||||
<rect key="frame" x="52" y="-13" width="110" height="110"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="755" verticalCompressionResistancePriority="755" image="avatar-0.png" translatesAutoresizingMaskIntoConstraints="NO" id="Aca-he-7Qi" userLabel="Avatar">
|
||||
<rect key="frame" x="52" y="216" width="110" height="110"/>
|
||||
<color key="tintColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="110" id="Ezz-dq-dfq"/>
|
||||
@@ -184,7 +183,7 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Sa-Vg-EEI" userLabel="Name Backdrop">
|
||||
<rect key="frame" x="43" y="34" width="128.5" height="16"/>
|
||||
<rect key="frame" x="43" y="263" width="128.5" height="16"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalCompressionResistancePriority="1000" text="Maarten Billemont" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cLT-s0-4SQ" userLabel="Name Field">
|
||||
<rect key="frame" x="5" y="0.0" width="118.5" height="16"/>
|
||||
@@ -206,7 +205,7 @@
|
||||
</view>
|
||||
<constraints>
|
||||
<constraint firstItem="J7b-uT-zY2" firstAttribute="leading" secondItem="Zab-uQ-uk9" secondAttribute="leading" id="1Sw-vq-MuH"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="750" id="1zu-ay-NUc"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="250" id="1zu-ay-NUc"/>
|
||||
<constraint firstItem="y4j-ds-HM7" firstAttribute="centerX" secondItem="Aca-he-7Qi" secondAttribute="centerX" id="D6m-xp-Ja0"/>
|
||||
<constraint firstAttribute="centerX" secondItem="0Sa-Vg-EEI" secondAttribute="centerX" id="EYH-CQ-6TX"/>
|
||||
<constraint firstItem="0Sa-Vg-EEI" firstAttribute="top" secondItem="Aca-he-7Qi" secondAttribute="bottom" priority="500" constant="8" symbolic="YES" id="F67-h9-FDi"/>
|
||||
@@ -218,16 +217,18 @@
|
||||
<constraint firstItem="y4j-ds-HM7" firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" id="b7q-13-zb4"/>
|
||||
<constraint firstAttribute="centerY" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="500" id="fKx-ZZ-sJa"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="top" secondItem="Zab-uQ-uk9" secondAttribute="top" constant="20" id="kO6-Hn-9ab"/>
|
||||
<constraint firstItem="Aca-he-7Qi" firstAttribute="centerY" relation="greaterThanOrEqual" secondItem="Zab-uQ-uk9" secondAttribute="top" priority="751" constant="60" id="qu4-jD-JoX"/>
|
||||
<constraint firstAttribute="bottom" secondItem="J7b-uT-zY2" secondAttribute="bottom" id="sKD-RY-oA8"/>
|
||||
<constraint firstItem="CQo-kd-XAU" firstAttribute="leading" secondItem="Zab-uQ-uk9" secondAttribute="leading" id="trm-Bp-zf3"/>
|
||||
<constraint firstItem="y4j-ds-HM7" firstAttribute="height" secondItem="Aca-he-7Qi" secondAttribute="height" id="wyT-4c-SaV"/>
|
||||
<constraint firstItem="J7b-uT-zY2" firstAttribute="top" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="250" constant="180" id="xgw-C1-V3h"/>
|
||||
<constraint firstItem="J7b-uT-zY2" firstAttribute="top" secondItem="Aca-he-7Qi" secondAttribute="centerY" priority="750" constant="180" id="xgw-C1-V3h"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="avatarImageView" destination="Aca-he-7Qi" id="Me2-jn-hSX"/>
|
||||
<outlet property="avatarRaisedConstraint" destination="xgw-C1-V3h" id="cHf-dg-hD9"/>
|
||||
<outlet property="avatarSizeConstraint" destination="Ezz-dq-dfq" id="FLf-Gq-Pdw"/>
|
||||
<outlet property="avatarToTopConstraint" destination="1zu-ay-NUc" id="i4J-5Z-Ky7"/>
|
||||
<outlet property="keyboardHeightConstraint" destination="KPB-We-gf0" id="gG1-Fl-VqV"/>
|
||||
<outlet property="nameContainer" destination="0Sa-Vg-EEI" id="VLy-AI-Yh8"/>
|
||||
<outlet property="nameLabel" destination="cLT-s0-4SQ" id="85r-AJ-Zkb"/>
|
||||
<outlet property="nameToCenterConstraint" destination="Ht7-Iz-cAW" id="zeF-2U-6GW"/>
|
||||
@@ -460,9 +461,11 @@
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="VDd-oM-ZOO" secondAttribute="centerX" id="0j9-vM-WFA"/>
|
||||
<constraint firstItem="zCP-wo-gTl" firstAttribute="top" secondItem="rWM-08-aab" secondAttribute="top" constant="20" id="1ly-9W-ybj"/>
|
||||
<constraint firstItem="cF4-TE-GEj" firstAttribute="bottom" secondItem="9u7-pu-Wtv" secondAttribute="top" id="3oq-Zs-Ann"/>
|
||||
<constraint firstItem="cF4-TE-GEj" firstAttribute="bottom" secondItem="9u7-pu-Wtv" secondAttribute="top" priority="500" id="3oq-Zs-Ann"/>
|
||||
<constraint firstItem="0Um-Ot-hI6" firstAttribute="top" secondItem="zCP-wo-gTl" secondAttribute="centerY" id="6zz-7f-HLz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="L6J-pd-gcp" secondAttribute="trailing" id="9fV-8e-y3E"/>
|
||||
<constraint firstItem="fUK-gJ-NRE" firstAttribute="centerY" relation="greaterThanOrEqual" secondItem="L6J-pd-gcp" secondAttribute="top" constant="60" id="ADW-TA-Iha"/>
|
||||
<constraint firstItem="9u7-pu-Wtv" firstAttribute="centerY" relation="greaterThanOrEqual" secondItem="L6J-pd-gcp" secondAttribute="top" constant="60" id="AQZ-W6-Xkf"/>
|
||||
<constraint firstItem="L6J-pd-gcp" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="BcO-0y-Nih"/>
|
||||
<constraint firstAttribute="centerX" secondItem="cF4-TE-GEj" secondAttribute="centerX" id="CvC-rv-8KE"/>
|
||||
<constraint firstItem="qp1-nX-o4i" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="DY1-Ad-Mbi"/>
|
||||
@@ -470,6 +473,7 @@
|
||||
<constraint firstItem="0Um-Ot-hI6" firstAttribute="centerX" secondItem="zCP-wo-gTl" secondAttribute="centerX" id="OJA-7u-h1T"/>
|
||||
<constraint firstAttribute="bottom" secondItem="XEP-O3-ayG" secondAttribute="bottom" id="PpW-Of-YOc"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fUK-gJ-NRE" secondAttribute="trailing" id="TBr-pS-kEK"/>
|
||||
<constraint firstItem="cF4-TE-GEj" firstAttribute="top" relation="greaterThanOrEqual" secondItem="L6J-pd-gcp" secondAttribute="top" constant="4" id="VHh-25-0mJ"/>
|
||||
<constraint firstAttribute="trailing" secondItem="qp1-nX-o4i" secondAttribute="trailing" id="cOq-BS-Xmo"/>
|
||||
<constraint firstAttribute="centerY" secondItem="VDd-oM-ZOO" secondAttribute="centerY" id="dxP-im-1dM"/>
|
||||
<constraint firstItem="zCP-wo-gTl" firstAttribute="leading" secondItem="rWM-08-aab" secondAttribute="leading" id="jBY-Gd-orW"/>
|
||||
@@ -486,9 +490,9 @@
|
||||
<constraint firstItem="VGz-R0-vMD" firstAttribute="top" secondItem="X8H-vh-j7B" secondAttribute="bottom" id="8Ed-3Y-ll0"/>
|
||||
<constraint firstAttribute="trailing" secondItem="X8H-vh-j7B" secondAttribute="trailing" id="8Gr-Dq-UpZ"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rWM-08-aab" secondAttribute="bottom" id="9Yx-cj-wHh"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="9u7-pu-Wtv" secondAttribute="centerY" constant="180" id="Gp5-h6-53S"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="9u7-pu-Wtv" secondAttribute="centerY" priority="500" constant="180" id="Gp5-h6-53S"/>
|
||||
<constraint firstItem="rWM-08-aab" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="Il8-kg-Dra"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="fUK-gJ-NRE" secondAttribute="centerY" constant="180" id="PgC-ZL-cQo"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="fUK-gJ-NRE" secondAttribute="centerY" priority="500" constant="180" id="PgC-ZL-cQo"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rWM-08-aab" secondAttribute="trailing" id="UPP-1n-zIe"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="top" secondItem="qp1-nX-o4i" secondAttribute="bottom" constant="20" id="WdK-tA-njz"/>
|
||||
<constraint firstItem="X8H-vh-j7B" firstAttribute="leading" secondItem="DOr-Xu-P9q" secondAttribute="leading" id="jbn-ko-MPq"/>
|
||||
@@ -506,6 +510,7 @@
|
||||
<outlet property="entryTipSubtitleLabel" destination="KhE-Yj-Kvm" id="G0X-19-RmH"/>
|
||||
<outlet property="entryTipTitleLabel" destination="ZI7-qg-7OW" id="dZj-rZ-efd"/>
|
||||
<outlet property="footerContainer" destination="XEP-O3-ayG" id="9cI-p9-av3"/>
|
||||
<outlet property="keyboardHeightConstraint" destination="GcG-kq-fq2" id="V1s-Sz-0Zp"/>
|
||||
<outlet property="marqueeButton" destination="4md-Gp-SLG" id="bUt-IL-8P1"/>
|
||||
<outlet property="nextAvatarButton" destination="fUK-gJ-NRE" id="5qo-lK-rSa"/>
|
||||
<outlet property="preferencesTipContainer" destination="0Um-Ot-hI6" id="Cv8-Bp-ZZs"/>
|
||||
@@ -2809,7 +2814,7 @@ See </string>
|
||||
<outlet property="purchasedIndicator" destination="yZX-ns-8oV" id="7x0-eq-oSs"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellFuel" rowHeight="394" id="le3-Q5-MSO" userLabel="Fuel" customClass="MPStoreProductCell">
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" shouldIndentWhileEditing="NO" reuseIdentifier="MPStoreProductCellFuel" rowHeight="407" id="le3-Q5-MSO" userLabel="Fuel" customClass="MPStoreProductCell">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="97"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="le3-Q5-MSO" id="SzQ-Y5-XIF">
|
||||
@@ -2823,12 +2828,13 @@ See </string>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fz2-AO-aGW">
|
||||
<rect key="frame" x="20" y="254" width="335" height="119.5"/>
|
||||
<rect key="frame" x="20" y="254" width="335" height="132"/>
|
||||
<string key="text">You really love Master Password and how it's solving your password problems. You're eager to encourage the maintenance, technical support and development of new features. I am a one-man shop, fuel enables me to allocate more work hours to Master Password.
|
||||
|
||||
UPCOMING:
|
||||
– Safari integration
|
||||
– Touch ID support
|
||||
– Multi-platform support
|
||||
– Your feedback</string>
|
||||
<fontDescription key="fontDescription" name="Exo2.0-Thin" family="Exo 2.0" pointSize="11"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
@@ -2881,7 +2887,6 @@ invested: 3.7 work hours</string>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="bottom" secondItem="EbU-DV-fKF" secondAttribute="bottom" id="KbL-rF-pVN"/>
|
||||
<constraint firstItem="Jnv-uN-xeg" firstAttribute="top" secondItem="PnG-hP-syh" secondAttribute="bottom" constant="8" symbolic="YES" id="OZV-m1-YZ1"/>
|
||||
<constraint firstItem="dsR-fr-dY4" firstAttribute="top" secondItem="SzQ-Y5-XIF" secondAttribute="top" constant="20" id="VH2-O8-CGj"/>
|
||||
<constraint firstAttribute="bottom" secondItem="fz2-AO-aGW" secondAttribute="bottom" constant="20" symbolic="YES" id="Wqo-Le-AcG"/>
|
||||
<constraint firstItem="eS4-59-Xny" firstAttribute="centerX" secondItem="PnG-hP-syh" secondAttribute="centerX" id="ZbQ-LX-kmS"/>
|
||||
<constraint firstItem="kYb-j4-32C" firstAttribute="leading" secondItem="dsR-fr-dY4" secondAttribute="leading" id="bih-Ha-Tz7"/>
|
||||
<constraint firstItem="EbU-DV-fKF" firstAttribute="leading" secondItem="Jnv-uN-xeg" secondAttribute="trailing" constant="8" symbolic="YES" id="cku-JX-4bK"/>
|
||||
@@ -2891,6 +2896,7 @@ invested: 3.7 work hours</string>
|
||||
<constraint firstAttribute="centerX" secondItem="PnG-hP-syh" secondAttribute="centerX" id="gO5-ME-YVO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="EbU-DV-fKF" secondAttribute="trailing" constant="20" id="hae-Jv-wOU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="fz2-AO-aGW" secondAttribute="trailing" constant="20" id="vlt-qH-1Xx"/>
|
||||
<constraint firstAttribute="bottom" secondItem="fz2-AO-aGW" secondAttribute="bottom" constant="20" symbolic="YES" id="xkO-cL-7m2"/>
|
||||
<constraint firstItem="eS4-59-Xny" firstAttribute="centerY" secondItem="PnG-hP-syh" secondAttribute="centerY" id="yUc-2F-y1r"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<?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>app</key>
|
||||
<string>com.bohemiancoding.sketch3</string>
|
||||
<key>build</key>
|
||||
<integer>8053</integer>
|
||||
<key>commit</key>
|
||||
<string>104f8b8798002207eebbbee810c02306c5ce85c9</string>
|
||||
<key>fonts</key>
|
||||
<array>
|
||||
<string>SourceCodePro-Light</string>
|
||||
<string>LucidaGrande</string>
|
||||
<string>HelveticaNeue-Medium</string>
|
||||
</array>
|
||||
<key>length</key>
|
||||
<integer>918726</integer>
|
||||
<key>version</key>
|
||||
<integer>37</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1 +0,0 @@
|
||||
37
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li class="active"><a href="algorithm.html">Algorithm</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li class="active"><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
@@ -77,42 +75,6 @@
|
||||
<p><b>Master Password is <em>an algorithm used to generate unique passwords</em></b> for websites, email accounts, or anything else <em>based only on easily reproducible input</em>.<br />
|
||||
The goal is a process that avoids all the problems involved with other password solutions.</p>
|
||||
<p>The Master Password algorithm is <i>open</i>: this page describes its inner workings in detail. We believe the following is an important lesson we should all learn: Regardless of how much encryption a solution claims, <a href="http://www.geekzone.co.nz/foobar/5823" onclick="_gaq.push(['_trackPageview', '/outbound/skype']);">if you don't know how it works, you <strong>cannot</strong> assume it is secure</a> (at least, not the kind of secure you care about).</p>
|
||||
|
||||
<h1>The Password Problem</h1>
|
||||
<img class="pull-right" src="img/thumb-authenticate.png" />
|
||||
<p>Passwords are used to authenticate you to someone else. That means, convince someone that you really are who you say you are. The theory is that when you two are the only ones that know a certain secret word, then the other party can be certain of your identity when you prove to them you know the secret word.</p>
|
||||
<p>Authentication using passwords is pretty good in theory but <strong>fails when</strong> the password is either:
|
||||
<ul>
|
||||
<li>Easily guessed by an impersonator.</li>
|
||||
<li>Known by others.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>So the only way to do passwords right is by inventing a secure (ie. hard to guess) and unique (ie. different for each site) password each time.</p>
|
||||
<p>Unfortunately, secure passwords are hard to come up with and even harder to remember.</p>
|
||||
<p>People generally give up and begin reusing passwords between sites. The password is now no longer secret. This can lead to your identity getting stolen when sites get hacked, you get conned by a hoax site, or you sign up with an untrustworthy website.</p>
|
||||
|
||||
<h1>Password Solutions</h1>
|
||||
<p>To help with these problems, there are a bunch of apps available that remember your passwords for you. They accomplish this by saving your passwords in an encrypted vault or by sending them off to a cloud server.</p>
|
||||
<p>These approaches are very helpful, but they come with a few very <em>important</em> <strong>downsides</strong>:
|
||||
<ul>
|
||||
<li>Vaults need to be backed-up to avoid the risk of complete identity loss.</li>
|
||||
<li>Vaults need to be kept nearby and in-sync across the your devices or you won't always be able to access the password you need.</li>
|
||||
<li>Sending passwords to the cloud means handing your keys to a company.</li>
|
||||
<li>When your passwords are in the cloud they may not be available when you have no Internet access.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h1>Solving Availability</h1>
|
||||
<p>Losing all your passwords or other password availability issues are frustrating and sometimes even disastrous.</p>
|
||||
<p>Master Password solves this problem by being a <em>stateless</em> solution. That means that no information needs to be saved in order for the program to be able to give you your password again in the future.</p>
|
||||
<p>Since Master Password doesn't save your passwords and doesn't send them anywhere, it <strong>avoids the following risks</strong>:
|
||||
<ul>
|
||||
<li>Your passwords cannot be found in a file or even a backup.</li>
|
||||
<li>Your passwords cannot be intercepted during sync.</li>
|
||||
<li>You don't need to trust a third party with your secrets.</li>
|
||||
<li>You can't lose your passwords.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="thumb clearfix">
|
||||
|
||||
@@ -189,6 +189,8 @@ header {
|
||||
background: black;
|
||||
text-shadow: black 0 1px 50px;
|
||||
box-shadow: 0 1px 5px #000;
|
||||
|
||||
transition: height 0.3s;
|
||||
}
|
||||
header .container {
|
||||
position: relative;
|
||||
@@ -267,15 +269,19 @@ header .box .maximized {
|
||||
height: 80%;
|
||||
}
|
||||
#app header .background {
|
||||
background: url('../img/shot-laptop-leaning-iphone.png') center center;
|
||||
background: url('../img/shot-laptop-leaning-iphone.jpg') center center;
|
||||
background-size: cover;
|
||||
}
|
||||
#what header,
|
||||
#security header,
|
||||
#algorithm header,
|
||||
#support header {
|
||||
height: 40%;
|
||||
|
||||
background: #272727;
|
||||
}
|
||||
#what header .background,
|
||||
#security header .background,
|
||||
#algorithm header .background,
|
||||
#support header .background {
|
||||
width: 940px;
|
||||
@@ -284,6 +290,8 @@ header .box .maximized {
|
||||
top: -10%;
|
||||
margin-left: -470px;
|
||||
}
|
||||
#what header .container,
|
||||
#security header .container,
|
||||
#algorithm header .container,
|
||||
#support header .container {
|
||||
background: radial-gradient(center, ellipse cover, rgba(0,0,0,0.3) 50%,rgba(0,0,0,0.8) 100%);
|
||||
@@ -321,6 +329,92 @@ header h2 {
|
||||
font-size: 2em;
|
||||
font-style: oblique;
|
||||
}
|
||||
header .movie {
|
||||
display: none;
|
||||
background: url('../img/about.png') no-repeat scroll 50% 40px/cover black;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-top: 40px;
|
||||
}
|
||||
header .movie::after {
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('../img/loading-spin.svg') no-repeat scroll center center transparent;
|
||||
}
|
||||
header.play {
|
||||
height: auto !important;
|
||||
max-height: 94%;
|
||||
}
|
||||
header.play .movie {
|
||||
display: block;
|
||||
}
|
||||
header.play .movie video {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
header.play h1, header.play h2, header.play .box {
|
||||
display: none;
|
||||
}
|
||||
header .moviecontrol {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -.5em;
|
||||
margin-left: -.5em;
|
||||
|
||||
font-size: 400%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
header .moviecontrol::before {
|
||||
content: "▶";
|
||||
}
|
||||
header .moviecontrol:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
header.play .moviecontrol {
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
left: auto;
|
||||
top: auto;
|
||||
}
|
||||
header.play .moviecontrol::before {
|
||||
content: "❙❙";
|
||||
}
|
||||
header .movie::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('../img/video-pattern.png') repeat;
|
||||
background: url('../img/video-bg.png') no-repeat scroll 50% 100%/cover transparent;
|
||||
}
|
||||
header .movie video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100% - 40px);
|
||||
height: auto;
|
||||
}
|
||||
header .movie .fallback {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 60px;
|
||||
text-align: center;
|
||||
z-index: 5;
|
||||
color: #BBB;
|
||||
}
|
||||
footer {
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
@@ -392,3 +486,29 @@ table .box.green {
|
||||
background: #6A6;
|
||||
border: 1px solid #3C3;
|
||||
}
|
||||
|
||||
@media (max-width: 979px) {
|
||||
.content {
|
||||
width: auto;
|
||||
}
|
||||
header .content {
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.pull-right, .pull-left {
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
header h1 {
|
||||
font-size: 4em;
|
||||
}
|
||||
header h2 {
|
||||
font-size: 2em;
|
||||
}
|
||||
header .moviecontrol {
|
||||
top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li class="active"><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li class="active"><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
BIN
Site/2013-05/img/howto-mp-copy.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Site/2013-05/img/howto-mp-copy@2x.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
Site/2013-05/img/howto-mp-create-confirm.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Site/2013-05/img/howto-mp-create-confirm@2x.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
Site/2013-05/img/howto-mp-create.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Site/2013-05/img/howto-mp-create@2x.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
Site/2013-05/img/howto-mp-login.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
Site/2013-05/img/howto-mp-login@2x.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
Site/2013-05/img/howto-mp-type-basic.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
Site/2013-05/img/howto-mp-type-basic@2x.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Site/2013-05/img/howto-mp-type-change.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
Site/2013-05/img/howto-mp-type-change@2x.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
Site/2013-05/img/howto-twitter-done.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Site/2013-05/img/howto-twitter-done@2x.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
Site/2013-05/img/howto-twitter-paste.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
Site/2013-05/img/howto-twitter-paste@2x.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
Site/2013-05/img/howto-twitter-signup.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Site/2013-05/img/howto-twitter-signup@2x.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
Site/2013-05/img/mac-icon-256.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
Site/2013-05/img/play.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
Site/2013-05/img/shot-laptop-leaning-iphone-800@2x.png
Normal file
|
After Width: | Height: | Size: 569 KiB |
BIN
Site/2013-05/img/shot-laptop-leaning-iphone.jpg
Normal file
|
After Width: | Height: | Size: 317 KiB |
BIN
Site/2013-05/img/video-bg.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
Site/2013-05/img/video-pattern.png
Normal file
|
After Width: | Height: | Size: 939 B |
@@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title itemprop="name">Master Password — Secure your life, forget your passwords.</title>
|
||||
<meta itemprop="description" content="Master Password is an ingenious password solution that makes your passwords truly impossible to lose." />
|
||||
<meta itemprop="image" content="http://masterpassword.lyndir.com/img/iTunesArtwork-Rounded.png" />
|
||||
<meta itemprop="image" content="http://masterpassword.lyndir.com/img/about.png" />
|
||||
<meta name="apple-itunes-app" content="app-id=510296984" />
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?6">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -34,21 +34,19 @@
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<a class="active brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
@@ -59,26 +57,21 @@
|
||||
<div class="background" data-stellar-ratio="0.4"></div>
|
||||
<div class="container">
|
||||
|
||||
<div class="movie">
|
||||
<video>
|
||||
<source src="vid/about.webm" type="video/webm; codecs=vp8,vorbis">
|
||||
<source src="vid/about.mp4" type="video/mp4">
|
||||
<source src="vid/about.ogv" type="video/ogg; codecs=theora,vorbis">
|
||||
</video>
|
||||
<h5 class="fallback"><a href="https://vimeo.com/108192090">I've been waiting for <em>hours</em> and it's still loading...</a></h5>
|
||||
</div>
|
||||
<a href="javascript:toggleMovie()" class="moviecontrol" onclick="$(this).toggleClass('active');_gaq.push(['_trackPageview', '/video/about']);"></a>
|
||||
|
||||
<div class="content">
|
||||
<h1>Master Password</h1>
|
||||
<h2>Secure your life, forget your passwords.</h2>
|
||||
</div>
|
||||
|
||||
<div class="box effect-8" onclick="$(this).toggleClass('active');_gaq.push(['_trackPageview', '/video/yt/QTfA0O7YnHQ']);">
|
||||
<div class="minimized">
|
||||
<img class="fit-height" src="http://i.vimeocdn.com/video/318668169_960.jpg" />
|
||||
<div class="middle play"></div>
|
||||
</div>
|
||||
<div class="maximized">
|
||||
<iframe id="youtube" type="text/html" width="853" height="480" frameborder="0"
|
||||
webkitAllowFullScreen mozallowfullscreen allowFullScreen
|
||||
src="http://www.youtube-nocookie.com/embed/QTfA0O7YnHQ?autohide=1&autoplay=0&rel=0&showinfo=0&theme=light&color=white"></iframe>
|
||||
<!--iframe id="vimeo" type="text/html" width="853" height="480" frameborder="0"
|
||||
webkitAllowFullScreen mozallowfullscreen allowFullScreen
|
||||
src="http://player.vimeo.com/video/45803664?autoplay=1&title=0&byline=0&portrait=0&color=ffffff"></iframe-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -4,5 +4,22 @@ $(function(){
|
||||
window.onscroll = function() {
|
||||
document.getElementById("scrollDown").style.opacity = Math.max(0, 200 - window.scrollY) / 200;
|
||||
};
|
||||
|
||||
if (document.location.hash == "#video")
|
||||
toggleMovie();
|
||||
|
||||
$("video")[0].addEventListener("playing", function() {
|
||||
$(this).parents().find(".fallback").hide();
|
||||
}, true);
|
||||
});
|
||||
|
||||
function toggleMovie() {
|
||||
if ($("header").hasClass("play")) {
|
||||
$("header").removeClass("play");
|
||||
$("header video")[0].pause();
|
||||
} else {
|
||||
$("header").addClass("play");
|
||||
$("header video")[0].play();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li class="active"><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
</head>
|
||||
<body itemscope itemtype="http://schema.org/MobileSoftwareApplication" id="trouble">
|
||||
<body itemscope itemtype="http://schema.org/MobileSoftwareApplication" id="security">
|
||||
<!--[if lt IE 7]>
|
||||
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li class="active"><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li class="active"><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
@@ -57,13 +55,6 @@
|
||||
<img class="background" src="img/mp-process-angled.png" data-stellar-ratio="2.5" />
|
||||
<div class="container">
|
||||
|
||||
<!-- <div class="box effect-8">
|
||||
iframe id="ytplayer" type="text/html" width="640" height="360" frameborder="0"
|
||||
src="http://www.youtube.com/embed/QTfA0O7YnHQ?origin=http://masterpassword.lyndir.com&autohide=1&autoplay=0&rel=0&showinfo=0&theme=light&color=white"></iframe
|
||||
<iframe width="640" height="360" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen
|
||||
src="http://player.vimeo.com/video/45803664?title=0&byline=0&portrait=0&color=ffffff"></iframe>
|
||||
</div> -->
|
||||
|
||||
<div class="content">
|
||||
<h2>Security Overview</h2>
|
||||
</div>
|
||||
@@ -305,7 +296,7 @@
|
||||
<h3 id="masterkey" class="inline">The Master Key</h3>
|
||||
<p>The first part of the process it to obtain a very strong "token" of your personal identity. We call this token your <em>master key</em>, because it is very much like the one and only <strong>main key that opens all your doors</strong>. It is a personal key, it represents your identity.</p>
|
||||
<p>The master key is derived from your name and your master password, and thrown away as soon as it's no longer needed to minimize the risk of loss.</p>
|
||||
<p>Since it's vital that nobody else can gain access to your master key, it's important that the process of deriving the key is unsurmountably difficult. An attacker could try a brute-force attack against your master key or password by convincing you to make an account on his website, and then guessing at your master password or your master key until he finds one that gives him your password for his fake site.</p>
|
||||
<p>Since it's vital that nobody else can gain access to your master key, it's important that the process of deriving the key is insurmountably difficult. An attacker could try a brute-force attack against your master key or password by convincing you to make an account on his website, and then guessing at your master password or your master key until he finds one that gives him your password for his fake site.</p>
|
||||
<p>These are two different types of brute-force attacks and we need to make sure to defeat both of them.</p>
|
||||
<p>To defeat a brute-force attack against your master key, we make sure the master key is sufficiently high in entropy. Since the master key is a 256-bit key, an attacker would now have to make up to <code>2<sup>256</sup></code> guesses, or try <code>115792089237316195423570985008687907853269984665640564039457584007913129639936</code> master keys before finding the right one. Even at an ambitious rate of 2 billion tries per second, it would take several times the age of the universe to try all of them.
|
||||
<p>A brute-force attack against your master password is more feasible, since your master password will be tiny compared to such a huge master key.</p>
|
||||
@@ -357,9 +348,9 @@
|
||||
|
||||
<div class="hlvl">
|
||||
<p><h2 class="inline">Custom passwords</h2>
|
||||
are sometimes still a necessity. You may want to store a password you've been using for a long time in your manager, or your boss may have set an unchangable password on your computer for you to use. Since Master Password's passwords are a mathematical result of your unchanging master password, it is impossible for it to be used with passwords that are created via another way.</p>
|
||||
are sometimes still a necessity. You may want to store a password you've been using for a long time in your manager, or your boss may have set an unchangeable password on your computer for you to use. Since Master Password's passwords are a mathematical result of your unchanging master password, it is impossible for it to be used with passwords that are created via another way.</p>
|
||||
<p>The Master Password application however <em>functions as a hybrid password manager, implementing both the Master Password algorithm and a vault-like password solution</em>. In the second mode, Master Password uses your master key to encrypt custom passwords and store the encrypted result in a vault. Since we use the master key for this process, the result is a vault that is much harder to break into than that used by many other vault-based password solutions (specifically
|
||||
because the encryption key is a large key derived from your master pasword using scrypt key derivation). As a result, <strong>this trade-off has been mitigated</strong>.</p>
|
||||
because the encryption key is a large key derived from your master password using scrypt key derivation). As a result, <strong>this trade-off has been mitigated</strong>.</p>
|
||||
</div>
|
||||
|
||||
<div class="hlvl">
|
||||
@@ -376,7 +367,7 @@
|
||||
the "something you know", they'll still need to obtain the "something you have" before they can break in. The most popular example of a two-factor solution is a bank card: Your PIN number is the secret you know, but with the PIN alone a thief can't get to your money. They'll need to first steal your card as well.</p>
|
||||
<p>A vault-based password manager is often considered two-factor, since it relies on your vault password as well as access to your vault file. <em>Most security experts disagree, however</em>. To be truly multi-factor, the security factors should come from separate categories:</p>
|
||||
<ul>
|
||||
<li><strong>Knowledge factors</strong>: passwords, keyfiles, other secret data or information</li>
|
||||
<li><strong>Knowledge factors</strong>: passwords, key files, other secret data or information</li>
|
||||
<li><strong>Possession factors</strong>: physical tokens, smart cards</li>
|
||||
<li><strong>Inherence factors</strong>: biometrics</li>
|
||||
</ul>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li class="active"><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li class="active"><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?1">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
@@ -35,18 +35,16 @@
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="./">App</a></li>
|
||||
<li><a href="security.html">Security</a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="algorithm.html">Algorithm</a></li>
|
||||
<li class="active"><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source (GPL)</a></li>
|
||||
<li><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword (freenode)</a></li>
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
|
||||
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
|
||||
BIN
Site/2013-05/vid/about.mp4
Normal file
BIN
Site/2013-05/vid/about.ogv
Normal file
BIN
Site/2013-05/vid/about.webm
Normal file
243
Site/2013-05/what.html
Normal file
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" itemscope itemtype="http://schema.org/Product">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title itemprop="name">Master Password — Secure your life, forget your passwords.</title>
|
||||
<meta itemprop="description" content="Master Password is an ingenious password solution that makes your passwords truly impossible to lose." />
|
||||
<meta itemprop="image" content="http://masterpassword.lyndir.com/img/iTunesArtwork-Rounded.png" />
|
||||
<meta name="apple-itunes-app" content="app-id=510296984" />
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||
<link rel="stylesheet" href="css/main.css?7">
|
||||
|
||||
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
|
||||
<script src="js/vendor/prefixfree.min.js"></script>
|
||||
</head>
|
||||
<body itemscope itemtype="http://schema.org/MobileSoftwareApplication" id="what">
|
||||
<!--[if lt IE 7]>
|
||||
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
|
||||
<nav class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="brand" href="./">●●●|</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li class="active"><a href="what.html">What is it? How do I use it?</a></li>
|
||||
<li><a href="security.html">Is it safe?</a></li>
|
||||
<li><a href="algorithm.html">How does it work?</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li><a href="irc://irc.freenode.net/#masterpassword" onclick="_gaq.push(['_trackPageview', '/outbound/irc']);">#masterpassword</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="faq.html">FAQ</a></li>
|
||||
<li><a href="support.html">Support</a></li>
|
||||
<li><a href="http://github.com/Lyndir/MasterPassword/" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">Source</a></li>
|
||||
</ul>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<img class="background" src="img/mp-process-angled.png" data-stellar-ratio="2.5" />
|
||||
<div class="container">
|
||||
|
||||
<div class="content">
|
||||
<h2>Master Password is a wholly <strong>different way</strong> of doing passwords.</h2>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section><div class="content">
|
||||
|
||||
<div class="thumb clearfix">
|
||||
|
||||
<h1>The Master Password way</h1>
|
||||
<p>Stop writing down your passwords.</p>
|
||||
<p>Stop storing your passwords in a "secure" place, such as a vault, a keychain, an app or "the cloud".</p>
|
||||
<p>In fact, just stop thinking about passwords at all.</p>
|
||||
<p>Master Password users have no more passwords. They have a password. Their password is their single master key for unlocking all doors.</p>
|
||||
|
||||
<h2>One, two, enter.</h2>
|
||||
<p>As a Master Password user, there are about three steps to entering any site:</p>
|
||||
<ol>
|
||||
<li>Enter your master password to unlock your Master Password app.</li>
|
||||
<li>Find the name of the site you want to get into, copy its key.</li>
|
||||
<li>Paste the site's key into the site and log in.</li>
|
||||
</ol>
|
||||
<p>Most browsers will then ask you to "save" the site's password. For most people, this is a good idea and will subsequently allow you to log in without having to use Master Password at all.</p>
|
||||
|
||||
<h2>How do I get started?</h2>
|
||||
<p>Depending on how many sites you currently hold active accounts on, this is likely going to be your biggest curve.</p>
|
||||
<p>Master Password <strong><em>generates passwords</em> for you to use</strong>. That means, you <em>cannot use your old passwords with it</em> (in truth, you could, but that would defeat the purpose - you <em>shouldn't</em>).</p>
|
||||
<p>For every site where you currently hold an account:<br />
|
||||
Sorry, you'll have to log into the site once with your old password and update the password to the new and much stronger password Master Password has generated for you.</p>
|
||||
<p>For every site you sign up with from now on:<br />
|
||||
Simple: stop trying to come up with a good new password for your next account. Just copy/paste Master Password's generated password for this site into the password and confirm password fields.</p>
|
||||
|
||||
<h3>I want pictures.</h3>
|
||||
<p>All right. Here's Robert on his iPhone:</p>
|
||||
<p><img src="img/howto-twitter-signup.png" /></p>
|
||||
<p>He wants to sign up for Twitter. Robert filled in all the fields, except for password. Not wanting to worry about what his twitter secret is going to be, he switches to Master Password.</p>
|
||||
<img src="img/howto-mp-login.png" /></p>
|
||||
<p>Of course, he begins by unlocking his user with his master password. Robert can skip this step by going into Master Password's preferences and setting it to either save his master key or remember his login, but he choses not to.</p>
|
||||
|
||||
<p><img src="img/howto-mp-create.png" />
|
||||
<img src="img/howto-mp-create-confirm.png" /></p>
|
||||
He creates a password for Twitter by using its <strong>bare domain name</strong>: <code>twitter.com</code>. He knows not to use <strike><code>mobile.twitter.com</code></strike> or <strike><code>Twitter</code></strike> or anything non-standard, because that would be very difficult to remember correctly on a later date. If he has multiple twitter accounts, he could prefix the name with a user name and an @: <code>rmitchell@twitter.com</code>,
|
||||
<code>superbob@twitter.com</code>.</p>
|
||||
<p><strong>Optional:</strong><br />
|
||||
<img src="img/howto-mp-type-change.png" />
|
||||
<img src="img/howto-mp-type-basic.png" /></p>
|
||||
<p>If the account Robert's signing up for is with a website that prohibits symbols for some daft reason, Robert can change the type to <em>Basic</em> or something similar instead. Robert can also bump up the complexity to get an even more secure password if he wants.</p>
|
||||
<p><img src="img/howto-twitter-paste.png" />
|
||||
<img src="img/howto-twitter-done.png" /></p>
|
||||
<p>When Robert created the site in Master Password, it copied the password to his pasteboard. Now, Robert just switches back to Safari and pastes his brand-new password he doesn't care to remember in twitter's password field. All done!</p>
|
||||
|
||||
<h2>Why, that sounds more complicated.</h2>
|
||||
<p>More complicated than what, exactly? Using <code>robert17</code> for all your sites? Well, yes. That's also rather the point.</p>
|
||||
<p>The point is to eliminate the many sources of insecurities related to password authentication, and yet keeping the process surprizingly trivial. What you get in exchange for these two extra first-time only steps is very robust, unique passwords which are not hackable even from a site's leaked password hashes, in addition to the freedom to forget all about passwords. Entirely.</p>
|
||||
<ul>
|
||||
<li>You get to stop worrying about what password you used for your bank or the government tax portal, because they both use ridiculous and different password policies.</li>
|
||||
<li>You get to stop writing down passwords and keeping those notes safe from others as well as safe from loss.</li>
|
||||
<li>You get to stop messing with password vaults that promise to encrypt your stuff, but can't help you when you're at a friend's house, or after your apartment fire.</li>
|
||||
<li>You can stop sharing the keys to your digital life with online password websites that promise all the military grade encryption while being gagged and tapped by a government agency.</li>
|
||||
</ul>
|
||||
|
||||
<h2>I use this other password manager, and it's awesome.</h2>
|
||||
<p>I shall not endeavour to quarrel with the point on the awesome scale of your other password manager. That said, Master Password was designed from the ground up specifically because of the many flaws that existed in all the popular password managers at the time. And the times haven't changed for the better since.</p>
|
||||
<p>I'm going to provide an excessively brief description of the primary flaws other password managers suffer, which Master Password is free from. Please <a href="support.html">contact me</a> if you have something to add, ask or correct.</p>
|
||||
|
||||
<p>While each of these services have many great pros, I will only mention those that Master Password lacks.</p>
|
||||
<ul>
|
||||
|
||||
<li><strong>Password Vaults</strong>: 1Password, Mac OS X Keychain, KeePass, ...
|
||||
<p><em>Pros:</em> Some allow you the ability to change your master password or reset it if you forgot it.</p>
|
||||
<p><em>Cons:</em> Your vault needs to be backed up, and you can only access your passwords if you can access the vault. Syncing the vault to all your devices is troublesome and generally relies on uploading your secrets to a company's servers. Total data loss is catastrophic.</p></li>
|
||||
|
||||
<li><strong>Online Vaults</strong>: LastPass, Secret Server, Mitto, ...
|
||||
<p><em>Pros:</em> Some allow you the ability to change your master password or reset it if you forgot it. Some support "two-factor" authentication.</p>
|
||||
<p><em>Cons:</em> Access to your secrets depends on an active data connection. You've given the keys to your global digital identity to some company you probably shouldn't trust as much as you wish you could. Their website stating that they "can't access your data" doesn't change this, nor does it make any assurances about tomorrow.</p></li>
|
||||
|
||||
<li><strong>Password Generators</strong>: SuperGenPass, PasswordMaker, PassHash, ...
|
||||
<p><em>Pros:</em> They got the same idea as us! Yay!</p>
|
||||
<p><em>Cons:</em> Sadly, nearly all of these, while claiming the same benefits as Master Password, suffer from critical flaws which either defeat their benefits (reverting them to mere password vaults) or use critically weak crypto, with the result of actually making it trivial to reverse your master password - and by extension, access to all your accounts.</p></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<h2>What are Master Password's cons? Or is it flawless?</h2>
|
||||
<p>Master Password also has cons. Let's be frank and list the cons that the other solutions generally don't suffer:</p>
|
||||
<p><em>Cons:</em> Changing your master password requires you to update all your site passwords. A compromised or forgotten master password requires you to do the same.</p>
|
||||
|
||||
<p>There are some other cons, which I consider <em>"fake cons"</em>, with a justification of why I label them as such:</p>
|
||||
<ul>
|
||||
<li><em>My boss gave me this password to use...</em>
|
||||
<p>Master Password's generated passwords only work if you use the password generated for you. You cannot use a password somebody else gave you. Only - you can: Master Password implements a hybrid solution, allowing you to save custom passwords in the app. They are AES encrypted with your master key, but like all vault-based password managers, are not immune to loss if you ever lose your phone and
|
||||
backups..</li>
|
||||
<li><em>I can't reset if I forgot my master password!</em>
|
||||
<p>Uh, no. If you forgot your master password, you're probably an alien replica of yourself. So no, you can't reset. If you're not a replica, just make a new user with a new master password and reset all your site passwords. Remember your master password this time.</li>
|
||||
<li><em>I noticed everybody's doing this two-factor thing now.</em>
|
||||
<p>Two factor authentication is defined as authenticating yourself with two methods that are so distinct that a single attack cannot compromise both. Many sites claim to use two-factor authentication but actually rely only on an extra password hidden in an app on your phone or computer. If an attacker can steal your master password, he can probably download the hidden password too. Or read in your two-factor response while you're typing it in. On top of that, you're using a password manager: after your "two-factor" authentication, you get a single password to perform another one-factor authentication with a site. As a hacker, I'd go for the weakest link to break your chain.</li>
|
||||
</ul>
|
||||
|
||||
<h2>You speak of trust, how can I trust you?</h2>
|
||||
<p>A very valid question, and arguably the most important one to ask!</p>
|
||||
<p>Trust is a very difficult thing to guarantee. Powerful entities will solicit your trust by appearing with it and coming well recommended. Trust can also be assured by legalese or contracts. If you have the means and energy to hold an entity responsible for his claims and actions, this might be sufficient for you.</p>
|
||||
<p>Most of us mere mortals cannot afford this level of trust enforcement, however. We're mostly left in the position of trusting claims blindly, in the hopes that companies will not violate those claims for fear of taking a seizable public-relations hit.</p>
|
||||
<h3>I propose that none of these forms of trust are sufficient adequate.</h3>
|
||||
<p>In fact, Master Password is what it is because it aims to avoid any requirement of trust in the solution's author. Master Password requires no services or proprietary storage format. I've published Master Password's algorithm for you to inspect and licensed to you the full source code to the implementations for you to use.</p>
|
||||
<p>What that gives you, is the ability to either inspect and learn how Master Password works or to take this information to a professional (be it an academic, mathematician or payed developer) and have him do this for you.</p>
|
||||
<p>While at first glimpse, this may not seem terribly useful to you - particularly when you don't have the skill set to perform this verification yourself - but it's actually a pretty big deal to show your naked self as proof of having nothing to hide. If you want to go all the way, you could even build the application from scratch rather than rely on the binaries provided by our distributions.</p>
|
||||
<p>This is the closest we can get to voiding any need for trust in Master Password, and it's more than you're likely to find in most other popular password solutions.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div></section>
|
||||
|
||||
<footer><div class="muted content">
|
||||
|
||||
<p><em>Master Password is a security product and algorithm by <a href="http://www.lhunath.com" onclick="_gaq.push(['_trackPageview', '/outbound/lhunath']);">Maarten Billemont</a>, <a href="http://www.lyndir.com" onclick="_gaq.push(['_trackPageview', '/outbound/lyndir']);">Lyndir</a> (© 2011-2013).</em></p>
|
||||
<p><a href="http://gorillas.lyndir.com" onclick="_gaq.push(['_trackPageview', '/outbound/gorillas']);">Gorillas</a> ● <a href="http://deblock.lyndir.com" onclick="_gaq.push(['_trackPageview', '/outbound/deblock']);">DeBlock</a> ● <a href="http://github.com/Lyndir" onclick="_gaq.push(['_trackPageview', '/outbound/github']);">GitHub</a> ● <a href="http://thanks.lhunath.com" onclick="_gaq.push(['_trackPageview', '/outbound/thanks']);">Send Thanks</a></p>
|
||||
|
||||
</div></footer>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
|
||||
|
||||
<script src="js/vendor/bootstrap.min.js"></script>
|
||||
|
||||
<script src="js/plugins.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
<!-- Internet Defense League -->
|
||||
<script type="text/javascript">
|
||||
window._idl = {};
|
||||
_idl.variant = "modal";
|
||||
(function() {
|
||||
var idl = document.createElement('script');
|
||||
idl.type = 'text/javascript';
|
||||
idl.async = true;
|
||||
idl.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'members.internetdefenseleague.org/include/?url=' + (_idl.url || '') + '&campaign=' + (_idl.campaign || '') + '&variant=' + (_idl.variant || 'banner');
|
||||
document.getElementsByTagName('body')[0].appendChild(idl);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- Google Analytics -->
|
||||
<script>
|
||||
var _gaq=[['_setAccount','UA-90535-15'],['_trackPageview']];
|
||||
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
|
||||
s.parentNode.insertBefore(g,s)}(document,'script'));
|
||||
</script>
|
||||
|
||||
<!-- Google +1 -->
|
||||
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
|
||||
|
||||
<!-- Tender -->
|
||||
<script src="https://masterpassword.tenderapp.com/tender_widget.js" type="text/javascript"></script>
|
||||
|
||||
<!-- AdWords -->
|
||||
<script type="text/javascript">
|
||||
/* <![CDATA[ */
|
||||
goog_snippet_vars = function() {
|
||||
var w = window;
|
||||
w.google_conversion_id = 1015576061;
|
||||
w.google_conversion_label = "PcXqCPPz5AIQ_euh5AM";
|
||||
w.google_conversion_value = 4;
|
||||
}
|
||||
goog_report_conversion = function(url) {
|
||||
goog_snippet_vars();
|
||||
window.google_conversion_format = "3";
|
||||
window.google_is_call = true;
|
||||
var opt = new Object();
|
||||
opt.onload_callback = function() {
|
||||
if (typeof(url) != 'undefined') {
|
||||
window.location = url;
|
||||
}
|
||||
}
|
||||
var conv_handler = window['google_trackConversion'];
|
||||
if (typeof(conv_handler) == 'function') {
|
||||
conv_handler(opt);
|
||||
}
|
||||
}
|
||||
/* ]]> */
|
||||
</script>
|
||||
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion_async.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||