OLMKit: Add objc wrappers for pk encryption/decryption
This commit is contained in:
parent
1eac1daa47
commit
9fd50c8eb5
9 changed files with 688 additions and 0 deletions
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
3244277D2175EF700023EDF1 /* OLMKitPkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3244277C2175EF700023EDF1 /* OLMKitPkTests.m */; };
|
||||
3274F6021D9A633A005282E4 /* OLMKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3274F5F81D9A633A005282E4 /* OLMKit.framework */; };
|
||||
3274F6071D9A633A005282E4 /* OLMKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3274F6061D9A633A005282E4 /* OLMKitTests.m */; };
|
||||
3274F6131D9A698E005282E4 /* OLMKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3274F6121D9A698E005282E4 /* OLMKit.h */; };
|
||||
|
@ -27,6 +28,7 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
1B226B371526F2782C9D6372 /* Pods-OLMKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OLMKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-OLMKit/Pods-OLMKit.release.xcconfig"; sourceTree = "<group>"; };
|
||||
3244277C2175EF700023EDF1 /* OLMKitPkTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OLMKitPkTests.m; sourceTree = "<group>"; };
|
||||
3274F5F81D9A633A005282E4 /* OLMKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OLMKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3274F5FC1D9A633A005282E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
3274F6011D9A633A005282E4 /* OLMKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OLMKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -105,6 +107,7 @@
|
|||
3274F6051D9A633A005282E4 /* OLMKitTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3244277C2175EF700023EDF1 /* OLMKitPkTests.m */,
|
||||
3274F6061D9A633A005282E4 /* OLMKitTests.m */,
|
||||
32A151301DABDD4300400192 /* OLMKitGroupTests.m */,
|
||||
3274F6081D9A633A005282E4 /* Info.plist */,
|
||||
|
@ -279,6 +282,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3274F6071D9A633A005282E4 /* OLMKitTests.m in Sources */,
|
||||
3244277D2175EF700023EDF1 /* OLMKitPkTests.m in Sources */,
|
||||
32A151311DABDD4300400192 /* OLMKitGroupTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
42
xcode/OLMKit/OLMPKEncryption.h
Normal file
42
xcode/OLMKit/OLMPKEncryption.h
Normal file
|
@ -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
|
111
xcode/OLMKit/OLMPKEncryption.m
Normal file
111
xcode/OLMKit/OLMPKEncryption.m
Normal file
|
@ -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
|
64
xcode/OLMKit/OLMPkDecryption.h
Normal file
64
xcode/OLMKit/OLMPkDecryption.h
Normal file
|
@ -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
|
295
xcode/OLMKit/OLMPkDecryption.m
Normal file
295
xcode/OLMKit/OLMPkDecryption.m
Normal file
|
@ -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
|
31
xcode/OLMKit/OLMPkMessage.h
Normal file
31
xcode/OLMKit/OLMPkMessage.h
Normal file
|
@ -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
|
32
xcode/OLMKit/OLMPkMessage.m
Normal file
32
xcode/OLMKit/OLMPkMessage.m
Normal file
|
@ -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
|
107
xcode/OLMKitTests/OLMKitPkTests.m
Normal file
107
xcode/OLMKitTests/OLMKitPkTests.m
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
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 <XCTest/XCTest.h>
|
||||
#import <OLMKit/OLMKit.h>
|
||||
|
||||
/**
|
||||
Tests are inspired from js tests.
|
||||
*/
|
||||
@interface OLMKitPkTests : XCTestCase {
|
||||
OLMPkEncryption *encryption;
|
||||
OLMPkDecryption *decryption;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation OLMKitPkTests
|
||||
|
||||
- (void)setUp {
|
||||
encryption = [OLMPkEncryption new];
|
||||
decryption = [OLMPkDecryption new];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
encryption = nil;
|
||||
decryption = nil;
|
||||
}
|
||||
|
||||
- (void)testImportExportKeys {
|
||||
UInt8 alicePrivateBytes[] = {
|
||||
0x77, 0x07, 0x6D, 0x0A, 0x73, 0x18, 0xA5, 0x7D,
|
||||
0x3C, 0x16, 0xC1, 0x72, 0x51, 0xB2, 0x66, 0x45,
|
||||
0xDF, 0x4C, 0x2F, 0x87, 0xEB, 0xC0, 0x99, 0x2A,
|
||||
0xB1, 0x77, 0xFB, 0xA5, 0x1D, 0xB9, 0x2C, 0x2A
|
||||
};
|
||||
|
||||
NSData *alicePrivate = [NSData dataWithBytes:alicePrivateBytes length:sizeof(alicePrivateBytes)];
|
||||
|
||||
NSError *error;
|
||||
NSString *alicePublic = [decryption setPrivateKey:alicePrivate error:&error];
|
||||
XCTAssertNil(error);
|
||||
XCTAssertEqualObjects(alicePublic, @"hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo");
|
||||
|
||||
NSData *alicePrivateOut = decryption.privateKey;
|
||||
XCTAssertNil(error);
|
||||
XCTAssertEqualObjects(alicePrivateOut, alicePrivate);
|
||||
}
|
||||
|
||||
- (void)testEncryptAndDecrypt {
|
||||
|
||||
NSString *pubKey = [decryption generateKey:nil];
|
||||
NSLog(@"Ephemeral Key: %@", pubKey);
|
||||
XCTAssertNotNil(pubKey);
|
||||
|
||||
NSString *TEST_TEXT = @"têst1";
|
||||
NSError *error;
|
||||
[encryption setRecipientKey:pubKey];
|
||||
OLMPkMessage *message = [encryption encryptMessage:TEST_TEXT error:&error];
|
||||
NSLog(@"message: %@ %@ %@", message.ciphertext, message.mac, message.ephemeralKey);
|
||||
XCTAssertNil(error);
|
||||
XCTAssertNotNil(message);
|
||||
XCTAssertNotNil(message.ciphertext);
|
||||
XCTAssertNotNil(message.mac);
|
||||
XCTAssertNotNil(message.ephemeralKey);
|
||||
|
||||
NSString *decrypted = [decryption decryptMessage:message error:&error];
|
||||
XCTAssertNil(error);
|
||||
XCTAssertEqualObjects(decrypted, TEST_TEXT);
|
||||
|
||||
TEST_TEXT = @"hot beverage: ☕";
|
||||
[encryption setRecipientKey:pubKey];
|
||||
message = [encryption encryptMessage:TEST_TEXT error:&error];
|
||||
decrypted = [decryption decryptMessage:message error:&error];
|
||||
XCTAssertEqualObjects(decrypted, TEST_TEXT);
|
||||
}
|
||||
|
||||
- (void)testOLMPkDecryptionSerialization {
|
||||
NSString *TEST_TEXT = @"têst1";
|
||||
NSString *pubKey = [decryption generateKey:nil];
|
||||
[encryption setRecipientKey:pubKey];
|
||||
OLMPkMessage *encrypted = [encryption encryptMessage:TEST_TEXT error:nil];
|
||||
|
||||
|
||||
NSData *pickle = [NSKeyedArchiver archivedDataWithRootObject:decryption];
|
||||
decryption = nil;
|
||||
|
||||
OLMPkDecryption *newDecryption = [NSKeyedUnarchiver unarchiveObjectWithData:pickle];
|
||||
|
||||
NSError *error;
|
||||
NSString *decrypted = [newDecryption decryptMessage:encrypted error:&error];
|
||||
XCTAssertEqualObjects(decrypted, TEST_TEXT);
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in a new issue