-
Notifications
You must be signed in to change notification settings - Fork 333
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support client side encryption via SEGCrypto protocol (#592)
* Adding SEGStorage and SEGCrypto classes * Adding SEGUserDefaultsStorage * Route all disk access through SEGStorage classes and expose SEGCrypto as part of SEGAnalyticsConfiguration * Run pod install again * Fix anonymousId loading. Removing no longer used anonymousIdURL * Removing unused SEGAnalyticsURLForFilename * Adding CryptoTest, FileStorageTest and UserDefaultsStorageTest from redux branch * Adding changes to Podfile
- Loading branch information
Showing
133 changed files
with
11,371 additions
and
1,026 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// SEGAES256Crypto.h | ||
// Analytics | ||
// | ||
// Copyright © 2016 Segment. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
#import "SEGCrypto.h" | ||
|
||
@interface SEGAES256Crypto : NSObject <SEGCrypto> | ||
|
||
@property (nonatomic, readonly, nonnull) NSString *password; | ||
@property (nonatomic, readonly, nonnull) NSData *salt; | ||
@property (nonatomic, readonly, nonnull) NSData *iv; | ||
|
||
- (instancetype _Nonnull)initWithPassword:(NSString * _Nonnull)password salt:(NSData * _Nonnull)salt iv:(NSData * _Nonnull)iv; | ||
// Convenient shorthand. Will randomly generate salt and iv. | ||
- (instancetype _Nonnull)initWithPassword:(NSString * _Nonnull)password; | ||
|
||
+ (NSData * _Nonnull)randomDataOfLength:(size_t)length; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// | ||
// SEGAES256Crypto.m | ||
// Analytics | ||
// | ||
// Copyright © 2016 Segment. All rights reserved. | ||
// | ||
|
||
|
||
#import <CommonCrypto/CommonCryptor.h> | ||
#import <CommonCrypto/CommonKeyDerivation.h> | ||
#import "SEGAES256Crypto.h" | ||
#import "SEGUtils.h" | ||
|
||
// Implementation courtesy of http://robnapier.net/aes-commoncrypto | ||
|
||
static NSString * const kRNCryptManagerErrorDomain = @"com.segment.crypto"; | ||
|
||
static const CCAlgorithm kAlgorithm = kCCAlgorithmAES; | ||
static const NSUInteger kAlgorithmKeySize = kCCKeySizeAES256; | ||
static const NSUInteger kAlgorithmBlockSize = kCCBlockSizeAES128; | ||
static const NSUInteger kAlgorithmIVSize = kCCBlockSizeAES128; | ||
static const NSUInteger kPBKDFSaltSize = 8; | ||
static const NSUInteger kPBKDFRounds = 10000; // ~80ms on an iPhone 4 | ||
|
||
@implementation SEGAES256Crypto | ||
|
||
- (instancetype)initWithPassword:(NSString *)password salt:(NSData *)salt iv:(NSData * _Nonnull)iv { | ||
if (self = [super init]) { | ||
_password = password; | ||
_salt = salt; | ||
_iv = iv; | ||
} | ||
return self; | ||
} | ||
|
||
- (instancetype)initWithPassword:(NSString *)password { | ||
NSData *iv = [SEGAES256Crypto randomDataOfLength:kAlgorithmIVSize]; | ||
NSData *salt = [SEGAES256Crypto randomDataOfLength:kPBKDFSaltSize]; | ||
return [self initWithPassword:password salt:salt iv:iv]; | ||
} | ||
|
||
- (NSData *)aesKey { | ||
return [[self class] AESKeyForPassword:self.password salt:self.salt]; | ||
} | ||
|
||
- (NSData *)encrypt:(NSData *)data { | ||
size_t outLength; | ||
NSMutableData *cipherData = [NSMutableData dataWithLength:data.length + kAlgorithmBlockSize]; | ||
|
||
CCCryptorStatus | ||
result = CCCrypt(kCCEncrypt, // operation | ||
kAlgorithm, // Algorithm | ||
kCCOptionPKCS7Padding, // options | ||
self.aesKey.bytes, // key | ||
self.aesKey.length, // keylength | ||
self.iv.bytes,// iv | ||
data.bytes, // dataIn | ||
data.length, // dataInLength, | ||
cipherData.mutableBytes, // dataOut | ||
cipherData.length, // dataOutAvailable | ||
&outLength); // dataOutMoved | ||
|
||
if (result == kCCSuccess) { | ||
cipherData.length = outLength; | ||
} else { | ||
NSError *error = [NSError errorWithDomain:kRNCryptManagerErrorDomain | ||
code:result | ||
userInfo:nil]; | ||
SEGLog(@"Unable to encrypt data", error); | ||
return nil; | ||
} | ||
return cipherData; | ||
} | ||
|
||
- (NSData *)decrypt:(NSData *)data { | ||
size_t outLength; | ||
NSMutableData *decryptedData = [NSMutableData dataWithLength:data.length + kAlgorithmBlockSize]; | ||
|
||
CCCryptorStatus | ||
result = CCCrypt(kCCDecrypt, // operation | ||
kAlgorithm, // Algorithm | ||
kCCOptionPKCS7Padding, // options | ||
self.aesKey.bytes, // key | ||
self.aesKey.length, // keylength | ||
self.iv.bytes,// iv | ||
data.bytes, // dataIn | ||
data.length, // dataInLength, | ||
decryptedData.mutableBytes, // dataOut | ||
decryptedData.length, // dataOutAvailable | ||
&outLength); // dataOutMoved | ||
|
||
if (result == kCCSuccess) { | ||
decryptedData.length = outLength; | ||
} else { | ||
NSError *error = [NSError errorWithDomain:kRNCryptManagerErrorDomain | ||
code:result | ||
userInfo:nil]; | ||
SEGLog(@"Unable to encrypt data", error); | ||
return nil; | ||
} | ||
return decryptedData; | ||
} | ||
|
||
+ (NSData *)randomDataOfLength:(size_t)length { | ||
NSMutableData *data = [NSMutableData dataWithLength:length]; | ||
|
||
int result = SecRandomCopyBytes(kSecRandomDefault, | ||
length, | ||
data.mutableBytes); | ||
if (result != kCCSuccess) { | ||
SEGLog(@"Unable to generate random bytes: %d", result); | ||
} | ||
|
||
return data; | ||
} | ||
|
||
// Replace this with a 10,000 hash calls if you don't have CCKeyDerivationPBKDF | ||
+ (NSData *)AESKeyForPassword:(NSString *)password | ||
salt:(NSData *)salt { | ||
NSMutableData *derivedKey = [NSMutableData dataWithLength:kAlgorithmKeySize]; | ||
|
||
int result = CCKeyDerivationPBKDF(kCCPBKDF2, // algorithm | ||
password.UTF8String, // password | ||
[password lengthOfBytesUsingEncoding:NSUTF8StringEncoding], // passwordLength | ||
salt.bytes, // salt | ||
salt.length, // saltLen | ||
kCCPRFHmacAlgSHA1, // PRF | ||
kPBKDFRounds, // rounds | ||
derivedKey.mutableBytes, // derivedKey | ||
derivedKey.length); // derivedKeyLen | ||
|
||
// Do not log password here | ||
if (result != kCCSuccess) { | ||
SEGLog(@"Unable to create AES key for password: %d", result); | ||
} | ||
|
||
return derivedKey; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// | ||
// SEGCrypto.h | ||
// Analytics | ||
// | ||
// Copyright © 2016 Segment. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
@protocol SEGCrypto <NSObject> | ||
|
||
- (NSData * _Nullable)encrypt:(NSData * _Nonnull)data; | ||
- (NSData * _Nullable)decrypt:(NSData * _Nonnull)data; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// | ||
// SEGFileStorage.h | ||
// Analytics | ||
// | ||
// Copyright © 2016 Segment. All rights reserved. | ||
// | ||
|
||
#import <Foundation/Foundation.h> | ||
#import "SEGStorage.h" | ||
|
||
@interface SEGFileStorage : NSObject <SEGStorage> | ||
|
||
@property (nonatomic, strong, nullable) id<SEGCrypto> crypto; | ||
|
||
- (instancetype _Nonnull)init; | ||
- (instancetype _Nonnull)initWithFolder:(NSURL * _Nonnull)folderURL crypto:(id<SEGCrypto> _Nullable)crypto; | ||
|
||
- (NSURL * _Nonnull)urlForKey:(NSString * _Nonnull)key; | ||
|
||
+ (NSURL * _Nullable)applicationSupportDirectoryURL; | ||
|
||
@end |
Oops, something went wrong.