Skip to content

Commit

Permalink
Fix ChatSecure#4: Add encryption for group messaging
Browse files Browse the repository at this point in the history
Co-Authored-By: Matthew Di Pasquale <[email protected]>
  • Loading branch information
matthewrpacker and ma11hew28 committed Mar 3, 2018
1 parent 6c85308 commit 41879ac
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 11 deletions.
4 changes: 3 additions & 1 deletion Classes/Models/SignalCiphertext.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
typedef NS_ENUM(NSInteger, SignalCiphertextType) {
SignalCiphertextTypeUnknown,
SignalCiphertextTypeMessage,
SignalCiphertextTypePreKeyMessage
SignalCiphertextTypePreKeyMessage,
SignalCiphertextTypeSenderKeyMessage,
SignalCiphertextTypeSenderKeyDistributionMessage
};

NS_ASSUME_NONNULL_BEGIN
Expand Down
16 changes: 16 additions & 0 deletions Classes/Models/SignalSenderKeyDistributionMessage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@import Foundation;
#import "SignalContext.h"

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyDistributionMessage : NSObject

- (nullable instancetype)initWithData:(NSData *)data
context:(SignalContext *)context
error:(NSError **)error;

- (NSData *)serializedData;

@end

NS_ASSUME_NONNULL_END
51 changes: 51 additions & 0 deletions Classes/Models/SignalSenderKeyDistributionMessage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#import "SignalSenderKeyDistributionMessage_Internal.h"
#import "SignalContext_Internal.h"
#import "SignalError.h"

@implementation SignalSenderKeyDistributionMessage

- (void)dealloc {
if (_sender_key_distribution_message) {
SIGNAL_UNREF(_sender_key_distribution_message);
}
}

- (instancetype)initWithSenderKeyDistributionMessage:(sender_key_distribution_message *)sender_key_distribution_message {
NSParameterAssert(sender_key_distribution_message);
if (!sender_key_distribution_message) { return nil; }
if (self = [super init]) {
_sender_key_distribution_message = sender_key_distribution_message;
}
return self;
}

- (instancetype)initWithData:(NSData *)data
context:(SignalContext *)context
error:(NSError **)error {
NSParameterAssert(data);
NSParameterAssert(context);
if (!data || !context) {
if (error) {
*error = ErrorFromSignalError(SignalErrorInvalidArgument);
}
return nil;
}
if (self = [super init]) {
int result = sender_key_distribution_message_deserialize(&_sender_key_distribution_message, data.bytes, data.length, context.context);
if (result < 0 || !_sender_key_distribution_message) {
if (error) {
*error = ErrorFromSignalError(SignalErrorFromCode(result));
}
return nil;
}
}
return self;
}

- (NSData *)serializedData {
ciphertext_message *message = (ciphertext_message *)_sender_key_distribution_message;
signal_buffer *serialized = ciphertext_message_get_serialized(message);
return [NSData dataWithBytes:signal_buffer_data(serialized) length:signal_buffer_len(serialized)];
}

@end
14 changes: 14 additions & 0 deletions Classes/Models/SignalSenderKeyDistributionMessage_Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import "SignalSenderKeyDistributionMessage.h"
@import SignalProtocolC;

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyDistributionMessage ()

@property (readonly, nonatomic) sender_key_distribution_message *sender_key_distribution_message;

- (instancetype)initWithSenderKeyDistributionMessage:(sender_key_distribution_message *)sender_key_distribution_message;

@end

NS_ASSUME_NONNULL_END
14 changes: 14 additions & 0 deletions Classes/Models/SignalSenderKeyMessage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@import Foundation;
#import "SignalContext.h"

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyMessage : NSObject

- (nullable instancetype)initWithData:(NSData *)data
context:(SignalContext *)context
error:(NSError **)error;

@end

NS_ASSUME_NONNULL_END
36 changes: 36 additions & 0 deletions Classes/Models/SignalSenderKeyMessage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#import "SignalSenderKeyMessage_Internal.h"
#import "SignalContext_Internal.h"
#import "SignalError.h"

@implementation SignalSenderKeyMessage

- (void)dealloc {
if (_sender_key_message) {
SIGNAL_UNREF(_sender_key_message);
}
}

- (instancetype)initWithData:(NSData *)data
context:(SignalContext *)context
error:(NSError **)error {
NSParameterAssert(data);
NSParameterAssert(context);
if (!data || !context) {
if (error) {
*error = ErrorFromSignalError(SignalErrorInvalidArgument);
}
return nil;
}
if (self = [super init]) {
int result = sender_key_message_deserialize(&_sender_key_message, data.bytes, data.length, context.context);
if (result < 0 || !_sender_key_message) {
if (error) {
*error = ErrorFromSignalError(SignalErrorFromCode(result));
}
return nil;
}
}
return self;
}

@end
12 changes: 12 additions & 0 deletions Classes/Models/SignalSenderKeyMessage_Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#import "SignalSenderKeyMessage.h"
@import SignalProtocolC;

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyMessage ()

@property (readonly, nonatomic) sender_key_message *sender_key_message;

@end

NS_ASSUME_NONNULL_END
14 changes: 14 additions & 0 deletions Classes/Models/SignalSenderKeyName.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import "SignalAddress.h"

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyName : NSObject

@property (readonly, copy, nonatomic) NSString *groupId;
@property (readonly, nonatomic) SignalAddress *address;

- (instancetype)initWithGroupId:(NSString *)groupId address:(SignalAddress *)address;

@end

NS_ASSUME_NONNULL_END
39 changes: 39 additions & 0 deletions Classes/Models/SignalSenderKeyName.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#import "SignalSenderKeyName_Internal.h"
#import "SignalAddress_Internal.h"

@implementation SignalSenderKeyName

- (void)dealloc {
if (_sender_key_name) {
free((void *)_sender_key_name->group_id);
free(_sender_key_name);
}
}

- (instancetype)initWithGroupId:(NSString *)groupId address:(SignalAddress *)address {
NSParameterAssert(groupId);
NSParameterAssert(address);
if (!groupId || !address) { return nil; }
if (self = [super init]) {
_groupId = [groupId copy];
_address = address;
_sender_key_name = malloc(sizeof(signal_protocol_sender_key_name));
_sender_key_name->group_id = strdup([groupId UTF8String]);
_sender_key_name->group_id_len = [groupId lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
_sender_key_name->sender = *(address.address);
}
return self;
}

- (instancetype)initWithSenderKeyName:(const signal_protocol_sender_key_name *)sender_key_name {
NSParameterAssert(sender_key_name);
NSParameterAssert(sender_key_name->group_id);
if (!sender_key_name || !sender_key_name->group_id) { return nil; }
NSString *groupId = [NSString stringWithUTF8String:sender_key_name->group_id];
SignalAddress *address = [[SignalAddress alloc] initWithAddress:&sender_key_name->sender];
if (self = [self initWithGroupId:groupId address:address]) {
}
return self;
}

@end
14 changes: 14 additions & 0 deletions Classes/Models/SignalSenderKeyName_Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import "SignalSenderKeyName.h"
@import SignalProtocolC;

NS_ASSUME_NONNULL_BEGIN

@interface SignalSenderKeyName ()

@property (readonly, nonatomic) signal_protocol_sender_key_name *sender_key_name;

- (nullable instancetype)initWithSenderKeyName:(const signal_protocol_sender_key_name *)sender_key_name;

@end

NS_ASSUME_NONNULL_END
20 changes: 20 additions & 0 deletions Classes/SignalGroupCipher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@import Foundation;
#import "SignalCiphertext.h"
#import "SignalContext.h"
#import "SignalSenderKeyName.h"

NS_ASSUME_NONNULL_BEGIN

@interface SignalGroupCipher : NSObject

@property (readonly, nonatomic) SignalContext *context;

- (instancetype)initWithSenderKeyName:(SignalSenderKeyName *)senderKeyName
context:(SignalContext *)context;

- (nullable SignalCiphertext *)encryptData:(NSData *)data error:(NSError **)error;
- (nullable NSData *)decryptCiphertext:(SignalCiphertext *)ciphertext error:(NSError **)error;

@end

NS_ASSUME_NONNULL_END
76 changes: 76 additions & 0 deletions Classes/SignalGroupCipher.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#import "SignalGroupCipher.h"
#import "SignalContext_Internal.h"
#import "SignalError.h"
#import "SignalSenderKeyMessage_Internal.h"
#import "SignalSenderKeyName_Internal.h"
#import "SignalStorage_Internal.h"

@interface SignalGroupCipher ()
@property (readonly, nonatomic) group_cipher *cipher;
@end

@implementation SignalGroupCipher

- (instancetype)initWithSenderKeyName:(SignalSenderKeyName *)senderKeyName
context:(SignalContext *)context {
NSParameterAssert(senderKeyName);
NSParameterAssert(context);
if (!senderKeyName || !context) { return nil; }
if (self = [super init]) {
_context = context;
int result = group_cipher_create(&_cipher, context.storage.storeContext, senderKeyName.sender_key_name, context.context);
NSAssert(result >= 0 && _cipher, @"couldn't create cipher");
if (result < 0 || !_cipher) {
return nil;
}
}
return self;
}

- (SignalCiphertext *)encryptData:(NSData *)data error:(NSError **)error {
NSParameterAssert(data);
if (!data) {
if (error) {
*error = ErrorFromSignalError(SignalErrorInvalidArgument);
}
return nil;
}
ciphertext_message *message = NULL;
int result = group_cipher_encrypt(_cipher, data.bytes, data.length, &message);
if (result < 0 || !message) {
*error = ErrorFromSignalError(SignalErrorFromCode(result));
return nil;
}
signal_buffer *serialized = ciphertext_message_get_serialized(message);
NSData *outData = [NSData dataWithBytes:signal_buffer_data(serialized) length:signal_buffer_len(serialized)];
SignalCiphertextType outType = SignalCiphertextTypeSenderKeyMessage;
SignalCiphertext *encrypted = [[SignalCiphertext alloc] initWithData:outData type:outType];
SIGNAL_UNREF(message);
return encrypted;
}

- (nullable NSData *)decryptCiphertext:(SignalCiphertext *)ciphertext error:(NSError **)error {
NSParameterAssert(ciphertext && ciphertext.data);
if (!ciphertext || !ciphertext.data) {
if (error) {
*error = ErrorFromSignalError(SignalErrorInvalidArgument);
}
return nil;
}
SignalSenderKeyMessage *message = [[SignalSenderKeyMessage alloc] initWithData:ciphertext.data context:_context error:error];
if (!message) { return nil; }
signal_buffer *buffer = NULL;
int result = SG_ERR_UNKNOWN;
result = group_cipher_decrypt(_cipher, message.sender_key_message, NULL, &buffer);
if (result < 0 || !buffer) {
if (error) {
*error = ErrorFromSignalError(SignalErrorFromCode(result));
}
return nil;
}
NSData *outData = [NSData dataWithBytes:signal_buffer_data(buffer) length:signal_buffer_len(buffer)];
signal_buffer_free(buffer);
return outData;
}

@end
22 changes: 22 additions & 0 deletions Classes/SignalGroupSessionBuilder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@import Foundation;
#import "SignalContext.h"
#import "SignalSenderKeyDistributionMessage.h"
#import "SignalSenderKeyName.h"

NS_ASSUME_NONNULL_BEGIN

@interface SignalGroupSessionBuilder : NSObject

@property (readonly, nonatomic) SignalContext *context;

- (instancetype)initWithContext:(SignalContext *)context;

- (BOOL)processSessionWithSenderKeyName:(SignalSenderKeyName *)senderKeyName
senderKeyDistributionMessage:(SignalSenderKeyDistributionMessage *)senderKeyDistributionMessage
error:(NSError **)error;
- (nullable SignalSenderKeyDistributionMessage *)createSessionWithSenderKeyName:(SignalSenderKeyName *)senderKeyName
error:(NSError **)error;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 41879ac

Please sign in to comment.