mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2025-07-22 12:13:35 +00:00
237 lines
8.0 KiB
Objective-C
237 lines
8.0 KiB
Objective-C
//
|
|
// CryptoManager.m
|
|
// Limelight
|
|
//
|
|
// Created by Diego Waxemberg on 10/14/14.
|
|
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
|
//
|
|
|
|
#import "CryptoManager.h"
|
|
#import "mkcert.h"
|
|
#import <AdSupport/ASIdentifierManager.h>
|
|
|
|
#include <openssl/aes.h>
|
|
#include <openssl/sha.h>
|
|
#include <openssl/x509.h>
|
|
#include <openssl/pem.h>
|
|
#include <openssl/evp.h>
|
|
|
|
@implementation CryptoManager
|
|
static const int SHA1_DIGEST_LENGTH = 20;
|
|
static NSData* key = nil;
|
|
static NSData* cert = nil;
|
|
static NSData* p12 = nil;
|
|
|
|
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN {
|
|
return [[self SHA1HashData:saltedPIN] subdataWithRange:NSMakeRange(0, 16)];
|
|
}
|
|
|
|
- (NSData*) SHA1HashData:(NSData*)data {
|
|
unsigned char sha1[SHA1_DIGEST_LENGTH];
|
|
SHA1([data bytes], [data length], sha1);
|
|
NSData* bytes = [NSData dataWithBytes:sha1 length:20];
|
|
return bytes;
|
|
}
|
|
|
|
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key {
|
|
AES_KEY aesKey;
|
|
AES_set_encrypt_key([key bytes], 128, &aesKey);
|
|
int size = [self getEncryptSize:data];
|
|
unsigned char* buffer = malloc(size);
|
|
unsigned char* blockRoundedBuffer = calloc(1, size);
|
|
memcpy(blockRoundedBuffer, [data bytes], [data length]);
|
|
|
|
// AES_encrypt only encrypts the first 16 bytes so iterate the entire buffer
|
|
int blockOffset = 0;
|
|
while (blockOffset < size) {
|
|
AES_encrypt(blockRoundedBuffer + blockOffset, buffer + blockOffset, &aesKey);
|
|
blockOffset += 16;
|
|
}
|
|
|
|
NSData* encryptedData = [NSData dataWithBytes:buffer length:size];
|
|
free(buffer);
|
|
free(blockRoundedBuffer);
|
|
return encryptedData;
|
|
}
|
|
|
|
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key {
|
|
AES_KEY aesKey;
|
|
AES_set_decrypt_key([key bytes], 128, &aesKey);
|
|
unsigned char* buffer = malloc([data length]);
|
|
|
|
// AES_decrypt only decrypts the first 16 bytes so iterate the entire buffer
|
|
int blockOffset = 0;
|
|
while (blockOffset < [data length]) {
|
|
AES_decrypt([data bytes] + blockOffset, buffer + blockOffset, &aesKey);
|
|
blockOffset += 16;
|
|
}
|
|
|
|
NSData* decryptedData = [NSData dataWithBytes:buffer length:[data length]];
|
|
free(buffer);
|
|
return decryptedData;
|
|
}
|
|
|
|
- (int) getEncryptSize:(NSData*)data {
|
|
// the size is the length of the data ceiling to the nearest 16 bytes
|
|
return (((int)[data length] + 15) / 16) * 16;
|
|
}
|
|
|
|
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert {
|
|
const char* buffer = [cert bytes];
|
|
X509* x509;
|
|
BIO* bio = BIO_new(BIO_s_mem());
|
|
BIO_puts(bio, buffer);
|
|
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (!x509) {
|
|
fprintf(stderr, "unable to parse certificate in memory\n");
|
|
return NULL;
|
|
}
|
|
|
|
EVP_PKEY* pubKey = X509_get_pubkey(x509);
|
|
EVP_MD_CTX *mdctx = NULL;
|
|
mdctx = EVP_MD_CTX_create();
|
|
EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pubKey);
|
|
EVP_DigestVerifyUpdate(mdctx, [data bytes], [data length]);
|
|
int result = EVP_DigestVerifyFinal(mdctx, (unsigned char*)[signature bytes], [signature length]);
|
|
|
|
X509_free(x509);
|
|
EVP_PKEY_free(pubKey);
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
return result > 0;
|
|
}
|
|
|
|
- (NSData *)signData:(NSData *)data withKey:(NSData *)key {
|
|
const char* buffer = [key bytes];
|
|
BIO* bio = BIO_new(BIO_s_mem());
|
|
BIO_puts(bio, buffer);
|
|
|
|
EVP_PKEY* pkey;
|
|
pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
|
|
|
BIO_free(bio);
|
|
|
|
if (!pkey) {
|
|
fprintf(stderr, "unable to parse private key in memory\n");
|
|
return NULL;
|
|
}
|
|
|
|
EVP_MD_CTX *mdctx = NULL;
|
|
mdctx = EVP_MD_CTX_create();
|
|
EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey);
|
|
EVP_DigestSignUpdate(mdctx, [data bytes], [data length]);
|
|
size_t slen;
|
|
EVP_DigestSignFinal(mdctx, NULL, &slen);
|
|
unsigned char* signature = malloc(slen);
|
|
int result = EVP_DigestSignFinal(mdctx, signature, &slen);
|
|
|
|
EVP_PKEY_free(pkey);
|
|
EVP_MD_CTX_destroy(mdctx);
|
|
|
|
if (result <= 0) {
|
|
free(signature);
|
|
return NULL;
|
|
}
|
|
|
|
NSData* signedData = [NSData dataWithBytes:signature length:slen];
|
|
free(signature);
|
|
|
|
return signedData;
|
|
}
|
|
|
|
// TODO: these three methods are almost identical, fix the copy-pasta
|
|
+ (NSData*) readCertFromFile {
|
|
if (cert == nil) {
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString *documentsDirectory = [paths objectAtIndex:0];
|
|
NSString *certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
|
|
cert = [NSData dataWithContentsOfFile:certFile];
|
|
}
|
|
return cert;
|
|
}
|
|
|
|
+ (NSData*) readP12FromFile {
|
|
if (p12 == nil) {
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString *documentsDirectory = [paths objectAtIndex:0];
|
|
NSString *p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
|
|
p12 = [NSData dataWithContentsOfFile:p12File];
|
|
}
|
|
return p12;
|
|
}
|
|
|
|
+ (NSData*) readKeyFromFile {
|
|
if (key == nil) {
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString *documentsDirectory = [paths objectAtIndex:0];
|
|
NSString *keyFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
|
|
key = [NSData dataWithContentsOfFile:keyFile];
|
|
}
|
|
return key;
|
|
}
|
|
|
|
+ (bool) keyPairExists {
|
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString *documentsDirectory = [paths objectAtIndex:0];
|
|
NSString *keyFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
|
|
NSString *p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
|
|
NSString *certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
|
|
|
|
bool keyFileExists = [[NSFileManager defaultManager] fileExistsAtPath:keyFile];
|
|
bool p12FileExists = [[NSFileManager defaultManager] fileExistsAtPath:p12File];
|
|
bool certFileExists = [[NSFileManager defaultManager] fileExistsAtPath:certFile];
|
|
|
|
return keyFileExists && p12FileExists && certFileExists;
|
|
}
|
|
|
|
+ (NSData *)getSignatureFromCert:(NSData *)cert {
|
|
const char* buffer = [cert bytes];
|
|
X509* x509;
|
|
BIO* bio = BIO_new(BIO_s_mem());
|
|
BIO_puts(bio, buffer);
|
|
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
|
|
|
if (!x509) {
|
|
fprintf(stderr, "unable to parse certificate in memory\n");
|
|
return NULL;
|
|
}
|
|
return [NSData dataWithBytes:x509->signature->data length:x509->signature->length];
|
|
}
|
|
|
|
+ (void) generateKeyPairUsingSSl {
|
|
if (![CryptoManager keyPairExists]) {
|
|
|
|
NSLog(@"Generating Certificate... ");
|
|
CertKeyPair certKeyPair = generateCertKeyPair();
|
|
|
|
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
|
NSString* documentsDirectory = [paths objectAtIndex:0];
|
|
NSString* certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
|
|
NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
|
|
NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
|
|
|
|
//NSLog(@"Writing cert and key to: \n%@\n%@", certFile, keyPairFile);
|
|
saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair);
|
|
freeCertKeyPair(certKeyPair);
|
|
}
|
|
}
|
|
|
|
+ (NSString*) getUniqueID {
|
|
// generate a UUID
|
|
NSUUID* uuid = [ASIdentifierManager sharedManager].advertisingIdentifier;
|
|
NSString* idString = [NSString stringWithString:[uuid UUIDString]];
|
|
|
|
// we need a 16byte hex-string so we take the last 17 characters
|
|
// and remove the '-' to get a 16 character string
|
|
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
|
|
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
|
|
|
|
//NSLog(@"Unique ID: %@", uniqueId);
|
|
return [NSString stringWithString:uniqueId];
|
|
}
|
|
|
|
@end
|