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

Wipe Secure Cell key copy on deallocation #612

Merged
merged 1 commit into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 45 additions & 22 deletions src/wrappers/themis/Obj-C/objcthemis/scell.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,56 @@
* @{
*/

/** @brief Base Secure cell interface
*
* Secure Сell is a high-level cryptographic service, aimed to protect arbitrary data being stored in various types of
* storages (like databases, filesystem files, document archives, cloud storage etc).
* It provides a simple way to secure your data using strong encryption and data authentication mechanisms,
* with easy-to-use interfaces for broad range of use-cases.
*
* Implementing secure storage is often constrained by various practical matters - ability to store keys,
* existence of length-sensitive code bound to database structure, requirements to preserve structure.
* To cover a broader range of usage scenarios and provide highest security level for systems with such constraints,
* we've designed several types of interfaces and implementations of secure data container, Secure Cell.
* They slightly differ in overall security level and ease of use: more complicated and slightly less secure ones can
* cover more constrained environments though. Interfaces below are prioritized by our preference,
* which takes only security and ease of use into account.
*/

NS_ASSUME_NONNULL_BEGIN

/**
* Themis Secure Cell.
*
* Secure Сell is a high-level cryptographic service, aimed to protect arbitrary
* data being stored in various types of storages (like databases, filesystem
* files, document archives, cloud storage etc). It provides a simple way to
* secure your data using strong encryption and data authentication mechanisms,
* with easy-to-use interfaces for broad range of use-cases.
*
* Implementing secure storage is often constrained by various practical
* matters - ability to store keys, existence of length-sensitive code
* bound to database structure, requirements to preserve structure. To cover
* a broader range of usage scenarios and provide highest security level for
* systems with such constraints, we've designed several types of interfaces
* and implementations of secure data container, Secure Cell. They slightly
* differ in overall security level and ease of use: more complicated and
* slightly less secure ones can cover more constrained environments though.
* Interfaces below are prioritized by our preference, which takes only
* security and ease of use into account.
*
* - @c TSCellSeal is the most secure and the easiest one to use.
*
* - @c TSCellToken is able to preserve the encrypted data length
* but requires separate data storage to be available.
*
* - @c TSCellContextImprint preserves encrypted data length too,
* but at a cost of slightly lower security and more involved
* interface.
*
* @note This @c TSCell is a base class of Secure Cells. You need to select
* one of the subclasses implementing a particular mode.
*
* Read more about Secure Cell modes:
*
* https://docs.cossacklabs.com/pages/secure-cell-cryptosystem/
*/
@interface TSCell : NSObject

/** @brief store master key
*/
@property(nonatomic, readonly) NSData *key;
/** Encryption key. */
@property (nonatomic, readonly) NSData *key;

/** @brief Initialize Secure Cell object
* @param [in] key master key
*/
/**
* Store Secure Cell encryption key.
*
* @param [in] key non-empty master key
*
* @returns @c nil if key is empty.
*/
- (nullable instancetype)initWithKey:(NSData *)key;

@end
Expand Down
25 changes: 12 additions & 13 deletions src/wrappers/themis/Obj-C/objcthemis/scell.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@

#import <objcthemis/scell.h>


@interface TSCell ()


/** @brief store master key, rewrite
*/
@property(nonatomic, readwrite) NSData *key;

@end


@implementation TSCell
@implementation TSCell {
NSMutableData *_key;
}

- (nullable instancetype)initWithKey:(NSData *)key {
self = [super init];
if (self) {
if (!key || [key length] == 0) {
return nil;
}
self.key = [[NSData alloc] initWithData:key];
_key = [[NSMutableData alloc] initWithData:key];
}
return self;
}

- (void)dealloc
{
// Wipe the sensitive encryption key from memory when Secure Cell
// is deallocated and can no longer be used.
[_key resetBytesInRange:NSMakeRange(0, _key.length)];
[_key setLength:0];
}

@end
66 changes: 66 additions & 0 deletions tests/objcthemis/objthemis/SecureCellTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,28 @@ - (void)testOldAPIWithoutContext
}
#pragma clang diagnostic pop

- (void)testKeyWipedOnDealloc
{
NSData *key = TSGenerateSymmetricKey();
{
NSData *cellKey;
{
TSCellSeal *cell = [[TSCellSeal alloc] initWithKey:key];

cellKey = cell.key;

XCTAssertNotNil(cellKey);
XCTAssertNotEqual(cellKey.length, 0);
XCTAssertNotEqual(cellKey, key, @"Secure Cell makes a copy of the key");
XCTAssert([cellKey isEqualToData:key]);
}
// The key is wiped after the cell has left the scope and has been deallocated.
XCTAssertNotNil(cellKey);
XCTAssertEqual(cellKey.length, 0);
XCTAssertFalse([cellKey isEqualToData:key]);
}
}

@end

#pragma mark - Token Protect
Expand Down Expand Up @@ -724,6 +746,28 @@ - (void)testOldAPIWithoutContext
}
#pragma clang diagnostic pop

- (void)testKeyWipedOnDealloc
{
NSData *key = TSGenerateSymmetricKey();
{
NSData *cellKey;
{
TSCellToken *cell = [[TSCellToken alloc] initWithKey:key];

cellKey = cell.key;

XCTAssertNotNil(cellKey);
XCTAssertNotEqual(cellKey.length, 0);
XCTAssertNotEqual(cellKey, key, @"Secure Cell makes a copy of the key");
XCTAssert([cellKey isEqualToData:key]);
}
// The key is wiped after the cell has left the scope and has been deallocated.
XCTAssertNotNil(cellKey);
XCTAssertEqual(cellKey.length, 0);
XCTAssertFalse([cellKey isEqualToData:key]);
}
}

@end

#pragma mark - Context Imprint
Expand Down Expand Up @@ -972,4 +1016,26 @@ - (void)testOldAPI
}
#pragma clang diagnostic pop

- (void)testKeyWipedOnDealloc
{
NSData *key = TSGenerateSymmetricKey();
{
NSData *cellKey;
{
TSCellContextImprint *cell = [[TSCellContextImprint alloc] initWithKey:key];

cellKey = cell.key;

XCTAssertNotNil(cellKey);
XCTAssertNotEqual(cellKey.length, 0);
XCTAssertNotEqual(cellKey, key, @"Secure Cell makes a copy of the key");
XCTAssert([cellKey isEqualToData:key]);
}
// The key is wiped after the cell has left the scope and has been deallocated.
XCTAssertNotNil(cellKey);
XCTAssertEqual(cellKey.length, 0);
XCTAssertFalse([cellKey isEqualToData:key]);
}
}

@end
54 changes: 54 additions & 0 deletions tests/objcthemis/objthemis/SecureCellTestsSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,24 @@ class SecureCellSealSwift: XCTestCase {
XCTAssertNotNil(decrypted)
XCTAssertEqual(decrypted, message)
}

func testKeyNotWipedOnDestruction() {
let key = TSGenerateSymmetricKey()!
do {
let cellKey: Data
do {
let cell = TSCellSeal(key: key)!

cellKey = cell.key

XCTAssertNotEqual(cellKey.count, 0)
XCTAssertEqual(cellKey, key)
}
// In Swift "Data" is a value type so "cellKey" is a copy of the key
// which is not wiped by Secure Cell.
XCTAssertEqual(cellKey, key)
}
}
}

// MARK: - Token Protect
Expand Down Expand Up @@ -493,6 +511,24 @@ class SecureCellTokenProtectSwift: XCTestCase {
XCTAssertNotNil(decrypted)
XCTAssertEqual(decrypted, message)
}

func testKeyNotWipedOnDestruction() {
let key = TSGenerateSymmetricKey()!
do {
let cellKey: Data
do {
let cell = TSCellToken(key: key)!

cellKey = cell.key

XCTAssertNotEqual(cellKey.count, 0)
XCTAssertEqual(cellKey, key)
}
// In Swift "Data" is a value type so "cellKey" is a copy of the key
// which is not wiped by Secure Cell.
XCTAssertEqual(cellKey, key)
}
}
}

// MARK: - Context Imprint
Expand Down Expand Up @@ -664,4 +700,22 @@ class SecureCellContextImprintSwift: XCTestCase {
XCTAssertNotNil(decrypted)
XCTAssertEqual(decrypted, message)
}

func testKeyNotWipedOnDestruction() {
let key = TSGenerateSymmetricKey()!
do {
let cellKey: Data
do {
let cell = TSCellContextImprint(key: key)!

cellKey = cell.key

XCTAssertNotEqual(cellKey.count, 0)
XCTAssertEqual(cellKey, key)
}
// In Swift "Data" is a value type so "cellKey" is a copy of the key
// which is not wiped by Secure Cell.
XCTAssertEqual(cellKey, key)
}
}
}