2016-10-10 17:10:51 +02:00
|
|
|
/*
|
|
|
|
Copyright 2016 OpenMarket Ltd
|
2016-11-17 15:50:23 +01:00
|
|
|
Copyright 2016 Vector Creations Ltd
|
2016-10-10 17:10:51 +02:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "OLMInboundGroupSession.h"
|
|
|
|
|
|
|
|
#import "OLMUtility.h"
|
|
|
|
#include "olm/olm.h"
|
2021-02-18 14:57:43 +01:00
|
|
|
#import "OLMKit.h"
|
2016-10-10 17:10:51 +02:00
|
|
|
|
|
|
|
@interface OLMInboundGroupSession ()
|
|
|
|
{
|
|
|
|
OlmInboundGroupSession *session;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation OLMInboundGroupSession
|
|
|
|
|
|
|
|
- (void)dealloc {
|
|
|
|
olm_clear_inbound_group_session(session);
|
|
|
|
free(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (instancetype)init {
|
|
|
|
self = [super init];
|
|
|
|
if (self)
|
|
|
|
{
|
|
|
|
session = malloc(olm_inbound_group_session_size());
|
|
|
|
if (session) {
|
|
|
|
session = olm_inbound_group_session(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!session) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2016-11-14 16:54:51 +01:00
|
|
|
- (instancetype)initInboundGroupSessionWithSessionKey:(NSString *)sessionKey error:(NSError**)error {
|
2016-10-10 17:10:51 +02:00
|
|
|
self = [self init];
|
|
|
|
if (self) {
|
|
|
|
NSData *sessionKeyData = [sessionKey dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
size_t result = olm_init_inbound_group_session(session, sessionKeyData.bytes, sessionKeyData.length);
|
|
|
|
if (result == olm_error()) {
|
2016-11-14 16:54:51 +01:00
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
NSLog(@"olm_init_inbound_group_session error: %@", errorString);
|
|
|
|
|
|
|
|
if (error && olm_error && errorString) {
|
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain
|
|
|
|
code:0
|
|
|
|
userInfo:@{
|
2016-11-24 11:45:59 +01:00
|
|
|
NSLocalizedDescriptionKey: errorString,
|
|
|
|
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_init_inbound_group_session error: %@", errorString]
|
2016-11-14 16:54:51 +01:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2017-01-17 14:47:41 +01:00
|
|
|
- (instancetype)initInboundGroupSessionWithImportedSession:(NSString *)sessionKey error:(NSError *__autoreleasing *)error
|
|
|
|
{
|
|
|
|
self = [self init];
|
|
|
|
if (self) {
|
|
|
|
NSData *sessionKeyData = [sessionKey dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
size_t result = olm_import_inbound_group_session(session, sessionKeyData.bytes, sessionKeyData.length);
|
|
|
|
if (result == olm_error()) {
|
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
NSLog(@"olm_import_inbound_group_session error: %@", errorString);
|
|
|
|
|
|
|
|
if (error && olm_error && errorString) {
|
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain
|
|
|
|
code:0
|
|
|
|
userInfo:@{
|
|
|
|
NSLocalizedDescriptionKey: errorString,
|
|
|
|
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_import_inbound_group_session error: %@", errorString]
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
- (NSString *)sessionIdentifier {
|
|
|
|
size_t length = olm_inbound_group_session_id_length(session);
|
|
|
|
NSMutableData *idData = [NSMutableData dataWithLength:length];
|
|
|
|
if (!idData) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
size_t result = olm_inbound_group_session_id(session, idData.mutableBytes, idData.length);
|
|
|
|
if (result == olm_error()) {
|
|
|
|
const char *error = olm_inbound_group_session_last_error(session);
|
2016-11-14 16:54:51 +01:00
|
|
|
NSLog(@"olm_inbound_group_session_id error: %s", error);
|
2016-10-10 17:10:51 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSString *idString = [[NSString alloc] initWithData:idData encoding:NSUTF8StringEncoding];
|
|
|
|
return idString;
|
|
|
|
}
|
|
|
|
|
2016-11-14 16:54:51 +01:00
|
|
|
- (NSString *)decryptMessage:(NSString *)message messageIndex:(NSUInteger*)messageIndex error:(NSError**)error
|
2016-10-10 17:10:51 +02:00
|
|
|
{
|
|
|
|
NSParameterAssert(message != nil);
|
|
|
|
NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
if (!messageData) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSMutableData *mutMessage = messageData.mutableCopy;
|
|
|
|
size_t maxPlaintextLength = olm_group_decrypt_max_plaintext_length(session, mutMessage.mutableBytes, mutMessage.length);
|
|
|
|
if (maxPlaintextLength == olm_error()) {
|
2016-11-14 16:54:51 +01:00
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
NSLog(@"olm_group_decrypt_max_plaintext_length error: %@", errorString);
|
|
|
|
|
|
|
|
if (error && olm_error && errorString) {
|
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain
|
|
|
|
code:0
|
|
|
|
userInfo:@{
|
2016-11-24 11:45:59 +01:00
|
|
|
NSLocalizedDescriptionKey: errorString,
|
|
|
|
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_decrypt_max_plaintext_length error: %@", errorString]
|
2016-11-14 16:54:51 +01:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
// message buffer is destroyed by olm_group_decrypt_max_plaintext_length
|
|
|
|
mutMessage = messageData.mutableCopy;
|
|
|
|
NSMutableData *plaintextData = [NSMutableData dataWithLength:maxPlaintextLength];
|
2016-11-14 17:02:56 +01:00
|
|
|
|
|
|
|
uint32_t message_index;
|
|
|
|
size_t plaintextLength = olm_group_decrypt(session, mutMessage.mutableBytes, mutMessage.length, plaintextData.mutableBytes, plaintextData.length, &message_index);
|
2016-10-10 17:10:51 +02:00
|
|
|
if (plaintextLength == olm_error()) {
|
2016-11-14 16:54:51 +01:00
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
NSLog(@"olm_group_decrypt error: %@", errorString);
|
|
|
|
|
|
|
|
if (error && olm_error && errorString) {
|
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain
|
|
|
|
code:0
|
|
|
|
userInfo:@{
|
2016-11-24 11:45:59 +01:00
|
|
|
NSLocalizedDescriptionKey: errorString,
|
|
|
|
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_decrypt error: %@", errorString]
|
2016-11-14 16:54:51 +01:00
|
|
|
}];
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
plaintextData.length = plaintextLength;
|
|
|
|
NSString *plaintext = [[NSString alloc] initWithData:plaintextData encoding:NSUTF8StringEncoding];
|
2016-12-20 11:46:57 +01:00
|
|
|
[plaintextData resetBytesInRange:NSMakeRange(0, plaintextData.length)];
|
2016-11-14 17:02:56 +01:00
|
|
|
|
|
|
|
if (messageIndex)
|
|
|
|
{
|
|
|
|
*messageIndex = message_index;
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
return plaintext;
|
|
|
|
}
|
|
|
|
|
2017-01-17 14:47:41 +01:00
|
|
|
- (NSUInteger)firstKnownIndex
|
|
|
|
{
|
|
|
|
return olm_inbound_group_session_first_known_index(session);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isVerified
|
|
|
|
{
|
|
|
|
return (0 != olm_inbound_group_session_is_verified(session));
|
|
|
|
}
|
|
|
|
|
2017-02-27 10:54:03 +01:00
|
|
|
- (NSString*)exportSessionAtMessageIndex:(NSUInteger)messageIndex error:(NSError**)error;
|
2017-01-17 14:47:41 +01:00
|
|
|
{
|
|
|
|
size_t length = olm_export_inbound_group_session_length(session);
|
|
|
|
NSMutableData *key = [NSMutableData dataWithLength:length];
|
2018-06-25 17:57:51 +02:00
|
|
|
size_t result = olm_export_inbound_group_session(session, key.mutableBytes, key.length, (uint32_t)messageIndex);
|
2017-01-17 14:47:41 +01:00
|
|
|
if (result == olm_error()) {
|
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
if (error && errorString) {
|
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSString *keyString = [[NSString alloc] initWithData:key encoding:NSUTF8StringEncoding];
|
2017-01-17 16:14:22 +01:00
|
|
|
[key resetBytesInRange:NSMakeRange(0, key.length)];
|
2017-01-17 14:47:41 +01:00
|
|
|
return keyString;
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
|
|
|
|
#pragma mark OLMSerializable
|
|
|
|
|
|
|
|
/** Initializes from encrypted serialized data. Will throw error if invalid key or invalid base64. */
|
|
|
|
- (instancetype) initWithSerializedData:(NSString *)serializedData key:(NSData *)key error:(NSError *__autoreleasing *)error {
|
|
|
|
self = [self init];
|
|
|
|
if (!self) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSParameterAssert(key.length > 0);
|
|
|
|
NSParameterAssert(serializedData.length > 0);
|
|
|
|
if (key.length == 0 || serializedData.length == 0) {
|
|
|
|
if (error) {
|
2016-11-14 16:54:51 +01:00
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
|
2016-10-10 17:10:51 +02:00
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
|
|
|
|
size_t result = olm_unpickle_inbound_group_session(session, key.bytes, key.length, pickle.mutableBytes, pickle.length);
|
2018-10-17 11:29:34 +02:00
|
|
|
[pickle resetBytesInRange:NSMakeRange(0, pickle.length)];
|
2016-10-10 17:10:51 +02:00
|
|
|
if (result == olm_error()) {
|
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
if (error && errorString) {
|
2016-11-14 16:54:51 +01:00
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
|
2016-10-10 17:10:51 +02:00
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Serializes and encrypts object data, outputs base64 blob */
|
|
|
|
- (NSString*) serializeDataWithKey:(NSData*)key error:(NSError**)error {
|
|
|
|
NSParameterAssert(key.length > 0);
|
|
|
|
size_t length = olm_pickle_inbound_group_session_length(session);
|
|
|
|
NSMutableData *pickled = [NSMutableData dataWithLength:length];
|
|
|
|
size_t result = olm_pickle_inbound_group_session(session, key.bytes, key.length, pickled.mutableBytes, pickled.length);
|
|
|
|
if (result == olm_error()) {
|
|
|
|
const char *olm_error = olm_inbound_group_session_last_error(session);
|
|
|
|
NSString *errorString = [NSString stringWithUTF8String:olm_error];
|
|
|
|
if (error && errorString) {
|
2016-11-14 16:54:51 +01:00
|
|
|
*error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
|
2016-10-10 17:10:51 +02:00
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
|
2018-10-17 11:29:34 +02:00
|
|
|
[pickled resetBytesInRange:NSMakeRange(0, pickled.length)];
|
2016-10-10 17:10:51 +02:00
|
|
|
return pickleString;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark NSSecureCoding
|
|
|
|
|
|
|
|
+ (BOOL) supportsSecureCoding {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark NSCoding
|
|
|
|
|
|
|
|
- (id)initWithCoder:(NSCoder *)decoder {
|
|
|
|
NSString *version = [decoder decodeObjectOfClass:[NSString class] forKey:@"version"];
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
|
|
|
|
if ([version isEqualToString:@"1"]) {
|
|
|
|
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
|
|
|
|
NSData *key = [decoder decodeObjectOfClass:[NSData class] forKey:@"key"];
|
|
|
|
|
|
|
|
self = [self initWithSerializedData:pickle key:key error:&error];
|
|
|
|
}
|
2021-02-18 14:57:43 +01:00
|
|
|
else if ([version isEqualToString:@"2"]) {
|
|
|
|
NSString *pickle = [decoder decodeObjectOfClass:[NSString class] forKey:@"pickle"];
|
|
|
|
NSData *key = OLMKit.sharedInstance.pickleKeyDelegate.pickleKey;
|
|
|
|
NSParameterAssert(key);
|
|
|
|
|
|
|
|
self = [self initWithSerializedData:pickle key:key error:&error];
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
NSParameterAssert(error == nil);
|
|
|
|
NSParameterAssert(self != nil);
|
|
|
|
if (!self) {
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)encodeWithCoder:(NSCoder *)encoder {
|
2021-02-18 14:57:43 +01:00
|
|
|
NSData *key = OLMKit.sharedInstance.pickleKeyDelegate.pickleKey;
|
|
|
|
if (key)
|
|
|
|
{
|
|
|
|
[encoder encodeObject:@"2" forKey:@"version"];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
key = [OLMUtility randomBytesOfLength:32];
|
|
|
|
[encoder encodeObject:key forKey:@"key"];
|
|
|
|
[encoder encodeObject:@"1" forKey:@"version"];
|
|
|
|
}
|
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
NSError *error = nil;
|
|
|
|
NSString *pickle = [self serializeDataWithKey:key error:&error];
|
|
|
|
NSParameterAssert(pickle.length > 0 && error == nil);
|
2021-02-18 14:57:43 +01:00
|
|
|
|
2016-10-10 17:10:51 +02:00
|
|
|
[encoder encodeObject:pickle forKey:@"pickle"];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|