aboutsummaryrefslogtreecommitdiff
path: root/xcode/OLMKit
diff options
context:
space:
mode:
authormanuroe <manu@matrix.org>2018-10-16 15:51:31 +0200
committermanuroe <manu@matrix.org>2018-10-16 15:51:31 +0200
commit9fd50c8eb50b788009be4f23729f2924e64349f5 (patch)
tree52962b005d02b86fee5ec8b2f0c3a3c394683ee4 /xcode/OLMKit
parent1eac1daa4787c8744ff7eb1a21fa56c737c4569b (diff)
OLMKit: Add objc wrappers for pk encryption/decryption
Diffstat (limited to 'xcode/OLMKit')
-rw-r--r--xcode/OLMKit/OLMKit.h2
-rw-r--r--xcode/OLMKit/OLMPKEncryption.h42
-rw-r--r--xcode/OLMKit/OLMPKEncryption.m111
-rw-r--r--xcode/OLMKit/OLMPkDecryption.h64
-rw-r--r--xcode/OLMKit/OLMPkDecryption.m295
-rw-r--r--xcode/OLMKit/OLMPkMessage.h31
-rw-r--r--xcode/OLMKit/OLMPkMessage.m32
7 files changed, 577 insertions, 0 deletions
diff --git a/xcode/OLMKit/OLMKit.h b/xcode/OLMKit/OLMKit.h
index 455d11b..6f79399 100644
--- a/xcode/OLMKit/OLMKit.h
+++ b/xcode/OLMKit/OLMKit.h
@@ -26,6 +26,8 @@
#import <OLMKit/OLMUtility.h>
#import <OLMKit/OLMInboundGroupSession.h>
#import <OLMKit/OLMOutboundGroupSession.h>
+#import <OLMKit/OLMPkEncryption.h>
+#import <OLMKit/OLMPkDecryption.h>
@interface OLMKit : NSObject
diff --git a/xcode/OLMKit/OLMPKEncryption.h b/xcode/OLMKit/OLMPKEncryption.h
new file mode 100644
index 0000000..a55d5bc
--- /dev/null
+++ b/xcode/OLMKit/OLMPKEncryption.h
@@ -0,0 +1,42 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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.0OLMPKEncryption
+ 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 <Foundation/Foundation.h>
+
+#import "OLMPkMessage.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OLMPkEncryption : NSObject
+
+/**
+ Set the recipient's public key for encrypting to.
+
+ @param recipientKey the recipient's public key.
+ */
+- (void)setRecipientKey:(NSString*)recipientKey;
+
+/**
+ Encrypt a plaintext for the recipient.
+
+ @param message the message to encrypt.
+ @param error the error if any.
+ @return the encrypted message.
+ */
+- (OLMPkMessage *)encryptMessage:(NSString*)message error:(NSError* _Nullable *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/xcode/OLMKit/OLMPKEncryption.m b/xcode/OLMKit/OLMPKEncryption.m
new file mode 100644
index 0000000..c2e3d04
--- /dev/null
+++ b/xcode/OLMKit/OLMPKEncryption.m
@@ -0,0 +1,111 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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 "OLMPkEncryption.h"
+
+#include "olm/olm.h"
+#include "olm/pk.h"
+#include "OLMUtility.h"
+
+@interface OLMPkEncryption ()
+{
+ OlmPkEncryption *session;
+}
+@end
+
+@implementation OLMPkEncryption
+
+- (void)dealloc {
+ olm_clear_pk_encryption(session);
+ free(session);
+}
+
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ session = (OlmPkEncryption *)malloc(olm_pk_encryption_size());
+ olm_pk_encryption(session);
+ }
+ return self;
+}
+
+- (void)setRecipientKey:(NSString*)recipientKey {
+ NSData *recipientKeyData = [recipientKey dataUsingEncoding:NSUTF8StringEncoding];
+ olm_pk_encryption_set_recipient_key(session, recipientKeyData.bytes, recipientKeyData.length);
+}
+
+- (OLMPkMessage *)encryptMessage:(NSString *)message error:(NSError *__autoreleasing _Nullable *)error {
+ NSData *plaintextData = [message dataUsingEncoding:NSUTF8StringEncoding];
+
+ size_t randomLength = olm_pk_encrypt_random_length(session);
+ NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
+ if (!random) {
+ return nil;
+ }
+
+ size_t ciphertextLength = olm_pk_ciphertext_length(session, plaintextData.length);
+ NSMutableData *ciphertext = [NSMutableData dataWithLength:ciphertextLength];
+ if (!ciphertext) {
+ return nil;
+ }
+
+ size_t macLength = olm_pk_mac_length(session);
+ NSMutableData *macData = [NSMutableData dataWithLength:macLength];
+ if (!ciphertext) {
+ return nil;
+ }
+
+ size_t ephemeralKeyLength = olm_pk_key_length();
+ NSMutableData *ephemeralKeyData = [NSMutableData dataWithLength:ephemeralKeyLength];
+ if (!ciphertext) {
+ return nil;
+ }
+
+ size_t result = olm_pk_encrypt(session,
+ plaintextData.bytes, plaintextData.length,
+ ciphertext.mutableBytes, ciphertext.length,
+ macData.mutableBytes, macLength,
+ ephemeralKeyData.mutableBytes, ephemeralKeyLength,
+ random.mutableBytes, randomLength);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_encryption_last_error(session);
+
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ NSLog(@"[OLMPkEncryption] encryptMessage: olm_group_encrypt error: %@", errorString);
+
+ if (error && olm_error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain
+ code:0
+ userInfo:@{
+ NSLocalizedDescriptionKey: errorString,
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_group_encrypt error: %@", errorString]
+ }];
+ }
+
+ return nil;
+ }
+
+ OLMPkMessage *encryptedMessage = [[OLMPkMessage alloc]
+ initWithCiphertext:[[NSString alloc] initWithData:ciphertext encoding:NSUTF8StringEncoding]
+ mac:[[NSString alloc] initWithData:macData encoding:NSUTF8StringEncoding]
+ ephemeralKey:[[NSString alloc] initWithData:ephemeralKeyData encoding:NSUTF8StringEncoding]];
+
+
+ return encryptedMessage;
+}
+
+@end
diff --git a/xcode/OLMKit/OLMPkDecryption.h b/xcode/OLMKit/OLMPkDecryption.h
new file mode 100644
index 0000000..8715a99
--- /dev/null
+++ b/xcode/OLMKit/OLMPkDecryption.h
@@ -0,0 +1,64 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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 <Foundation/Foundation.h>
+
+#import "OLMSerializable.h"
+#import "OLMPkMessage.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OLMPkDecryption : NSObject <OLMSerializable, NSSecureCoding>
+
+/**
+ Initialise the key from the private part of a key as returned by `privateKey`.
+
+ Note that the pubkey is a base64 encoded string, but the private key is
+ an unencoded byte array.
+
+ @param privateKey the private key part.
+ @param error the error if any.
+ @return the associated public key.
+ */
+- (NSString *)setPrivateKey:(NSData*)privateKey error:(NSError* _Nullable *)error;
+
+/**
+ Generate a new key to use for decrypting messages.
+
+ @param error the error if any.
+ @return the public part of the generated key.
+ */
+- (NSString *)generateKey:(NSError* _Nullable *)error;
+
+/**
+ Get the private key.
+
+ @return the private key;
+ */
+- (NSData *)privateKey;
+
+/**
+ Decrypt a ciphertext.
+
+ @param message the cipher message to decrypt.
+ @param error the error if any.
+ @return the decrypted message.
+ */
+- (NSString *)decryptMessage:(OLMPkMessage*)message error:(NSError* _Nullable *)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/xcode/OLMKit/OLMPkDecryption.m b/xcode/OLMKit/OLMPkDecryption.m
new file mode 100644
index 0000000..38a86a2
--- /dev/null
+++ b/xcode/OLMKit/OLMPkDecryption.m
@@ -0,0 +1,295 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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 "OLMPkDecryption.h"
+
+#include "olm/olm.h"
+#include "olm/pk.h"
+#include "OLMUtility.h"
+
+@interface OLMPkDecryption ()
+{
+ OlmPkDecryption *session;
+}
+@end
+
+@implementation OLMPkDecryption
+
+- (void)dealloc {
+ olm_clear_pk_decryption(session);
+ free(session);
+}
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ session = (OlmPkDecryption *)malloc(olm_pk_decryption_size());
+ olm_pk_decryption(session);
+ }
+ return self;
+}
+
+- (NSString *)setPrivateKey:(NSData *)privateKey error:(NSError *__autoreleasing _Nullable *)error {
+ size_t publicKeyLength = olm_pk_key_length();
+ NSMutableData *publicKeyData = [NSMutableData dataWithLength:publicKeyLength];
+ if (!publicKeyData) {
+ return nil;
+ }
+
+ size_t result = olm_pk_key_from_private(session,
+ publicKeyData.mutableBytes, publicKeyLength,
+ (void*)privateKey.bytes, privateKey.length);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+ NSLog(@"[OLMPkDecryption] setPrivateKey: olm_pk_key_from_private error: %s", olm_error);
+
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ if (error && olm_error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain
+ code:0
+ userInfo:@{
+ NSLocalizedDescriptionKey: errorString,
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_pk_key_from_private error: %@", errorString]
+ }];
+ }
+ return nil;
+ }
+
+ NSString *publicKey = [[NSString alloc] initWithData:publicKeyData encoding:NSUTF8StringEncoding];
+ [publicKeyData resetBytesInRange:NSMakeRange(0, publicKeyData.length)];
+
+ return publicKey;
+}
+
+- (NSString *)generateKey:(NSError *__autoreleasing _Nullable *)error {
+ size_t randomLength = olm_pk_private_key_length();
+ NSMutableData *random = [OLMUtility randomBytesOfLength:randomLength];
+ if (!random) {
+ return nil;
+ }
+
+ size_t publicKeyLength = olm_pk_key_length();
+ NSMutableData *publicKeyData = [NSMutableData dataWithLength:publicKeyLength];
+ if (!publicKeyData) {
+ return nil;
+ }
+
+ size_t result = olm_pk_key_from_private(session,
+ publicKeyData.mutableBytes, publicKeyData.length,
+ random.mutableBytes, randomLength);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+ NSLog(@"[OLMPkDecryption] generateKey: olm_pk_key_from_private error: %s", olm_error);
+
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ if (error && olm_error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain
+ code:0
+ userInfo:@{
+ NSLocalizedDescriptionKey: errorString,
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_pk_key_from_private error: %@", errorString]
+ }];
+ }
+ return nil;
+ }
+
+ NSString *publicKey = [[NSString alloc] initWithData:publicKeyData encoding:NSUTF8StringEncoding];
+ [publicKeyData resetBytesInRange:NSMakeRange(0, publicKeyData.length)];
+
+ return publicKey;
+}
+
+- (NSData *)privateKey {
+ size_t privateKeyLength = olm_pk_private_key_length();
+ NSMutableData *privateKeyData = [NSMutableData dataWithLength:privateKeyLength];
+ if (!privateKeyData) {
+ return nil;
+ }
+
+ size_t result = olm_pk_get_private_key(session,
+ privateKeyData.mutableBytes, privateKeyLength);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+ NSLog(@"[OLMPkDecryption] privateKey: olm_pk_get_private_key error: %s", olm_error);
+ return nil;
+ }
+
+ NSData *privateKey = [privateKeyData copy];
+ [privateKeyData resetBytesInRange:NSMakeRange(0, privateKeyData.length)];
+
+ return privateKey;
+}
+
+-(NSString *)decryptMessage:(OLMPkMessage *)message error:(NSError *__autoreleasing _Nullable *)error {
+ NSData *messageData = [message.ciphertext dataUsingEncoding:NSUTF8StringEncoding];
+ NSData *macData = [message.mac dataUsingEncoding:NSUTF8StringEncoding];
+ NSData *ephemeralKeyData = [message.ephemeralKey dataUsingEncoding:NSUTF8StringEncoding];
+ if (!messageData || !macData || !ephemeralKeyData) {
+ return nil;
+ }
+
+ NSMutableData *mutMessage = messageData.mutableCopy;
+ size_t maxPlaintextLength = olm_pk_max_plaintext_length(session, mutMessage.length);
+ if (maxPlaintextLength == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ NSLog(@"[OLMPkDecryption] decryptMessage: olm_pk_max_plaintext_length error: %@", errorString);
+
+ if (error && olm_error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain
+ code:0
+ userInfo:@{
+ NSLocalizedDescriptionKey: errorString,
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_pk_max_plaintext_length error: %@", errorString]
+ }];
+ }
+
+ return nil;
+ }
+
+ mutMessage = messageData.mutableCopy;
+ NSMutableData *plaintextData = [NSMutableData dataWithLength:maxPlaintextLength];
+ size_t plaintextLength = olm_pk_decrypt(session,
+ ephemeralKeyData.bytes, ephemeralKeyData.length,
+ macData.bytes, macData.length,
+ mutMessage.mutableBytes, mutMessage.length,
+ plaintextData.mutableBytes, plaintextData.length);
+ if (plaintextLength == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ NSLog(@"[OLMPkDecryption] decryptMessage: olm_pk_decrypt error: %@", errorString);
+
+ if (error && olm_error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain
+ code:0
+ userInfo:@{
+ NSLocalizedDescriptionKey: errorString,
+ NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"olm_decrypt error: %@", errorString]
+ }];
+ }
+
+ return nil;
+ }
+
+ plaintextData.length = plaintextLength;
+ NSString *plaintext = [[NSString alloc] initWithData:plaintextData encoding:NSUTF8StringEncoding];
+ [plaintextData resetBytesInRange:NSMakeRange(0, plaintextData.length)];
+ return plaintext;
+}
+
+#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) {
+ *error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"Bad length."}];
+ }
+ return nil;
+ }
+
+ size_t ephemeralLength = olm_pk_key_length();
+ NSMutableData *ephemeralBuffer = [NSMutableData dataWithLength:ephemeralLength];
+
+ NSMutableData *pickle = [serializedData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
+ size_t result = olm_unpickle_pk_decryption(session,
+ key.bytes, key.length,
+ pickle.mutableBytes, pickle.length,
+ ephemeralBuffer.mutableBytes, ephemeralLength);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ if (error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+ }
+ 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_pk_decryption_length(session);
+ NSMutableData *pickled = [NSMutableData dataWithLength:length];
+
+ size_t result = olm_pickle_pk_decryption(session,
+ key.bytes, key.length,
+ pickled.mutableBytes, pickled.length);
+ if (result == olm_error()) {
+ const char *olm_error = olm_pk_decryption_last_error(session);
+ NSString *errorString = [NSString stringWithUTF8String:olm_error];
+ if (error && errorString) {
+ *error = [NSError errorWithDomain:OLMErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: errorString}];
+ }
+ return nil;
+ }
+
+ NSString *pickleString = [[NSString alloc] initWithData:pickled encoding:NSUTF8StringEncoding];
+ 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];
+ }
+
+ NSParameterAssert(error == nil);
+ NSParameterAssert(self != nil);
+ if (!self) {
+ return nil;
+ }
+
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)encoder {
+ NSData *key = [OLMUtility randomBytesOfLength:32];
+ NSError *error = nil;
+
+ NSString *pickle = [self serializeDataWithKey:key error:&error];
+ NSParameterAssert(pickle.length > 0 && error == nil);
+
+ [encoder encodeObject:pickle forKey:@"pickle"];
+ [encoder encodeObject:key forKey:@"key"];
+ [encoder encodeObject:@"1" forKey:@"version"];
+}
+
+@end
diff --git a/xcode/OLMKit/OLMPkMessage.h b/xcode/OLMKit/OLMPkMessage.h
new file mode 100644
index 0000000..1559fca
--- /dev/null
+++ b/xcode/OLMKit/OLMPkMessage.h
@@ -0,0 +1,31 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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 <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OLMPkMessage : NSObject
+
+@property (nonatomic, copy, readonly) NSString *ciphertext;
+@property (nonatomic, copy, readonly,) NSString *mac;
+@property (nonatomic, copy, readonly) NSString *ephemeralKey;
+
+- (instancetype) initWithCiphertext:(NSString*)ciphertext mac:(NSString*)mac ephemeralKey:(NSString*)ephemeralKey;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/xcode/OLMKit/OLMPkMessage.m b/xcode/OLMKit/OLMPkMessage.m
new file mode 100644
index 0000000..0f24512
--- /dev/null
+++ b/xcode/OLMKit/OLMPkMessage.m
@@ -0,0 +1,32 @@
+/*
+ Copyright 2018 New Vector Ltd
+
+ 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 "OLMPkMessage.h"
+
+@implementation OLMPkMessage
+
+- (instancetype)initWithCiphertext:(NSString *)ciphertext mac:(NSString *)mac ephemeralKey:(NSString *)ephemeralKey {
+ self = [super init];
+ if (!self) {
+ return nil;
+ }
+ _ciphertext = [ciphertext copy];
+ _mac = [mac copy];
+ _ephemeralKey = [ephemeralKey copy];
+ return self;
+}
+
+@end