mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-06-15 21:21:45 +00:00
pairing works!
This commit is contained in:
@@ -15,4 +15,13 @@
|
||||
+ (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
|
||||
|
||||
@@ -10,7 +10,135 @@
|
||||
#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;
|
||||
|
||||
- (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 (([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;
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
EVP_MD_CTX *mdctx = NULL;
|
||||
mdctx = EVP_MD_CTX_create();
|
||||
ret = EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey);
|
||||
ret = EVP_DigestSignUpdate(mdctx, [data bytes], [data length]);
|
||||
size_t slen;
|
||||
ret = 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 {
|
||||
@@ -34,6 +162,20 @@
|
||||
return [NSData dataWithContentsOfFile:keyFile];
|
||||
}
|
||||
|
||||
+ (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 {
|
||||
NSLog(@"Generating Certificate... ");
|
||||
CertKeyPair certKeyPair = generateCertKeyPair();
|
||||
|
||||
+14
-3
@@ -9,8 +9,19 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
||||
|
||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
|
||||
|
||||
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
||||
- (NSString*) generatePIN;
|
||||
- (NSData*) saltPIN:(NSString*)PIN;
|
||||
- (NSURL*) newPairRequest;
|
||||
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
||||
- (NSURLRequest*) newUnpairRequest;
|
||||
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge;
|
||||
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp;
|
||||
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret;
|
||||
- (NSURLRequest*) newPairChallenge;
|
||||
- (NSURLRequest*) newAppListRequest;
|
||||
- (NSURLRequest*) newServerInfoRequest;
|
||||
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
+139
-55
@@ -9,17 +9,70 @@
|
||||
#import "HttpManager.h"
|
||||
#import "CryptoManager.h"
|
||||
|
||||
#include <libxml2/libxml/xmlreader.h>
|
||||
#include <string.h>
|
||||
|
||||
@implementation HttpManager {
|
||||
NSString* _baseURL;
|
||||
NSString* _host;
|
||||
NSString* _uniqueId;
|
||||
NSString* _deviceName;
|
||||
NSData* _salt;
|
||||
NSData* _cert;
|
||||
NSMutableData* _respData;
|
||||
NSData* _requestResp;
|
||||
dispatch_semaphore_t _requestLock;
|
||||
}
|
||||
|
||||
static const NSString* PORT = @"47984";
|
||||
|
||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag {
|
||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], [xml length]);
|
||||
|
||||
if (docPtr == NULL) {
|
||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
||||
return NULL;
|
||||
}
|
||||
NSString* value;
|
||||
xmlNodePtr node;
|
||||
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
|
||||
|
||||
// Check root status_code
|
||||
if (![HttpManager verifyStatus: rootNode]) {
|
||||
//TODO: handle error
|
||||
}
|
||||
|
||||
// Skip the root node
|
||||
node = node->children;
|
||||
|
||||
while (node != NULL) {
|
||||
//NSLog(@"node: %s", node->name);
|
||||
if (!xmlStrcmp(node->name, (const xmlChar*)[tag UTF8String])) {
|
||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, node->xmlChildrenNode, 1);
|
||||
value = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||
xmlFree(nodeVal);
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
//NSLog(@"xmlValue: %@", value);
|
||||
xmlFree(rootNode);
|
||||
xmlFree(docPtr);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
+ (bool) verifyStatus:(xmlNodePtr)docRoot {
|
||||
xmlChar* statusStr = xmlGetProp(docRoot, (const xmlChar*)"status_code");
|
||||
NSLog(@"status: %s", statusStr);
|
||||
int status = [[NSString stringWithUTF8String:(const char*)statusStr] intValue];
|
||||
xmlFree(statusStr);
|
||||
return status == 200;
|
||||
}
|
||||
|
||||
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
|
||||
NSString* xmlString = [[[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:@"UTF-16" withString:@"UTF-8" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [xmlData length])];
|
||||
//NSLog(@"xmlString: %@", xmlString);
|
||||
return [NSData dataWithBytes:[xmlString UTF8String] length:[xmlString length]];
|
||||
}
|
||||
|
||||
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert {
|
||||
self = [super init];
|
||||
@@ -29,15 +82,72 @@ static const NSString* PORT = @"47984";
|
||||
_cert = cert;
|
||||
_baseURL = [[NSString stringWithFormat:@"https://%@:%@", host, PORT]
|
||||
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
_requestLock = dispatch_semaphore_create(0);
|
||||
_respData = [[NSMutableData alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURL*) newPairRequest {
|
||||
//NSLog(@"host: %@ \nport: %@ \nuniqueID: %@ \ndeviceName: %@ \nsalt: %@ \ncert: %@", _host, PORT, _uniqueId, _deviceName, salt, cert);
|
||||
NSString* urlString = [[NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@", _baseURL, _uniqueId, _deviceName, [self bytesToHex:_salt], [self bytesToHex:_cert]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSURL* url = [[NSURL alloc] initWithString:urlString];
|
||||
//NSLog(@"pair url: %@", url);
|
||||
return url;
|
||||
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request {
|
||||
NSLog(@"Making Request: %@", request);
|
||||
[_respData setLength:0];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[NSURLConnection connectionWithRequest:request delegate:self];
|
||||
});
|
||||
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
|
||||
return _requestResp;
|
||||
}
|
||||
|
||||
- (void) executeRequest:(NSURLRequest*)request {
|
||||
[NSURLConnection connectionWithRequest:request delegate:self];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) createRequestFromString:(NSString*) urlString {
|
||||
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
|
||||
return [NSURLRequest requestWithURL:url];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newPairRequest:(NSData*)salt {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
|
||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newUnpairRequest {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
|
||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
|
||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newPairChallenge {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest *)newAppListRequest {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSURLRequest *)newServerInfoRequest {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId];
|
||||
return [self createRequestFromString:urlString];
|
||||
}
|
||||
|
||||
- (NSString*) bytesToHex:(NSData*)data {
|
||||
@@ -49,50 +159,27 @@ static const NSString* PORT = @"47984";
|
||||
return hex;
|
||||
}
|
||||
|
||||
- (NSString*) generatePIN {
|
||||
NSString* PIN = [NSString stringWithFormat:@"%d%d%d%d",
|
||||
arc4random() % 10, arc4random() % 10,
|
||||
arc4random() % 10, arc4random() % 10];
|
||||
NSLog(@"PIN: %@", PIN);
|
||||
return PIN;
|
||||
}
|
||||
|
||||
- (NSData*) saltPIN:(NSString*)PIN {
|
||||
NSMutableData* saltedPIN = [[NSMutableData alloc] initWithCapacity:20];
|
||||
[saltedPIN appendData:[self randomBytes:16]];
|
||||
[saltedPIN appendBytes:[PIN UTF8String] length:4];
|
||||
|
||||
//NSLog(@"Salted PIN: %@", [saltedPIN description]);
|
||||
_salt = saltedPIN;
|
||||
return saltedPIN;
|
||||
}
|
||||
|
||||
- (NSData*) randomBytes:(NSInteger)length {
|
||||
char* bytes = malloc(length);
|
||||
arc4random_buf(bytes, length);
|
||||
NSData* randomData = [NSData dataWithBytes:bytes length:length];
|
||||
free(bytes);
|
||||
return randomData;
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSLog(@"Received response: %@", response);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
NSLog(@"Received data: %@", data);
|
||||
NSLog(@"Received data: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
||||
[_respData appendData:data];
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
_requestResp = [HttpManager fixXmlVersion:_respData];
|
||||
dispatch_semaphore_signal(_requestLock);
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
SecIdentityRef identity = [self getClientCertificate]; // Go get a SecIdentityRef
|
||||
CFArrayRef certs = [self getCertificate:identity]; // Get an array of certificates
|
||||
// Convert the CFArrayRef to a NSArray
|
||||
NSArray *myArray = (__bridge NSArray *)certs;
|
||||
NSArray *certArray = (__bridge NSArray *)certs;
|
||||
|
||||
// Create the NSURLCredential
|
||||
NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:myArray persistence:NSURLCredentialPersistencePermanent];
|
||||
NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
|
||||
|
||||
// Send
|
||||
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
|
||||
}
|
||||
|
||||
@@ -103,35 +190,32 @@ static const NSString* PORT = @"47984";
|
||||
SecIdentityCopyCertificate(identity, &certificate);
|
||||
SecCertificateRef certs[1] = { certificate };
|
||||
|
||||
CFArrayRef array = CFArrayCreate(NULL, (const void **) certs, 1, NULL);
|
||||
CFArrayRef certArray = CFArrayCreate(NULL, (const void **) certs, 1, NULL);
|
||||
|
||||
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
|
||||
SecTrustRef myTrust;
|
||||
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
|
||||
SecTrustRef trustRef;
|
||||
|
||||
OSStatus status = SecTrustCreateWithCertificates(array, myPolicy, &myTrust);
|
||||
if (status == noErr) {
|
||||
NSLog(@"No Err creating certificate");
|
||||
} else {
|
||||
NSLog(@"Possible Err Creating certificate");
|
||||
OSStatus status = SecTrustCreateWithCertificates(certArray, policyRef, &trustRef);
|
||||
if (status != noErr) {
|
||||
NSLog(@"Error Creating certificate");
|
||||
}
|
||||
return array;
|
||||
return certArray;
|
||||
}
|
||||
|
||||
// Returns the identity
|
||||
- (SecIdentityRef)getClientCertificate {
|
||||
SecIdentityRef identityApp = nil;
|
||||
NSData *PKCS12Data = [CryptoManager readP12FromFile];
|
||||
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
|
||||
|
||||
CFStringRef password = CFSTR("limelight"); // no password
|
||||
const void *keys[] = { kSecImportExportPassphrase };//kSecImportExportPassphrase };
|
||||
CFDataRef p12Data = (__bridge CFDataRef)[CryptoManager readP12FromFile];
|
||||
|
||||
CFStringRef password = CFSTR("limelight");
|
||||
const void *keys[] = { kSecImportExportPassphrase };
|
||||
const void *values[] = { password };
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
|
||||
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
|
||||
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
|
||||
OSStatus securityError = SecPKCS12Import(p12Data, options, &items);
|
||||
|
||||
if (securityError == errSecSuccess) {
|
||||
NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
|
||||
//NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
|
||||
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
|
||||
identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
|
||||
} else {
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#import "Computer.h"
|
||||
#import "CryptoManager.h"
|
||||
#import "HttpManager.h"
|
||||
#import "PairManager.h"
|
||||
|
||||
@implementation MainFrameViewController
|
||||
NSString* hostAddr = @"cement-truck.case.edu";
|
||||
NSString* hostAddr;
|
||||
MDNSManager* mDNSManager;
|
||||
|
||||
+ (const char*)getHostAddr
|
||||
@@ -24,7 +25,15 @@ MDNSManager* mDNSManager;
|
||||
- (void)PairButton:(UIButton *)sender
|
||||
{
|
||||
NSLog(@"Pair Button Pressed!");
|
||||
[ConnectionHandler pairWithHost:hostAddr];
|
||||
[CryptoManager generateKeyPairUsingSSl];
|
||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
||||
NSData* cert = [CryptoManager readCertFromFile];
|
||||
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddr uniqueId:uniqueId deviceName:@"roth" cert:cert];
|
||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:cert];
|
||||
|
||||
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
|
||||
[opQueue addOperation:pMan];
|
||||
}
|
||||
|
||||
- (void)StreamButton:(UIButton *)sender
|
||||
@@ -50,9 +59,9 @@ MDNSManager* mDNSManager;
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
|
||||
{
|
||||
//self.hostPickerVals = [mDNSManager getFoundHosts];
|
||||
self.hostPickerVals = [mDNSManager getFoundHosts];
|
||||
|
||||
//[self.HostPicker reloadAllComponents];
|
||||
[self.HostPicker reloadAllComponents];
|
||||
if (pickerView == self.HostPicker) {
|
||||
hostAddr = ((Computer*)([self.hostPickerVals objectAtIndex:[self.HostPicker selectedRowInComponent:0]])).hostName;
|
||||
}
|
||||
@@ -85,21 +94,9 @@ MDNSManager* mDNSManager;
|
||||
self.streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
||||
self.hostPickerVals = [[NSArray alloc] init];
|
||||
|
||||
|
||||
mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
||||
//[mDNSManager searchForHosts];
|
||||
|
||||
[CryptoManager generateKeyPairUsingSSl];
|
||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
||||
NSData* cert = [CryptoManager readCertFromFile];
|
||||
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddr uniqueId:uniqueId deviceName:@"roth" cert:cert];
|
||||
NSString* PIN = [hMan generatePIN];
|
||||
NSData* saltedPIN = [hMan saltPIN:PIN];
|
||||
NSLog(@"PIN: %@, saltedPIN: %@", PIN, saltedPIN);
|
||||
NSURL* pairUrl = [hMan newPairRequest];
|
||||
NSURLRequest* pairRequest = [[NSURLRequest alloc] initWithURL:pairUrl];
|
||||
// NSLog(@"making pair request: %@", [pairRequest description]);
|
||||
[NSURLConnection connectionWithRequest:pairRequest delegate:hMan];
|
||||
[mDNSManager searchForHosts];
|
||||
}
|
||||
|
||||
- (void)updateHosts:(NSArray *)hosts {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// PairManager.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/19/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HttpManager.h"
|
||||
|
||||
@interface PairManager : NSOperation
|
||||
- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert;
|
||||
- (NSString*) generatePIN;
|
||||
- (NSData*) saltPIN:(NSString*)PIN;
|
||||
- (void) initiatePair;
|
||||
@end
|
||||
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// PairManager.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/19/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "PairManager.h"
|
||||
#import "CryptoManager.h"
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
@implementation PairManager {
|
||||
HttpManager* _httpManager;
|
||||
NSData* _cert;
|
||||
}
|
||||
|
||||
- (id) initWithManager:(HttpManager*)httpManager andCert:(NSData*)cert {
|
||||
self = [super init];
|
||||
_httpManager = httpManager;
|
||||
_cert = cert;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) main {
|
||||
[self initiatePair];
|
||||
}
|
||||
|
||||
- (void) initiatePair {
|
||||
NSString* PIN = [self generatePIN];
|
||||
NSData* salt = [self saltPIN:PIN];
|
||||
NSLog(@"PIN: %@, saltedPIN: %@", PIN, salt);
|
||||
|
||||
NSData* pairResp = [_httpManager executeRequestSynchronously:[_httpManager newPairRequest:salt]];
|
||||
if ([[HttpManager getStringFromXML:pairResp tag:@"paired"] intValue] != 1) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString* plainCert = [HttpManager getStringFromXML:pairResp tag:@"plaincert"];
|
||||
|
||||
CryptoManager* cryptoMan = [[CryptoManager alloc] init];
|
||||
NSData* aesKey = [cryptoMan createAESKeyFromSalt:salt];
|
||||
|
||||
NSData* randomChallenge = [self randomBytes:16];
|
||||
NSData* encryptedChallenge = [cryptoMan aesEncrypt:randomChallenge withKey:aesKey];
|
||||
|
||||
NSData* challengeResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRequest:encryptedChallenge]];
|
||||
if ([[HttpManager getStringFromXML:challengeResp tag:@"paired"] intValue] != 1) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSData* encServerChallengeResp = [self hexToBytes:[HttpManager getStringFromXML:challengeResp tag:@"challengeresponse"]];
|
||||
NSData* decServerChallengeResp = [cryptoMan aesDecrypt:encServerChallengeResp withKey:aesKey];
|
||||
|
||||
NSData* serverResponse = [decServerChallengeResp subdataWithRange:NSMakeRange(0, 20)];
|
||||
NSData* serverChallenge = [decServerChallengeResp subdataWithRange:NSMakeRange(20, 16)];
|
||||
|
||||
NSData* clientSecret = [self randomBytes:16];
|
||||
NSData* challengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:serverChallenge with:[CryptoManager getSignatureFromCert:_cert]] with:clientSecret]];
|
||||
NSData* challengeRespEncrypted = [cryptoMan aesEncrypt:challengeRespHash withKey:aesKey];
|
||||
|
||||
NSData* secretResp = [_httpManager executeRequestSynchronously:[_httpManager newChallengeRespRequest:challengeRespEncrypted]];
|
||||
if ([[HttpManager getStringFromXML:secretResp tag:@"paired"] intValue] != 1) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSData* serverSecretResp = [self hexToBytes:[HttpManager getStringFromXML:secretResp tag:@"pairingsecret"]];
|
||||
NSData* serverSecret = [serverSecretResp subdataWithRange:NSMakeRange(0, 16)];
|
||||
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
|
||||
|
||||
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[self hexToBytes:plainCert]]) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[self hexToBytes:plainCert]]] with:serverSecret]];
|
||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSData* clientPairingSecret = [self concatData:clientSecret with:[cryptoMan signData:clientSecret withKey:[CryptoManager readKeyFromFile]]];
|
||||
NSData* clientSecretResp = [_httpManager executeRequestSynchronously:[_httpManager newClientSecretRespRequest:[self bytesToHex:clientPairingSecret]]];
|
||||
if (![[HttpManager getStringFromXML:clientSecretResp tag:@"paired"] isEqual:@"1"]) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
|
||||
NSData* clientPairChallenge = [_httpManager executeRequestSynchronously:[_httpManager newPairChallenge]];
|
||||
if (![[HttpManager getStringFromXML:clientPairChallenge tag:@"paired"] isEqual:@"1"]) {
|
||||
[_httpManager executeRequestSynchronously:[_httpManager newUnpairRequest]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSData*) concatData:(NSData*)data with:(NSData*)moreData {
|
||||
NSMutableData* concatData = [[NSMutableData alloc] initWithData:data];
|
||||
[concatData appendData:moreData];
|
||||
return concatData;
|
||||
}
|
||||
|
||||
- (NSString*) generatePIN {
|
||||
NSString* PIN = [NSString stringWithFormat:@"%d%d%d%d",
|
||||
arc4random() % 10, arc4random() % 10,
|
||||
arc4random() % 10, arc4random() % 10];
|
||||
NSLog(@"PIN: %@", PIN);
|
||||
return PIN;
|
||||
}
|
||||
|
||||
- (NSData*) saltPIN:(NSString*)PIN {
|
||||
NSMutableData* saltedPIN = [[NSMutableData alloc] initWithCapacity:20];
|
||||
[saltedPIN appendData:[self randomBytes:16]];
|
||||
[saltedPIN appendBytes:[PIN UTF8String] length:4];
|
||||
|
||||
//NSLog(@"Salted PIN: %@", [saltedPIN description]);
|
||||
return saltedPIN;
|
||||
}
|
||||
|
||||
- (NSData*) randomBytes:(NSInteger)length {
|
||||
char* bytes = malloc(length);
|
||||
arc4random_buf(bytes, length);
|
||||
NSData* randomData = [NSData dataWithBytes:bytes length:length];
|
||||
free(bytes);
|
||||
return randomData;
|
||||
}
|
||||
|
||||
- (NSData*) hexToBytes:(NSString*) hex {
|
||||
int len = [hex length];
|
||||
NSMutableData* data = [NSMutableData dataWithCapacity:len / 2];
|
||||
char byteChars[3] = {'\0','\0','\0'};
|
||||
unsigned long wholeByte;
|
||||
|
||||
const char *chars = [hex UTF8String];
|
||||
int i = 0;
|
||||
while (i < len) {
|
||||
byteChars[0] = chars[i++];
|
||||
byteChars[1] = chars[i++];
|
||||
wholeByte = strtoul(byteChars, NULL, 16);
|
||||
[data appendBytes:&wholeByte length:1];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSString*) bytesToHex:(NSData*)data {
|
||||
const unsigned char* bytes = [data bytes];
|
||||
NSMutableString *hex = [[NSMutableString alloc] init];
|
||||
for (int i = 0; i < [data length]; i++) {
|
||||
[hex appendFormat:@"%02X" , bytes[i]];
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user