Skip to content

Commit

Permalink
Site-specific support for keys of different algorithm versions.
Browse files Browse the repository at this point in the history
[ADDED]     Ability to downgrade sites.
[ADDED]     A more explicit message that sites need to be upgraded.
  • Loading branch information
lhunath committed Feb 28, 2015
1 parent fd855bb commit ca8f14f
Show file tree
Hide file tree
Showing 36 changed files with 805 additions and 313 deletions.
2 changes: 1 addition & 1 deletion External/Pearl
Binary file modified External/iOS/Crashlytics.framework/Versions/A/Crashlytics
Binary file not shown.
Expand Up @@ -218,3 +218,8 @@ OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;

@end

/**
* `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, simply use `Crashlytics()`
*/
#define CrashlyticsKit [Crashlytics sharedInstance]
Expand Up @@ -15,13 +15,13 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.5</string>
<string>2.2.9</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>40</string>
<string>44</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>MinimumOSVersion</key>
Expand Down
Binary file modified External/iOS/Crashlytics.framework/run
Binary file not shown.
Binary file modified External/iOS/Crashlytics.framework/submit
Binary file not shown.
3 changes: 1 addition & 2 deletions MasterPassword/ObjC/MPAlgorithm.h
Expand Up @@ -48,9 +48,8 @@ NSString *NSStringFromTimeToCrack(TimeToCrack timeToCrack);
- (BOOL)tryMigrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc;
- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit;

- (MPKey *)keyForPassword:(NSString *)password ofUserNamed:(NSString *)userName;
- (MPKey *)keyFromKeyData:(NSData *)keyData;
- (NSData *)keyIDForKeyData:(NSData *)keyData;
- (NSData *)keyDataForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword;

- (NSString *)nameOfType:(MPSiteType)type;
- (NSString *)shortNameOfType:(MPSiteType)type;
Expand Down
65 changes: 32 additions & 33 deletions MasterPassword/ObjC/MPAlgorithmV0.m
Expand Up @@ -89,7 +89,7 @@ - (BOOL)tryMigrateUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)

- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

if (site.version != [self version] - 1)
if ([site.algorithm version] != [self version] - 1)
// Only migrate from previous version.
return NO;

Expand All @@ -101,24 +101,19 @@ - (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

// Apply migration.
site.requiresExplicitMigration = NO;
site.version = [self version];
site.algorithm = self;
return YES;
}

- (MPKey *)keyForPassword:(NSString *)password ofUserNamed:(NSString *)userName {
- (NSData *)keyDataForFullName:(NSString *)fullName withMasterPassword:(NSString *)masterPassword {

NSDate *start = [NSDate date];
uint8_t const *masterKeyBytes = mpw_masterKeyForUser( userName.UTF8String, password.UTF8String, [self version] );
MPKey *masterKey = [self keyFromKeyData:[NSData dataWithBytes:masterKeyBytes length:MP_dkLen]];
uint8_t const *masterKeyBytes = mpw_masterKeyForUser( fullName.UTF8String, masterPassword.UTF8String, [self version] );
NSData *keyData = [NSData dataWithBytes:masterKeyBytes length:MP_dkLen];
trc( @"User: %@, password: %@ derives to key ID: %@ (took %0.2fs)", //
fullName, masterPassword, [self keyIDForKeyData:keyData], -[start timeIntervalSinceNow] );
mpw_free( masterKeyBytes, MP_dkLen );
trc( @"User: %@, password: %@ derives to key ID: %@ (took %0.2fs)", userName, password, [masterKey.keyID encodeHex],
-[start timeIntervalSinceNow] );
return masterKey;
}

- (MPKey *)keyFromKeyData:(NSData *)keyData {

return [[MPKey alloc] initWithKeyData:keyData algorithm:self];
return keyData;
}

- (NSData *)keyIDForKeyData:(NSData *)keyData {
Expand Down Expand Up @@ -322,8 +317,8 @@ - (NSString *)generateAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
variant:(MPSiteVariant)variant context:(NSString *)context usingKey:(MPKey *)key {

char const *contentBytes = mpw_passwordForSite( key.keyData.bytes, name.UTF8String, type, (uint32_t)counter,
variant, context.UTF8String, [self version] );
char const *contentBytes = mpw_passwordForSite( [key keyDataForAlgorithm:self].bytes,
name.UTF8String, type, (uint32_t)counter, variant, context.UTF8String, [self version] );
NSString *content = [NSString stringWithCString:contentBytes encoding:NSUTF8StringEncoding];
mpw_freeString( contentBytes );

Expand All @@ -342,7 +337,7 @@ - (NSString *)storedPasswordForSite:(MPStoredSiteEntity *)site usingKey:(MPKey *

- (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
Expand All @@ -363,8 +358,9 @@ - (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)site usingK
return NO;
}

NSData *encryptionKey = [siteKey keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:[siteKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
encryptWithSymmetricKey:encryptionKey padding:YES];
if ([((MPStoredSiteEntity *)site).contentObject isEqualToData:encryptedContent])
return NO;

Expand All @@ -378,8 +374,9 @@ - (BOOL)savePassword:(NSString *)clearContent toSite:(MPSiteEntity *)site usingK
return NO;
}

NSData *encryptionKey = [siteKey keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
NSData *encryptedContent = [[clearContent dataUsingEncoding:NSUTF8StringEncoding]
encryptWithSymmetricKey:[siteKey subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
encryptWithSymmetricKey:encryptionKey padding:YES];
NSDictionary *siteQuery = [self queryForDevicePrivateSiteNamed:site.name];
if (!encryptedContent)
[PearlKeyChain deleteItemForQuery:siteQuery];
Expand Down Expand Up @@ -456,14 +453,14 @@ - (NSString *)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey

- (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSString *name = site.name;
BOOL loginGenerated = site.loginGenerated && [[MPAppDelegate_Shared get] isFeatureUnlocked:MPProductGenerateLogins];
NSString *loginName = loginGenerated? nil: site.loginName;
id<MPAlgorithm> algorithm = nil;
if (!name.length)
err( @"Missing name." );
else if (!siteKey.keyData.length)
else if (!siteKey)
err( @"Missing key." );
else
algorithm = site.algorithm;
Expand All @@ -478,7 +475,7 @@ - (void)resolveLoginForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey resul

- (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
Expand All @@ -500,7 +497,7 @@ - (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey re
id<MPAlgorithm> algorithm = nil;
if (!site.name.length)
err( @"Missing name." );
else if (!siteKey.keyData.length)
else if (!siteKey)
err( @"Missing key." );
else
algorithm = site.algorithm;
Expand Down Expand Up @@ -546,12 +543,12 @@ - (void)resolvePasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey re

- (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey result:(void ( ^ )(NSString *result))resultBlock {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSString *name = site.name;
id<MPAlgorithm> algorithm = nil;
if (!site.name.length)
err( @"Missing name." );
else if (!siteKey.keyData.length)
else if (!siteKey)
err( @"Missing key." );
else
algorithm = site.algorithm;
Expand All @@ -565,13 +562,13 @@ - (void)resolveAnswerForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey resu
- (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKey *)siteKey
result:(void ( ^ )(NSString *result))resultBlock {

NSAssert( [siteKey.keyID isEqualToData:question.site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:question.site.user.algorithm] isEqualToData:question.site.user.keyID], @"Site does not belong to current user." );
NSString *name = question.site.name;
NSString *keyword = question.keyword;
id<MPAlgorithm> algorithm = nil;
if (!name.length)
err( @"Missing name." );
else if (!siteKey.keyData.length)
else if (!siteKey)
err( @"Missing key." );
else
algorithm = question.site.algorithm;
Expand All @@ -585,7 +582,7 @@ - (void)resolveAnswerForQuestion:(MPSiteQuestionEntity *)question usingKey:(MPKe
- (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPKey *)importKey
intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
Expand All @@ -603,7 +600,7 @@ - (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPK
(long)site.type, [site class] );
break;
}
if ([importKey.keyID isEqualToData:siteKey.keyID])
if ([[importKey keyIDForAlgorithm:self] isEqualToData:[siteKey keyIDForAlgorithm:self]])
((MPStoredSiteEntity *)site).contentObject = [protectedContent decodeBase64];

else {
Expand All @@ -620,7 +617,7 @@ - (void)importProtectedPassword:(NSString *)protectedContent protectedByKey:(MPK

- (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
switch (site.type) {
case MPSiteTypeGeneratedMaximum:
case MPSiteTypeGeneratedLong:
Expand All @@ -644,7 +641,7 @@ - (void)importClearTextPassword:(NSString *)clearContent intoSite:(MPSiteEntity

- (NSString *)exportPasswordForSite:(MPSiteEntity *)site usingKey:(MPKey *)siteKey {

NSAssert( [siteKey.keyID isEqualToData:site.user.keyID], @"Site does not belong to current user." );
NSAssert( [[siteKey keyIDForAlgorithm:site.user.algorithm] isEqualToData:site.user.keyID], @"Site does not belong to current user." );
if (!(site.type & MPSiteFeatureExportContent))
return nil;

Expand Down Expand Up @@ -701,8 +698,10 @@ - (NSString *)decryptContent:(NSData *)encryptedContent usingKey:(MPKey *)key {
if (!key)
return nil;
NSData *decryptedContent = nil;
if ([encryptedContent length])
decryptedContent = [encryptedContent decryptWithSymmetricKey:[key subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
if ([encryptedContent length]) {
NSData *encryptionKey = [key keyDataForAlgorithm:self trimmedLength:PearlCryptKeySize];
decryptedContent = [encryptedContent decryptWithSymmetricKey:encryptionKey padding:YES];
}
if (!decryptedContent)
return nil;

Expand All @@ -711,7 +710,7 @@ - (NSString *)decryptContent:(NSData *)encryptedContent usingKey:(MPKey *)key {

- (BOOL)timeToCrack:(out TimeToCrack *)timeToCrack passwordOfType:(MPSiteType)type byAttacker:(MPAttacker)attacker {

if (!type)
if (!(type & MPSiteTypeClassGenerated))
return NO;
size_t count = 0;
const char **templates = mpw_templatesForType( type, &count );
Expand Down
4 changes: 2 additions & 2 deletions MasterPassword/ObjC/MPAlgorithmV1.m
Expand Up @@ -27,7 +27,7 @@ - (MPAlgorithmVersion)version {

- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

if (site.version != [self version] - 1)
if ([site.algorithm version] != [self version] - 1)
// Only migrate from previous version.
return NO;

Expand All @@ -41,7 +41,7 @@ - (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

// Apply migration.
site.requiresExplicitMigration = NO;
site.version = [self version];
site.algorithm = self;
return YES;
}

Expand Down
5 changes: 2 additions & 3 deletions MasterPassword/ObjC/MPAlgorithmV2.m
Expand Up @@ -15,7 +15,6 @@
// Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
//

#import <objc/runtime.h>
#import "MPAlgorithmV2.h"
#import "MPEntities.h"

Expand All @@ -28,7 +27,7 @@ - (MPAlgorithmVersion)version {

- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

if (site.version != [self version] - 1)
if ([site.algorithm version] != [self version] - 1)
// Only migrate from previous version.
return NO;

Expand All @@ -42,7 +41,7 @@ - (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

// Apply migration.
site.requiresExplicitMigration = NO;
site.version = [self version];
site.algorithm = self;
return YES;
}

Expand Down
7 changes: 4 additions & 3 deletions MasterPassword/ObjC/MPAlgorithmV3.m
Expand Up @@ -27,12 +27,13 @@ - (MPAlgorithmVersion)version {

- (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

if (site.version != [self version] - 1)
if ([site.algorithm version] != [self version] - 1)
// Only migrate from previous version.
return NO;

if (!explicit) {
if (site.type & MPSiteTypeClassGenerated && site.name.length != [site.name dataUsingEncoding:NSUTF8StringEncoding].length) {
if (site.type & MPSiteTypeClassGenerated &&
site.user.name.length != [site.user.name dataUsingEncoding:NSUTF8StringEncoding].length) {
// This migration requires explicit permission for types of the generated class.
site.requiresExplicitMigration = YES;
return NO;
Expand All @@ -41,7 +42,7 @@ - (BOOL)tryMigrateSite:(MPSiteEntity *)site explicit:(BOOL)explicit {

// Apply migration.
site.requiresExplicitMigration = NO;
site.version = [self version];
site.algorithm = self;
return YES;
}

Expand Down

0 comments on commit ca8f14f

Please sign in to comment.