talk-ios/VideoCalls/NCSettingsController.m

234 строки
6.8 KiB
Objective-C

//
// NCSettingsController.m
// VideoCalls
//
// Created by Ivan Sein on 26.06.17.
// Copyright © 2017 struktur AG. All rights reserved.
//
#import "NCSettingsController.h"
#import <openssl/rsa.h>
#import <openssl/pem.h>
#import <openssl/bio.h>
#import <openssl/bn.h>
#import <openssl/sha.h>
#import <openssl/err.h>
#import <CommonCrypto/CommonDigest.h>
#import "NCAPIController.h"
@interface NCSettingsController ()
{
UICKeyChainStore *_keychain;
}
@end
@implementation NCSettingsController
NSString * const kNCServerKey = @"ncServer";
NSString * const kNCUserKey = @"ncUser";
NSString * const kNCUserDisplayNameKey = @"ncUserDisplayName";
NSString * const kNCTokenKey = @"ncToken";
NSString * const kNCPushTokenKey = @"ncPushToken";
NSString * const kNCPushServer = @"https://push-notifications.nextcloud.com";
NSString * const kNCPNPublicKey = @"ncPNPublicKey";
NSString * const kNCPNPrivateKey = @"ncPNPrivateKey";
NSString * const kNCDeviceIdentifier = @"ncDeviceIdentifier";
NSString * const kNCDeviceSignature = @"ncDeviceSignature";
NSString * const kNCUserPublicKey = @"ncUserPublicKey";
+ (NCSettingsController *)sharedInstance
{
static dispatch_once_t once;
static NCSettingsController *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
_keychain = [UICKeyChainStore keyChainStoreWithService:@"com.nextcloud.Talk"
accessGroup:@"group.com.nextcloud.Talk"];
[self readValuesFromKeyChain];
}
return self;
}
#pragma mark - KeyChain
- (void)readValuesFromKeyChain
{
_ncServer = [_keychain stringForKey:kNCServerKey];
_ncUser = [_keychain stringForKey:kNCUserKey];
_ncUserDisplayName = [_keychain stringForKey:kNCUserDisplayNameKey];
_ncToken = [_keychain stringForKey:kNCTokenKey];
_ncPushToken = [_keychain stringForKey:kNCPushTokenKey];
_ncPNPublicKey = [_keychain dataForKey:kNCPNPublicKey];
_ncPNPrivateKey = [_keychain dataForKey:kNCPNPrivateKey];
_ncDeviceIdentifier = [_keychain stringForKey:kNCDeviceIdentifier];
_ncDeviceSignature = [_keychain stringForKey:kNCDeviceSignature];
_ncUserPublicKey = [_keychain stringForKey:kNCUserPublicKey];
}
- (void)cleanUserAndServerStoredValues
{
_ncServer = nil;
_ncUser = nil;
_ncUserDisplayName = nil;
_ncToken = nil;
_ncPNPublicKey = nil;
_ncPNPrivateKey = nil;
_ncUserPublicKey = nil;
_ncDeviceIdentifier = nil;
_ncDeviceSignature = nil;
[_keychain removeItemForKey:kNCServerKey];
[_keychain removeItemForKey:kNCUserKey];
[_keychain removeItemForKey:kNCUserDisplayNameKey];
[_keychain removeItemForKey:kNCTokenKey];
[_keychain removeItemForKey:kNCPNPublicKey];
[_keychain removeItemForKey:kNCPNPrivateKey];
[_keychain removeItemForKey:kNCDeviceIdentifier];
[_keychain removeItemForKey:kNCDeviceSignature];
[_keychain removeItemForKey:kNCUserPublicKey];
#warning TODO - Restore NCAPIController in a diferent way
[[NCAPIController sharedInstance] setAuthHeaderWithUser:NULL andToken:NULL];
}
#pragma mark - Push Notifications
- (BOOL)generatePushNotificationsKeyPair
{
EVP_PKEY *pkey;
NSError *keyError;
pkey = [self generateRSAKey:&keyError];
if (keyError) {
return NO;
}
// Extract publicKey, privateKey
int len;
char *keyBytes;
// PublicKey
BIO *publicKeyBIO = BIO_new(BIO_s_mem());
PEM_write_bio_PUBKEY(publicKeyBIO, pkey);
len = BIO_pending(publicKeyBIO);
keyBytes = malloc(len);
BIO_read(publicKeyBIO, keyBytes, len);
_ncPNPublicKey = [NSData dataWithBytes:keyBytes length:len];
[_keychain setData:_ncPNPublicKey forKey:kNCPNPublicKey];
NSLog(@"Push Notifications Key Pair generated: \n%@", [[NSString alloc] initWithData:_ncPNPublicKey encoding:NSUTF8StringEncoding]);
// PrivateKey
BIO *privateKeyBIO = BIO_new(BIO_s_mem());
PEM_write_bio_PKCS8PrivateKey(privateKeyBIO, pkey, NULL, NULL, 0, NULL, NULL);
len = BIO_pending(privateKeyBIO);
keyBytes = malloc(len);
BIO_read(privateKeyBIO, keyBytes, len);
_ncPNPrivateKey = [NSData dataWithBytes:keyBytes length:len];
[_keychain setData:_ncPNPrivateKey forKey:kNCPNPrivateKey];
EVP_PKEY_free(pkey);
return YES;
}
- (EVP_PKEY *)generateRSAKey:(NSError **)error
{
EVP_PKEY *pkey = EVP_PKEY_new();
if (!pkey) {
return NULL;
}
BIGNUM *bigNumber = BN_new();
int exponent = RSA_F4;
RSA *rsa = RSA_new();
if (BN_set_word(bigNumber, exponent) < 0) {
goto cleanup;
}
if (RSA_generate_key_ex(rsa, 2048, bigNumber, NULL) < 0) {
goto cleanup;
}
if (!EVP_PKEY_set1_RSA(pkey, rsa)) {
goto cleanup;
}
cleanup:
RSA_free(rsa);
BN_free(bigNumber);
return pkey;
}
- (NSString *)decryptPushNotification:(NSString *)message withDevicePrivateKey:(NSData *)privateKey
{
NSString *privateKeyString = [[NSString alloc] initWithData:privateKey encoding:NSUTF8StringEncoding];
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:message options:0];
char *privKey = (char *)[privateKeyString UTF8String];
// Get Device Private Key from PEM
BIO *bio = BIO_new(BIO_s_mem());
BIO_write(bio, privKey, (int)strlen(privKey));
EVP_PKEY* pkey = 0;
PEM_read_bio_PrivateKey(bio, &pkey, 0, 0);
RSA* rsa = EVP_PKEY_get1_RSA(pkey);
// Decrypt the message
unsigned char *decrypted = (unsigned char *) malloc(4096);
int decrypted_length = RSA_private_decrypt((int)[decodedData length], [decodedData bytes], decrypted, rsa, RSA_PKCS1_PADDING);
if(decrypted_length == -1) {
char buffer[500];
ERR_error_string(ERR_get_error(), buffer);
NSLog(@"%@",[NSString stringWithUTF8String:buffer]);
return nil;
}
NSString *decryptString = [[NSString alloc] initWithBytes:decrypted length:decrypted_length encoding:NSUTF8StringEncoding];
if (decrypted)
free(decrypted);
free(bio);
free(rsa);
return decryptString;
}
- (NSString *)pushTokenSHA512
{
return [self createSHA512:_ncPushToken];
}
#pragma mark - Utils
- (NSString *)createSHA512:(NSString *)string
{
const char *cstr = [string cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:string.length];
uint8_t digest[CC_SHA512_DIGEST_LENGTH];
CC_SHA512(data.bytes, (unsigned int)data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA512_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA512_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x", digest[i]];
return output;
}
@end