Compare commits
64 Commits
2.0-appsto
...
2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c97546a232 | ||
|
|
88fdc89f27 | ||
|
|
9109a59410 | ||
|
|
61bed8b29c | ||
|
|
72b1d36626 | ||
|
|
6e14554f95 | ||
|
|
fecbd2ea1c | ||
|
|
1c5f5675a5 | ||
|
|
76b717e06d | ||
|
|
eb48f749e2 | ||
|
|
398f7bdb66 | ||
|
|
d40ccee0fe | ||
|
|
a481626f80 | ||
|
|
24c48a78f8 | ||
|
|
edda3cf12a | ||
|
|
6c2cd01015 | ||
|
|
c9988d8cc2 | ||
|
|
a8bb434ded | ||
|
|
1e8a832cba | ||
|
|
4f70e0f676 | ||
|
|
9d7799c814 | ||
|
|
2adb74c971 | ||
|
|
cc80a66331 | ||
|
|
cf8ecb2952 | ||
|
|
adcea94a37 | ||
|
|
3ebef16007 | ||
|
|
3225985e1e | ||
|
|
76280ac71c | ||
|
|
f47ff67ba9 | ||
|
|
65cef6d8ed | ||
|
|
89145d6e13 | ||
|
|
63b4c605e2 | ||
|
|
b3b7858c1d | ||
|
|
eb4ea08a8b | ||
|
|
51d61b8bc0 | ||
|
|
bddbd199e2 | ||
|
|
b579dac180 | ||
|
|
609675f663 | ||
|
|
c57bd5d5d3 | ||
|
|
a4fe13842a | ||
|
|
56bb5bf5db | ||
|
|
f720d552bb | ||
|
|
ce8a00fd48 | ||
|
|
d72defb0bc | ||
|
|
27f6bd7905 | ||
|
|
2aebcadf70 | ||
|
|
cf750f30e0 | ||
|
|
cf52221175 | ||
|
|
adc79d331b | ||
|
|
942d10e7a2 | ||
|
|
aa60dcfbe4 | ||
|
|
a831e15b3e | ||
|
|
18ae7a316f | ||
|
|
7bcc631caf | ||
|
|
caab474355 | ||
|
|
2d4e26e009 | ||
|
|
7ce8df664c | ||
|
|
6597a44096 | ||
|
|
b481af2a51 | ||
|
|
60ecd8181e | ||
|
|
31b2f22ded | ||
|
|
9d5c2e29af | ||
|
|
3740ade240 | ||
|
|
9f2c83e4a9 |
2
External/InAppSettingsKit
vendored
2
External/Pearl
vendored
2
External/UbiquityStoreManager
vendored
6
External/iOS/Crashlytics.framework/Modules/module.modulemap
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
framework module Crashlytics {
|
||||
umbrella header "Crashlytics.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
@@ -15,13 +15,13 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.2.1</string>
|
||||
<string>2.2.4</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>35</string>
|
||||
<string>38</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>iphoneos</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
|
||||
BIN
External/iOS/Crashlytics.framework/run
vendored
BIN
External/iOS/Crashlytics.framework/submit
vendored
@@ -10,57 +10,69 @@
|
||||
<string>MasterPassword</string>
|
||||
<key>IDESourceControlProjectOriginsDictionary</key>
|
||||
<dict>
|
||||
<key>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</key>
|
||||
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
|
||||
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
|
||||
<string>git://github.com/Lyndir/love-lyndir.client.git</string>
|
||||
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
|
||||
<string>git://github.com/lhunath/UbiquityStoreManager.git</string>
|
||||
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
||||
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
|
||||
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
|
||||
<string>ssh://github.com/Lyndir/Pearl.git</string>
|
||||
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
|
||||
<key>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</key>
|
||||
<string>github.com:Lyndir/Lyndir.git</string>
|
||||
<key>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</key>
|
||||
<string>git://github.com/lhunath/uicolor-utilities.git</string>
|
||||
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
||||
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
|
||||
<string>git://github.com/lhunath/RHStatusItemView.git</string>
|
||||
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
|
||||
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
|
||||
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
||||
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
|
||||
<string>ssh://github.com/Lyndir/Pearl.git</string>
|
||||
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
|
||||
<string>git://github.com/jonmarimba/jrswizzle.git</string>
|
||||
<key>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</key>
|
||||
<string>git://github.com/lhunath/UbiquityStoreManager.git</string>
|
||||
<key>F788B28042EDBEF29EFE34687DA79A778C2CC260</key>
|
||||
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectPath</key>
|
||||
<string>MasterPassword.xcworkspace</string>
|
||||
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
||||
<dict>
|
||||
<key>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</key>
|
||||
<string>../External/InAppSettingsKit</string>
|
||||
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
|
||||
<string>../External/LoveLyndir</string>
|
||||
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
|
||||
<string>../External/UbiquityStoreManager</string>
|
||||
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
|
||||
<string>..</string>
|
||||
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
|
||||
<string>../External/Pearl</string>
|
||||
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
|
||||
<key>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</key>
|
||||
<string>../..</string>
|
||||
<key>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</key>
|
||||
<string>../External/Pearl/External/uicolor-utilities</string>
|
||||
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
|
||||
<key>3E67FB08419C920516AAC3B00DAAF23073B8CF77</key>
|
||||
<string>../External/RHStatusItemView</string>
|
||||
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
|
||||
<string>../External/InAppSettingsKit</string>
|
||||
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
|
||||
<key>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</key>
|
||||
<string>../External/Pearl</string>
|
||||
<key>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</key>
|
||||
<string>../External/Pearl/External/jrswizzle</string>
|
||||
<key>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</key>
|
||||
<string>../External/UbiquityStoreManager</string>
|
||||
<key>F788B28042EDBEF29EFE34687DA79A778C2CC260</key>
|
||||
<string>..</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectURL</key>
|
||||
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
|
||||
<key>IDESourceControlProjectVersion</key>
|
||||
<integer>110</integer>
|
||||
<integer>111</integer>
|
||||
<key>IDESourceControlProjectWCCIdentifier</key>
|
||||
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
|
||||
<string>F788B28042EDBEF29EFE34687DA79A778C2CC260</string>
|
||||
<key>IDESourceControlProjectWCConfigurations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</string>
|
||||
<string>2A70319CE0F91B35406CA7D970AE7CB4957B0A75</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>1712FC0BC3C9AABD8B7B5376E310E93FBDB3BCFA</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>InAppSettingsKit</string>
|
||||
</dict>
|
||||
@@ -68,7 +80,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>E4C8E206-229C-4DA8-A130-0C544DEC7E07</string>
|
||||
<string>8A15A8EA0B3D0B497C4883425BC74DF995224BB3</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>jrswizzle</string>
|
||||
</dict>
|
||||
@@ -84,7 +96,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
|
||||
<string>F788B28042EDBEF29EFE34687DA79A778C2CC260</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>MasterPassword</string>
|
||||
</dict>
|
||||
@@ -92,7 +104,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</string>
|
||||
<string>4DDCFFD91B41F00326AD14553BD66CFD366ABD91</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>Pearl</string>
|
||||
</dict>
|
||||
@@ -100,7 +112,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</string>
|
||||
<string>3E67FB08419C920516AAC3B00DAAF23073B8CF77</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>RHStatusItemView</string>
|
||||
</dict>
|
||||
@@ -108,7 +120,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>42C94803-87A2-403E-896C-D9AC3A807E1B</string>
|
||||
<string>E47DEC29CB0D0FDE3560EF46E1808FA1C723D657</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>UbiquityStoreManager</string>
|
||||
</dict>
|
||||
@@ -116,7 +128,7 @@
|
||||
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
||||
<string>public.vcs.git</string>
|
||||
<key>IDESourceControlWCCIdentifierKey</key>
|
||||
<string>AE3786C7-912B-4651-A73F-2E1DACBFB604</string>
|
||||
<string>2FE140B36B7D26140DC8D5E5C639DC5900EFCF35</string>
|
||||
<key>IDESourceControlWCCName</key>
|
||||
<string>uicolor-utilities</string>
|
||||
</dict>
|
||||
|
||||
@@ -38,15 +38,20 @@ void usage() {
|
||||
fprintf(stderr, " -u name Specify the full name of the user.\n"
|
||||
" Defaults to %s in env.\n\n", MP_env_username);
|
||||
fprintf(stderr, " -t type Specify the password's template.\n"
|
||||
" Defaults to %s in env or 'long'.\n"
|
||||
" Defaults to %s in env or 'long' for password, 'name' for login.\n"
|
||||
" x, max, maximum | 20 characters, contains symbols.\n"
|
||||
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
|
||||
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
|
||||
" b, basic | 8 characters, no symbols.\n"
|
||||
" s, short | Copy-friendly, 4 characters, no symbols.\n"
|
||||
" p, pin | 4 numbers.\n\n", MP_env_sitetype);
|
||||
" p, pin | 4 numbers.\n"
|
||||
" n, name | 9 letter name.\n\n", MP_env_sitetype);
|
||||
fprintf(stderr, " -c counter The value of the counter.\n"
|
||||
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter);
|
||||
fprintf(stderr, " -v variant The kind of content to generate.\n"
|
||||
" Defaults to 'password'.\n"
|
||||
" p, password | The password to log in with.\n"
|
||||
" l, login | The username to log in as.\n\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -86,12 +91,14 @@ int main(int argc, char *const argv[]) {
|
||||
const char *siteName = NULL;
|
||||
MPElementType siteType = MPElementTypeGeneratedLong;
|
||||
const char *siteTypeString = getenv( MP_env_sitetype );
|
||||
MPElementVariant siteVariant = MPElementVariantPassword;
|
||||
const char *siteVariantString = NULL;
|
||||
uint32_t siteCounter = 1;
|
||||
const char *siteCounterString = getenv( MP_env_sitecounter );
|
||||
|
||||
// Read the options.
|
||||
char opt;
|
||||
while ((opt = getopt(argc, argv, "u:t:c:h")) != -1)
|
||||
while ((opt = getopt(argc, argv, "u:t:c:v:h")) != -1)
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage();
|
||||
@@ -102,6 +109,9 @@ int main(int argc, char *const argv[]) {
|
||||
case 't':
|
||||
siteTypeString = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
siteVariantString = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
siteCounterString = optarg;
|
||||
break;
|
||||
@@ -144,6 +154,11 @@ int main(int argc, char *const argv[]) {
|
||||
return 1;
|
||||
}
|
||||
trc("siteCounter: %d\n", siteCounter);
|
||||
if (siteVariantString)
|
||||
siteVariant = VariantWithName( siteVariantString );
|
||||
trc("siteVariant: %d (%s)\n", siteVariant, siteVariantString);
|
||||
if (siteVariant == MPElementVariantLogin)
|
||||
siteType = MPElementTypeGeneratedName;
|
||||
if (siteTypeString)
|
||||
siteType = TypeWithName( siteTypeString );
|
||||
trc("siteType: %d (%s)\n", siteType, siteTypeString);
|
||||
@@ -176,9 +191,10 @@ int main(int argc, char *const argv[]) {
|
||||
trc("masterPassword: %s\n", masterPassword);
|
||||
|
||||
// Calculate the master key salt.
|
||||
char *mpNameSpace = "com.lyndir.masterpassword";
|
||||
const char *mpKeyScope = ScopeForVariant(MPElementVariantPassword);
|
||||
trc("key scope: %s\n", mpKeyScope);
|
||||
const uint32_t n_userNameLength = htonl(strlen(userName));
|
||||
size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName);
|
||||
size_t masterKeySaltLength = strlen(mpKeyScope) + sizeof(n_userNameLength) + strlen(userName);
|
||||
char *masterKeySalt = malloc( masterKeySaltLength );
|
||||
if (!masterKeySalt) {
|
||||
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
|
||||
@@ -186,7 +202,7 @@ int main(int argc, char *const argv[]) {
|
||||
}
|
||||
|
||||
char *mKS = masterKeySalt;
|
||||
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace);
|
||||
memcpy(mKS, mpKeyScope, strlen(mpKeyScope)); mKS += strlen(mpKeyScope);
|
||||
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
|
||||
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
|
||||
if (mKS - masterKeySalt != masterKeySaltLength)
|
||||
@@ -210,9 +226,11 @@ int main(int argc, char *const argv[]) {
|
||||
trc("masterKey ID: %s\n", IDForBuf(masterKey, MP_dkLen));
|
||||
|
||||
// Calculate the site seed.
|
||||
const char *mpSiteScope = ScopeForVariant(siteVariant);
|
||||
trc("site scope: %s\n", mpSiteScope);
|
||||
const uint32_t n_siteNameLength = htonl(strlen(siteName));
|
||||
const uint32_t n_siteCounter = htonl(siteCounter);
|
||||
size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
|
||||
size_t sitePasswordInfoLength = strlen(mpSiteScope) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
|
||||
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
|
||||
if (!sitePasswordInfo) {
|
||||
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
|
||||
@@ -220,13 +238,13 @@ int main(int argc, char *const argv[]) {
|
||||
}
|
||||
|
||||
char *sPI = sitePasswordInfo;
|
||||
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace);
|
||||
memcpy(sPI, mpSiteScope, strlen(mpSiteScope)); sPI += strlen(mpSiteScope);
|
||||
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
|
||||
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
|
||||
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
|
||||
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
|
||||
abort();
|
||||
trc("seed from: hmac-sha256(masterKey, 'com.lyndir.masterpassword' | %s | %s | %s)\n", Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
|
||||
trc("seed from: hmac-sha256(masterKey, %s | %s | %s | %s)\n", mpSiteScope, Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
|
||||
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
|
||||
|
||||
uint8_t sitePasswordSeed[32];
|
||||
|
||||
@@ -33,6 +33,8 @@ const MPElementType TypeWithName(const char *typeName) {
|
||||
return MPElementTypeGeneratedShort;
|
||||
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin"))
|
||||
return MPElementTypeGeneratedPIN;
|
||||
if (0 == strcmp(lowerTypeName, "n") || 0 == strcmp(lowerTypeName, "name"))
|
||||
return MPElementTypeGeneratedName;
|
||||
|
||||
fprintf(stderr, "Not a generated type name: %s", lowerTypeName);
|
||||
abort();
|
||||
@@ -67,6 +69,9 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
case MPElementTypeGeneratedPIN: {
|
||||
return "nnnn";
|
||||
}
|
||||
case MPElementTypeGeneratedName: {
|
||||
return "cvccvcvcv";
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown generated type: %d", type);
|
||||
abort();
|
||||
@@ -74,6 +79,36 @@ const char *CipherForType(MPElementType type, uint8_t seedByte) {
|
||||
}
|
||||
}
|
||||
|
||||
const MPElementVariant VariantWithName(const char *variantName) {
|
||||
char lowerVariantName[strlen(variantName)];
|
||||
strcpy(lowerVariantName, variantName);
|
||||
for (char *vN = lowerVariantName; *vN; ++vN)
|
||||
*vN = tolower(*vN);
|
||||
|
||||
if (0 == strcmp(lowerVariantName, "p") || 0 == strcmp(lowerVariantName, "password"))
|
||||
return MPElementVariantPassword;
|
||||
if (0 == strcmp(lowerVariantName, "l") || 0 == strcmp(lowerVariantName, "login"))
|
||||
return MPElementVariantLogin;
|
||||
|
||||
fprintf(stderr, "Not a variant name: %s", lowerVariantName);
|
||||
abort();
|
||||
}
|
||||
|
||||
const char *ScopeForVariant(MPElementVariant variant) {
|
||||
switch (variant) {
|
||||
case MPElementVariantPassword: {
|
||||
return "com.lyndir.masterpassword";
|
||||
}
|
||||
case MPElementVariantLogin: {
|
||||
return "com.lyndir.masterpassword.login";
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown variant: %d", variant);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char CharacterFromClass(char characterClass, uint8_t seedByte) {
|
||||
const char *classCharacters;
|
||||
switch (characterClass) {
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
MPElementContentTypePassword,
|
||||
MPElementContentTypeNote,
|
||||
MPElementContentTypePicture,
|
||||
} MPElementContentType;
|
||||
/** Generate the password to log in with. */
|
||||
MPElementVariantPassword,
|
||||
/** Generate the login name to log in as. */
|
||||
MPElementVariantLogin,
|
||||
} MPElementVariant;
|
||||
|
||||
typedef enum {
|
||||
/** Generate the password. */
|
||||
@@ -33,6 +34,7 @@ typedef enum {
|
||||
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
|
||||
MPElementTypeGeneratedName = 0xF | MPElementTypeClassGenerated | 0x0,
|
||||
|
||||
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
|
||||
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
|
||||
@@ -44,6 +46,8 @@ typedef enum {
|
||||
#define trc(...) do {} while (0)
|
||||
#endif
|
||||
|
||||
const MPElementVariant VariantWithName(const char *variantName);
|
||||
const char *ScopeForVariant(MPElementVariant variant);
|
||||
const MPElementType TypeWithName(const char *typeName);
|
||||
const char *CipherForType(MPElementType type, uint8_t seedByte);
|
||||
const char CharacterFromClass(char characterClass, uint8_t seedByte);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
@@ -13,7 +13,7 @@
|
||||
<name>Master Password Algorithm Implementation</name>
|
||||
<description>The implementation of the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-system</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>1.6-p6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-crypto</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<version>1.6-p6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
@@ -41,7 +41,7 @@
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>scrypt</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Set;
|
||||
@@ -79,11 +80,9 @@ public enum MPElementType {
|
||||
*/
|
||||
public static MPElementType forName(final String name) {
|
||||
|
||||
for (final MPElementType type : values()) {
|
||||
if (type.getName().equalsIgnoreCase( name ) || type.getShortName().equalsIgnoreCase( name )) {
|
||||
for (final MPElementType type : values())
|
||||
if (type.getName().equalsIgnoreCase( name ) || type.getShortName().equalsIgnoreCase( name ))
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
throw logger.bug( "Element type not known: %s", name );
|
||||
}
|
||||
@@ -93,14 +92,12 @@ public enum MPElementType {
|
||||
*
|
||||
* @return All types that support the given class.
|
||||
*/
|
||||
public static ImmutableSet<MPElementType> forClass(final MPElementTypeClass typeClass) {
|
||||
public static ImmutableList<MPElementType> forClass(final MPElementTypeClass typeClass) {
|
||||
|
||||
ImmutableSet.Builder<MPElementType> types = ImmutableSet.builder();
|
||||
for (final MPElementType type : values()) {
|
||||
if (type.getTypeClass() == typeClass) {
|
||||
ImmutableList.Builder<MPElementType> types = ImmutableList.builder();
|
||||
for (final MPElementType type : values())
|
||||
if (type.getTypeClass() == typeClass)
|
||||
types.add( type );
|
||||
}
|
||||
}
|
||||
|
||||
return types.build();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.lyndir.lhunath.masterpassword.entity.*;
|
||||
import com.lyndir.masterpassword.entity.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import com.lyndir.lhunath.opal.system.util.ObjectMeta;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Throwables;
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.CharSource;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.lambdaworks.crypto.SCrypt;
|
||||
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
||||
@@ -11,18 +13,17 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import javax.xml.stream.events.Characters;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the Master Password algorithm.
|
||||
*
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public abstract class MasterPassword {
|
||||
public class MasterKey {
|
||||
|
||||
static final Logger logger = Logger.get( MasterPassword.class );
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKey.class );
|
||||
private static final int MP_N = 32768;
|
||||
private static final int MP_r = 8;
|
||||
private static final int MP_p = 2;
|
||||
@@ -33,52 +34,60 @@ public abstract class MasterPassword {
|
||||
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
|
||||
private static final MPTemplates templates = MPTemplates.load();
|
||||
|
||||
public static byte[] keyForPassword(final String password, final String username) {
|
||||
private final String userName;
|
||||
private final byte[] key;
|
||||
|
||||
private boolean valid;
|
||||
|
||||
public MasterKey(final String userName, final String masterPassword) {
|
||||
|
||||
this.userName = userName;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
byte[] nusernameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
|
||||
.order( MP_byteOrder )
|
||||
.putInt( username.length() )
|
||||
.array();
|
||||
byte[] userNameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
|
||||
.order( MP_byteOrder )
|
||||
.putInt( userName.length() )
|
||||
.array();
|
||||
byte[] salt = Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
|
||||
nusernameLengthBytes, //
|
||||
username.getBytes( MP_charset ) );
|
||||
userNameLengthBytes, userName.getBytes( MP_charset ) );
|
||||
|
||||
try {
|
||||
byte[] key = SCrypt.scrypt( password.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
logger.trc( "User: %s, password: %s derives to key ID: %s (took %.2fs)", username, password,
|
||||
CodeUtils.encodeHex( keyIDForKey( key ) ), (double) (System.currentTimeMillis() - start) / 1000 );
|
||||
key = SCrypt.scrypt( masterPassword.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
valid = true;
|
||||
|
||||
return key;
|
||||
logger.trc( "User: %s, master password derives to key ID: %s (took %.2fs)", //
|
||||
userName, getKeyID(), (double) (System.currentTimeMillis() - start) / 1000 );
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] subkeyForKey(final byte[] key, final int subkeyLength) {
|
||||
public String getUserName() {
|
||||
|
||||
return userName;
|
||||
}
|
||||
|
||||
public String getKeyID() {
|
||||
|
||||
Preconditions.checkState( valid );
|
||||
return CodeUtils.encodeHex( MP_hash.of( key ) );
|
||||
}
|
||||
|
||||
private byte[] getSubkey(final int subkeyLength) {
|
||||
|
||||
Preconditions.checkState( valid );
|
||||
byte[] subkey = new byte[Math.min( subkeyLength, key.length )];
|
||||
System.arraycopy( key, 0, subkey, 0, subkey.length );
|
||||
|
||||
return subkey;
|
||||
}
|
||||
|
||||
public static byte[] keyIDForPassword(final String password, final String username) {
|
||||
|
||||
return keyIDForKey( keyForPassword( password, username ) );
|
||||
}
|
||||
|
||||
public static byte[] keyIDForKey(final byte[] key) {
|
||||
|
||||
return MP_hash.of( key );
|
||||
}
|
||||
|
||||
public static String generateContent(final MPElementType type, final String name, final byte[] key, int counter) {
|
||||
public String encode(final String name, final MPElementType type, int counter) {
|
||||
|
||||
Preconditions.checkState( valid );
|
||||
Preconditions.checkArgument( type.getTypeClass() == MPElementTypeClass.Generated );
|
||||
Preconditions.checkArgument( !name.isEmpty() );
|
||||
Preconditions.checkArgument( key.length > 0 );
|
||||
|
||||
if (counter == 0)
|
||||
counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
|
||||
@@ -112,17 +121,9 @@ public abstract class MasterPassword {
|
||||
return password.toString();
|
||||
}
|
||||
|
||||
public static void main(final String... arguments) {
|
||||
public void invalidate() {
|
||||
|
||||
String masterPassword = "test-mp";
|
||||
String username = "test-user";
|
||||
String siteName = "test-site";
|
||||
MPElementType siteType = MPElementType.GeneratedLong;
|
||||
int siteCounter = 42;
|
||||
|
||||
String sitePassword = generateContent( siteType, siteName, keyForPassword( masterPassword, username ), siteCounter );
|
||||
|
||||
logger.inf( "master password: %s, username: %s\nsite name: %s, site type: %s, site counter: %d\n => site password: %s",
|
||||
masterPassword, username, siteName, siteType, siteCounter, sitePassword );
|
||||
valid = false;
|
||||
Arrays.fill( key, (byte) 0 );
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
package com.lyndir.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
@@ -1,18 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.lyndir.lhunath.masterpassword" android:versionCode="1" android:versionName="GIT-SNAPSHOT">
|
||||
package="com.lyndir.masterpassword"
|
||||
android:versionCode="1"
|
||||
android:versionName="GIT-SNAPSHOT">
|
||||
|
||||
<uses-sdk android:minSdkVersion="8"
|
||||
android:targetSdkVersion="16" />
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name=".HelloAndroidActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="19" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:allowBackup="true">
|
||||
<activity android:name=".EmergencyActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".UsersActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
|
||||
public final class BuildConfig {
|
||||
public final static boolean DEBUG = Boolean.parseBoolean(null);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
|
||||
public final class Manifest {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*___Generated_by_IDEA___*/
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
|
||||
public final class R {
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
@@ -13,7 +13,7 @@
|
||||
<name>Master Password Android</name>
|
||||
<description>An Android application to the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-android</artifactId>
|
||||
<packaging>apk</packaging>
|
||||
|
||||
@@ -24,35 +24,101 @@
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
|
||||
<!--configuration>
|
||||
<proguard>
|
||||
<configuration>
|
||||
<zipalign>
|
||||
<verbose>true</verbose>
|
||||
<skip>false</skip>
|
||||
<config>proguard.cfg</config>
|
||||
</proguard>
|
||||
</configuration-->
|
||||
</zipalign>
|
||||
<sdk>
|
||||
<platform>19</platform>
|
||||
</sdk>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>sign</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jarsigner-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>signing</id>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<archiveDirectory></archiveDirectory>
|
||||
<includes>
|
||||
<include>target/*.apk</include>
|
||||
</includes>
|
||||
<keystore>release.jks</keystore>
|
||||
<storepass>${env.PASSWORD}</storepass>
|
||||
<keypass>${env.PASSWORD}</keypass>
|
||||
<alias>android</alias>
|
||||
<arguments>
|
||||
<argument>-sigalg</argument><argument>MD5withRSA</argument>
|
||||
<argument>-digestalg</argument><argument>SHA1</argument>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<configuration>
|
||||
<sign>
|
||||
<debug>false</debug>
|
||||
</sign>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<groupId>com.lyndir.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<groupId>com.jakewharton</groupId>
|
||||
<artifactId>butterknife</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.android</groupId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-android</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- clone https://github.com/mosabua/maven-android-sdk-deployer.git
|
||||
run mvn install -P 4.4 -->
|
||||
<dependency>
|
||||
<groupId>android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<version>4.1.1.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>libscrypt</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<type>so</type>
|
||||
<classifier>android</classifier>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<size
|
||||
android:width="20dp"
|
||||
android:height="20dp" />
|
||||
</shape>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:background="@drawable/background">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/userNameField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text|textCapWords|textPersonName"
|
||||
android:hint="@string/userName.hint"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="26sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/masterPasswordField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text|textPassword"
|
||||
android:hint="@string/masterPassword.hint"
|
||||
android:password="true"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/double_"
|
||||
android:contentDescription="@string/empty" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/siteNameField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text|textNoSuggestions|textUri"
|
||||
android:hint="@string/siteName.hint"
|
||||
android:gravity="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="26sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/sitePasswordField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:background="@null"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="32sp"
|
||||
android:text="LuxdZozvDuma4["
|
||||
android:onClick="copySitePassword" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/typeField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/counterField"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/background">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/users"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="@drawable/divider20"
|
||||
android:showDividers="middle" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp" />
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
</FrameLayout>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/hello"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/userName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/avatar0"
|
||||
android:drawablePadding="8dp"
|
||||
android:text="Maarten Billemont" />
|
||||
@@ -1,5 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="hello">Hello masterpassword-android!</string>
|
||||
<string name="app_name">masterpassword-android</string>
|
||||
<string name="app_name">Master Password</string>
|
||||
<string name="avatar">User Avatar</string>
|
||||
<string name="siteName.hint">Site Name</string>
|
||||
<string name="userName.hint">Your Name</string>
|
||||
<string name="masterPassword.hint">Your Master Password</string>
|
||||
<string name="empty" />
|
||||
</resources>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class HelloAndroidActivity extends Activity {
|
||||
|
||||
private static String TAG = "masterpassword-android";
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
* @param savedInstanceState If the activity is being re-initialized after
|
||||
* previously being shut down then this Bundle contains the data it most
|
||||
* recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Log.i(TAG, "onCreate");
|
||||
setContentView(R.layout.main);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.*;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
|
||||
public class EmergencyActivity extends Activity {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( EmergencyActivity.class );
|
||||
|
||||
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||
private final ValueChangedListener updateMasterKey = new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateMasterKey();
|
||||
}
|
||||
};
|
||||
private final ValueChangedListener updateSitePassword = new ValueChangedListener() {
|
||||
@Override
|
||||
void update() {
|
||||
updateSitePassword();
|
||||
}
|
||||
};
|
||||
|
||||
private ListenableFuture<MasterKey> masterKeyFuture;
|
||||
|
||||
@InjectView(R.id.progressView)
|
||||
ProgressBar progressView;
|
||||
|
||||
@InjectView(R.id.userNameField)
|
||||
EditText userNameField;
|
||||
|
||||
@InjectView(R.id.masterPasswordField)
|
||||
EditText masterPasswordField;
|
||||
|
||||
@InjectView(R.id.siteNameField)
|
||||
EditText siteNameField;
|
||||
|
||||
@InjectView(R.id.typeField)
|
||||
Spinner typeField;
|
||||
|
||||
@InjectView(R.id.counterField)
|
||||
NumberPicker counterField;
|
||||
|
||||
@InjectView(R.id.sitePasswordField)
|
||||
TextView sitePasswordField;
|
||||
|
||||
private int hc_userName;
|
||||
private int hc_masterPassword;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate( savedInstanceState );
|
||||
Res.init( getResources() );
|
||||
|
||||
setContentView( R.layout.activity_emergency );
|
||||
ButterKnife.inject( this );
|
||||
|
||||
userNameField.setOnFocusChangeListener( updateMasterKey );
|
||||
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
|
||||
siteNameField.addTextChangedListener( updateSitePassword );
|
||||
typeField.setOnItemSelectedListener( updateSitePassword );
|
||||
counterField.setOnValueChangedListener( updateSitePassword );
|
||||
|
||||
userNameField.setTypeface( Res.exo_Thin );
|
||||
userNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
masterPasswordField.setTypeface( Res.sourceCodePro_ExtraLight );
|
||||
masterPasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
siteNameField.setTypeface( Res.exo_Regular );
|
||||
siteNameField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
|
||||
sitePasswordField.setPaintFlags( userNameField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||
|
||||
typeField.setAdapter(
|
||||
new ArrayAdapter<MPElementType>( this, R.layout.type_item, MPElementType.forClass( MPElementTypeClass.Generated ) ) );
|
||||
typeField.setSelection( MPElementType.GeneratedLong.ordinal() );
|
||||
|
||||
counterField.setMinValue( 1 );
|
||||
counterField.setMaxValue( Integer.MAX_VALUE );
|
||||
counterField.setWrapSelectorWheel( false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
userNameField.setText( getPreferences( MODE_PRIVATE ).getString( "userName", "" ) );
|
||||
masterPasswordField.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
synchronized (this) {
|
||||
hc_userName = hc_masterPassword = 0;
|
||||
if (masterKeyFuture != null) {
|
||||
masterKeyFuture.cancel( true );
|
||||
masterKeyFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private synchronized void updateMasterKey() {
|
||||
final String userName = userNameField.getText().toString();
|
||||
final String masterPassword = masterPasswordField.getText().toString();
|
||||
if (userName.hashCode() == hc_userName && masterPassword.hashCode() == hc_masterPassword)
|
||||
return;
|
||||
hc_userName = userName.hashCode();
|
||||
hc_masterPassword = masterPassword.hashCode();
|
||||
|
||||
SharedPreferences.Editor pref = getPreferences( MODE_PRIVATE ).edit();
|
||||
pref.putString( "userName", userName );
|
||||
pref.commit();
|
||||
|
||||
if (masterKeyFuture != null)
|
||||
masterKeyFuture.cancel( true );
|
||||
|
||||
if (userName.isEmpty() || masterPassword.isEmpty()) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
return;
|
||||
}
|
||||
|
||||
progressView.setVisibility( View.VISIBLE );
|
||||
(masterKeyFuture = executor.submit( new Callable<MasterKey>() {
|
||||
@Override
|
||||
public MasterKey call()
|
||||
throws Exception {
|
||||
try {
|
||||
return new MasterKey( userName, masterPassword );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
logger.err( e, "While generating master key." );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} )).addListener( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateSitePassword();
|
||||
}
|
||||
} );
|
||||
}
|
||||
}, executor );
|
||||
}
|
||||
|
||||
private void updateSitePassword() {
|
||||
final String siteName = siteNameField.getText().toString();
|
||||
final MPElementType type = (MPElementType) typeField.getSelectedItem();
|
||||
final int counter = counterField.getValue();
|
||||
|
||||
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
return;
|
||||
}
|
||||
|
||||
progressView.setVisibility( View.VISIBLE );
|
||||
executor.submit( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final String sitePassword = masterKeyFuture.get().encode( siteName, type, counter );
|
||||
|
||||
runOnUiThread( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
sitePasswordField.setText( sitePassword );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
}
|
||||
} );
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
logger.err( e, "While generating site password." );
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
sitePasswordField.setText( "" );
|
||||
progressView.setVisibility( View.INVISIBLE );
|
||||
logger.err( e, "While generating site password." );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void copySitePassword(View view) {
|
||||
String sitePassword = sitePasswordField.getText().toString();
|
||||
if (sitePassword.isEmpty())
|
||||
return;
|
||||
|
||||
ClipDescription description = new ClipDescription( strf( "Password for %s", siteNameField.getText() ),
|
||||
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN } );
|
||||
((ClipboardManager) getSystemService( CLIPBOARD_SERVICE )).setPrimaryClip(
|
||||
new ClipData( description, new ClipData.Item( sitePassword ) ) );
|
||||
|
||||
Intent startMain = new Intent(Intent.ACTION_MAIN);
|
||||
startMain.addCategory(Intent.CATEGORY_HOME);
|
||||
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(startMain);
|
||||
}
|
||||
|
||||
private abstract class ValueChangedListener
|
||||
implements TextWatcher, NumberPicker.OnValueChangeListener, AdapterView.OnItemSelectedListener, View.OnFocusChangeListener {
|
||||
|
||||
abstract void update();
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(final AdapterView<?> parent) {
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFocusChange(final View v, final boolean hasFocus) {
|
||||
if (!hasFocus)
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-25
|
||||
*/
|
||||
public class Res {
|
||||
|
||||
public static Typeface sourceCodePro_Black;
|
||||
public static Typeface sourceCodePro_ExtraLight;
|
||||
public static Typeface exo_Bold;
|
||||
public static Typeface exo_ExtraBold;
|
||||
public static Typeface exo_Regular;
|
||||
public static Typeface exo_Thin;
|
||||
|
||||
private static boolean initialized;
|
||||
|
||||
public static void init(Resources resources) {
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
sourceCodePro_Black = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-Black.otf" );
|
||||
sourceCodePro_ExtraLight = Typeface.createFromAsset( resources.getAssets(), "SourceCodePro-ExtraLight.otf" );
|
||||
exo_Bold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Bold.otf" );
|
||||
exo_ExtraBold = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-ExtraBold.otf" );
|
||||
exo_Regular = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Regular.otf" );
|
||||
exo_Thin = Typeface.createFromAsset( resources.getAssets(), "Exo2.0-Thin.otf" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.widget.LinearLayout;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import com.lyndir.masterpassword.model.Avatar;
|
||||
import com.lyndir.masterpassword.model.User;
|
||||
import com.lyndir.masterpassword.view.AvatarView;
|
||||
|
||||
|
||||
public class UsersActivity extends Activity {
|
||||
|
||||
@InjectView(R.id.users)
|
||||
LinearLayout users;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate( savedInstanceState );
|
||||
setContentView( R.layout.activity_users );
|
||||
ButterKnife.inject( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
AvatarView avatarView = new AvatarView( this );
|
||||
avatarView.setUser( new User( "Maarten Billemont", Avatar.EIGHT ) );
|
||||
users.addView( avatarView );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.lyndir.masterpassword.model;
|
||||
|
||||
import com.lyndir.masterpassword.R;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2014-08-20
|
||||
*/
|
||||
public enum Avatar {
|
||||
ZERO( R.drawable.avatar0 ),
|
||||
ONE( R.drawable.avatar1 ),
|
||||
TWO( R.drawable.avatar2 ),
|
||||
THREE( R.drawable.avatar3 ),
|
||||
FOUR( R.drawable.avatar4 ),
|
||||
FIVE( R.drawable.avatar5 ),
|
||||
SIX( R.drawable.avatar6 ),
|
||||
SEVEN( R.drawable.avatar7 ),
|
||||
EIGHT( R.drawable.avatar8 ),
|
||||
NINE( R.drawable.avatar9 ),
|
||||
TEN( R.drawable.avatar10 ),
|
||||
ELEVEN( R.drawable.avatar11 ),
|
||||
TWELVE( R.drawable.avatar12 ),
|
||||
THIRTEEN( R.drawable.avatar13 ),
|
||||
FOURTEEN( R.drawable.avatar14 ),
|
||||
FIFTEEN( R.drawable.avatar15 ),
|
||||
SIXTEEN( R.drawable.avatar16 ),
|
||||
SEVENTEEN( R.drawable.avatar17 ),
|
||||
EIGHTEEN( R.drawable.avatar18 );
|
||||
|
||||
private final int imageResource;
|
||||
|
||||
Avatar(final int imageResource) {
|
||||
this.imageResource = imageResource;
|
||||
}
|
||||
|
||||
public int getImageResource() {
|
||||
return imageResource;
|
||||
}
|
||||
}
|
||||