Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support client side encryption via SEGCrypto protocol #592

Merged
merged 8 commits into from
Aug 30, 2016
Merged

Conversation

tonyxiao
Copy link
Contributor

@tonyxiao tonyxiao commented Aug 25, 2016

https://segment.atlassian.net/browse/INT-587
Architecture here: https://paper.dropbox.com/doc/Pluggable-Client-Side-Encryption-Architecture-Review-z7spaYemPF4IU5vVlppQL

In order to make this happen we needed to route all disk access through
SEGStorage protocol. There are two concrete implementations, one for file based
and another for user defaults based, depending on OS.

cc @f2prateek @jgershen

@tonyxiao
Copy link
Contributor Author

Tests are here. But unfortunately in Swift, and it's out of scope to setup swift tests in master.
https://github.com/segmentio/analytics-ios/blob/redux/AnalyticsTest/FileStorageTest.swift
https://github.com/segmentio/analytics-ios/blob/redux/AnalyticsTest/UserDefaultsStorageTest.swift
https://github.com/segmentio/analytics-ios/blob/redux/AnalyticsTest/CryptoTest.swift

They do pass of course :)

Test Suite 'UserDefaultsStorageTest' started at 2016-08-24 23:01:44.220
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_data]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_data]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_string]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_string]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_array]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_array]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_dictionary]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest persists_and_loads_dictionary]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.UserDefaultsStorageTest should_work_with_crypto]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest should_work_with_crypto]' passed (0.034 seconds).
Test Case '-[AnalyticsTest.UserDefaultsStorageTest should_work_with_namespace]' started.
Test Case '-[AnalyticsTest.UserDefaultsStorageTest should_work_with_namespace]' passed (0.034 seconds).
Test Suite 'UserDefaultsStorageTest' passed at 2016-08-24 23:01:44.293.
    Executed 6 tests, with 0 failures (0 unexpected) in 0.071 (0.073) seconds
Test Suite 'FileStorageTest' started at 2016-08-24 23:01:42.693
Test Case '-[AnalyticsTest.FileStorageTest creates_folder_if_none_exists]' started.
Test Case '-[AnalyticsTest.FileStorageTest creates_folder_if_none_exists]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_data]' started.
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_data]' passed (0.002 seconds).
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_string]' started.
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_string]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_array]' started.
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_array]' passed (0.002 seconds).
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_dictionary]' started.
Test Case '-[AnalyticsTest.FileStorageTest persists_and_loads_dictionary]' passed (0.002 seconds).
Test Case '-[AnalyticsTest.FileStorageTest saves_file_to_disk_and_removes_from_disk]' started.
Test Case '-[AnalyticsTest.FileStorageTest saves_file_to_disk_and_removes_from_disk]' passed (0.001 seconds).
Test Case '-[AnalyticsTest.FileStorageTest should_be_binary_compatible_with_old_SDKs]' started.
Test Case '-[AnalyticsTest.FileStorageTest should_be_binary_compatible_with_old_SDKs]' passed (0.002 seconds).
Test Case '-[AnalyticsTest.FileStorageTest should_work_with_crypto]' started.
Test Case '-[AnalyticsTest.FileStorageTest should_work_with_crypto]' passed (0.034 seconds).
Test Suite 'FileStorageTest' passed at 2016-08-24 23:01:42.752.
     Executed 8 tests, with 0 failures (0 unexpected) in 0.045 (0.059) seconds
Test Suite 'CryptoTest' started at 2016-08-24 23:01:42.575
Test Case '-[AnalyticsTest.CryptoTest encrypts_and_decrypts_data]' started.
Test Case '-[AnalyticsTest.CryptoTest encrypts_and_decrypts_data]' passed (0.034 seconds).
Test Case '-[AnalyticsTest.CryptoTest fails_for_incorrect_password]' started.
Test Case '-[AnalyticsTest.CryptoTest fails_for_incorrect_password]' passed (0.034 seconds).
Test Case '-[AnalyticsTest.CryptoTest fails_for_incorrect_iv_and_sault]' started.
Test Case '-[AnalyticsTest.CryptoTest fails_for_incorrect_iv_and_sault]' passed (0.033 seconds).
Test Suite 'CryptoTest' passed at 2016-08-24 23:01:42.678.
     Executed 3 tests, with 0 failures (0 unexpected) in 0.101 (0.103) seconds


#import <Foundation/Foundation.h>

@protocol SEGCrypto <NSObject>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be public so users can supply their own implementation, yeah?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool so let's move it out of the Internal folder?

@f2prateek
Copy link
Contributor

We should definitely port the tests here either in Swift or just with what's already setup https://github.com/segmentio/analytics-ios/blob/master/Example/Tests/SEGHTTPClientTests.m.

@f2prateek
Copy link
Contributor

also the PR should be against the dev branch https://github.com/segmentio/analytics-ios/blob/master/CONTRIBUTING.md

@tonyxiao tonyxiao changed the base branch from master to dev August 25, 2016 20:14
@tonyxiao
Copy link
Contributor Author

@f2prateek changed based to dev. We should have a separate PR to support testing in Swift rather than expanding this scope of this PR.

@f2prateek
Copy link
Contributor

@tonyxiao makes sense about testing in Swift, I don't think this should be released without adding some tests so we can just write them in objective c for now.


@interface SEGUserDefaultsStorage : NSObject <SEGStorage>

@property (nonatomic, strong, nullable) id<SEGCrypto> crypto;
Copy link
Contributor

@f2prateek f2prateek Aug 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit leaky that the the storage mechanism knows about encryption. Also causes fair bit of duplicated code b/w the two storage implementations to deal with crypto.

I think the encryption could happen before call the storage methods, and decryption after.

The usage could be like this:

NSData *encrypted = [crypto encrypt:data];
[storage setData:encrypted forKey:key];
NSData *encrypted = [storage dataForKey:key];
NSData *decrypted = [crypto decrypt:encrypted];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it difficult to be backward compatible with old storage mechanisms. In particular for user default based storage we don't always storage NSData objects, we directly store NSString and etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I see. I think that's ok, the user defaults code is only for tvOS and is only been available for a single release, and it gives us a window to change some of the implementation and we should use it now rather than be stuck with a legacy implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I think this shouldn't be a blocker for the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@f2prateek are we ok not worrying about migration on tvOS since last version?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tonyxiao Possibly, given support has been very recently added (just since the last release) I'm not too worried about migrating it cleanly for tvOS, if it helps us implementing this.

But as I said, doesn't need to be a blocker, should be ok as is and we can refine it later since the FileStorage class is internal.

@tonyxiao
Copy link
Contributor Author

tonyxiao commented Aug 25, 2016

Is it worth the effort to port the tests and duplicate code considering we'll actually have real Swift setup soon? Most of the current code also does not contain test coverage.

@f2prateek
Copy link
Contributor

I think it definitely is worth the effort of having tests for new features. It doesn't have to be a full end to end test, but at least have unit tests like https://github.com/segmentio/analytics-ios/blob/master/Example/Tests/SEGHTTPClientTests.m. We haven't had time to bring back the removed tests, but should at least keep adding tests for new components.

@tonyxiao
Copy link
Contributor Author

Hmm between re-writing tests in Objc and setting up tests in swift I'd rather just set up tests in Swift so no effort is wasted. Maybe I should get that in first or part of this PR.

@f2prateek
Copy link
Contributor

I don't think it should be that much work to port the tests, I'm happy to do it myself once this branch is ready (it might already be)

@tonyxiao
Copy link
Contributor Author

It's all good. I'll take a stab at getting the Swift tests running in this branch, shouldn't to too bad. (After all, we have it already elsewhere)

@tonyxiao
Copy link
Contributor Author

@f2prateek all comments addressed.

// Convenient shorthand. Will randomly generate salt and iv.
- (instancetype _Nonnull)initWithPassword:(NSString * _Nonnull)password;

+ (NSData * _Nonnull)randomDataOfLength:(size_t)length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's a convenience method for people to generate salt and iv and possibly password.

@f2prateek
Copy link
Contributor

LGTM

@f2prateek f2prateek merged commit 4bd68ab into dev Aug 30, 2016
@f2prateek f2prateek deleted the storage-crypto branch August 30, 2016 17:52
f2prateek pushed a commit that referenced this pull request Sep 1, 2016
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants