mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-17 22:23:31 +00:00
refactored project directories
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// CryptoManager.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/14/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CryptoManager : NSObject
|
||||
|
||||
+ (void) generateKeyPairUsingSSl;
|
||||
+ (NSString*) getUniqueID;
|
||||
+ (NSData*) readCertFromFile;
|
||||
+ (NSData*) readKeyFromFile;
|
||||
+ (NSData*) readP12FromFile;
|
||||
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
||||
|
||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN;
|
||||
- (NSData*) SHA1HashData:(NSData*)data;
|
||||
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key;
|
||||
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key;
|
||||
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert;
|
||||
- (NSData*) signData:(NSData*)data withKey:(NSData*)key;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,236 @@
|
||||
//
|
||||
// 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
|
||||
@@ -0,0 +1,169 @@
|
||||
|
||||
#include "mkcert.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
static const int NUM_BITS = 2048;
|
||||
static const int SERIAL = 0;
|
||||
static const int NUM_YEARS = 10;
|
||||
|
||||
int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years);
|
||||
int add_ext(X509 *cert, int nid, char *value);
|
||||
|
||||
struct CertKeyPair generateCertKeyPair() {
|
||||
BIO *bio_err;
|
||||
X509 *x509 = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
PKCS12 *p12 = NULL;
|
||||
|
||||
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
|
||||
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
|
||||
|
||||
SSLeay_add_all_algorithms();
|
||||
ERR_load_crypto_strings();
|
||||
|
||||
mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS);
|
||||
|
||||
p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
|
||||
if (p12 == NULL) {
|
||||
printf("Error generating a valid PKCS12 certificate.\n");
|
||||
}
|
||||
|
||||
// Debug Print statements
|
||||
//RSA_print_fp(stdout, pkey->pkey.rsa, 0);
|
||||
//X509_print_fp(stdout, x509);
|
||||
//PEM_write_PUBKEY(stdout, pkey);
|
||||
//PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL);
|
||||
//PEM_write_X509(stdout, x509);
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_cleanup();
|
||||
#endif
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
|
||||
CRYPTO_mem_leaks(bio_err);
|
||||
BIO_free(bio_err);
|
||||
|
||||
return (CertKeyPair){x509, pkey, p12};
|
||||
}
|
||||
|
||||
void freeCertKeyPair(struct CertKeyPair certKeyPair) {
|
||||
X509_free(certKeyPair.x509);
|
||||
EVP_PKEY_free(certKeyPair.pkey);
|
||||
PKCS12_free(certKeyPair.p12);
|
||||
}
|
||||
|
||||
void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair) {
|
||||
FILE* certFilePtr = fopen(certFile, "w");
|
||||
FILE* keyPairFilePtr = fopen(keyPairFile, "w");
|
||||
FILE* p12FilePtr = fopen(p12File, "wb");
|
||||
|
||||
//TODO: error check
|
||||
PEM_write_PrivateKey(keyPairFilePtr, certKeyPair.pkey, NULL, NULL, 0, NULL, NULL);
|
||||
PEM_write_X509(certFilePtr, certKeyPair.x509);
|
||||
i2d_PKCS12_fp(p12FilePtr, certKeyPair.p12);
|
||||
|
||||
fclose(p12FilePtr);
|
||||
fclose(certFilePtr);
|
||||
fclose(keyPairFilePtr);
|
||||
}
|
||||
|
||||
int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
||||
X509 *x;
|
||||
EVP_PKEY *pk;
|
||||
RSA *rsa;
|
||||
X509_NAME *name = NULL;
|
||||
|
||||
if (*pkeyp == NULL) {
|
||||
if ((pk=EVP_PKEY_new()) == NULL) {
|
||||
abort();
|
||||
return(0);
|
||||
}
|
||||
} else {
|
||||
pk = *pkeyp;
|
||||
}
|
||||
|
||||
if (*x509p == NULL) {
|
||||
if ((x = X509_new()) == NULL) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
x = *x509p;
|
||||
}
|
||||
|
||||
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
||||
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
||||
abort();
|
||||
goto err;
|
||||
}
|
||||
|
||||
X509_set_version(x, 2);
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
|
||||
X509_gmtime_adj(X509_get_notBefore(x), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*365*years);
|
||||
X509_set_pubkey(x, pk);
|
||||
|
||||
name = X509_get_subject_name(x);
|
||||
|
||||
/* This function creates and adds the entry, working out the
|
||||
* correct string type and performing checks on its length.
|
||||
*/
|
||||
X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char*)"NVIDIA GameStream Client", -1, -1, 0);
|
||||
|
||||
/* Its self signed so set the issuer name to be the same as the
|
||||
* subject.
|
||||
*/
|
||||
X509_set_issuer_name(x, name);
|
||||
|
||||
/* Add various extensions: standard extensions */
|
||||
add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
|
||||
add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
|
||||
|
||||
add_ext(x, NID_subject_key_identifier, "hash");
|
||||
|
||||
if (!X509_sign(x, pk, EVP_sha1())) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
*x509p = x;
|
||||
*pkeyp = pk;
|
||||
|
||||
return(1);
|
||||
err:
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Add extension using V3 code: we can set the config file as NULL
|
||||
* because we wont reference any other sections.
|
||||
*/
|
||||
|
||||
int add_ext(X509 *cert, int nid, char *value)
|
||||
{
|
||||
X509_EXTENSION *ex;
|
||||
X509V3_CTX ctx;
|
||||
/* This sets the 'context' of the extensions. */
|
||||
/* No configuration database */
|
||||
X509V3_set_ctx_nodb(&ctx);
|
||||
/* Issuer and subject certs: both the target since it is self signed,
|
||||
* no request and no CRL
|
||||
*/
|
||||
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
|
||||
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
|
||||
if (!ex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
X509_add_ext(cert, ex, -1);
|
||||
X509_EXTENSION_free(ex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// mkcert.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/16/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Limelight_mkcert_h
|
||||
#define Limelight_mkcert_h
|
||||
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
typedef struct CertKeyPair {
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
PKCS12 *p12;
|
||||
} CertKeyPair;
|
||||
|
||||
struct CertKeyPair generateCertKeyPair();
|
||||
void freeCertKeyPair(CertKeyPair);
|
||||
void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user