pairing works!

This commit is contained in:
Diego Waxemberg
2014-10-20 02:59:16 -04:00
parent 13f39e30f6
commit b8d256b73d
8 changed files with 500 additions and 354 deletions
+9
View File
@@ -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
+142
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+15 -18
View File
@@ -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 {
+17
View File
@@ -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
+158
View File
@@ -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