Last active
September 1, 2021 05:32
-
-
Save aleclaws/e1eb680081f05dfa6bb5b70d89bbd69c to your computer and use it in GitHub Desktop.
SecKeyRef to NSData
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// HELPER QUERIES | |
void queryValueToData(NSMutableDictionary *query, void * value) { | |
query[(__bridge id)kSecValueRef] = (__bridge id)value ; | |
query[(__bridge id)kSecReturnData] = @YES ; | |
} | |
void queryDataToValue(NSMutableDictionary *query, id data) { | |
query[(__bridge id)kSecValueData] = data ; | |
query[(__bridge id)kSecReturnRef] = @YES ; | |
} | |
NSMutableDictionary * rsa2048KeyQuery(NSData* tag) { | |
NSMutableDictionary * rsaQuery = [[NSMutableDictionary alloc] init]; | |
rsaQuery[(__bridge id)kSecClass] = (__bridge id)kSecClassKey; | |
rsaQuery[(__bridge id)kSecAttrKeyType] = (__bridge id)kSecAttrKeyTypeRSA ; | |
rsaQuery[(__bridge id)kSecAttrApplicationTag] = tag ; | |
rsaQuery[(__bridge id)kSecAttrKeySizeInBits] = @(RSAKeySize2048); | |
return rsaQuery; | |
} | |
OSStatus queryAddAndRemove(NSMutableDictionary * query, CFTypeRef * ref) { | |
OSStatus sanityCheck; | |
sanityCheck = SecItemAdd((__bridge CFDictionaryRef) query, ref); | |
if(sanityCheck == errSecDuplicateItem) { | |
// if it was already there, need to delete before we add | |
(void) SecItemDelete((__bridge CFDictionaryRef) query); | |
sanityCheck = SecItemAdd((__bridge CFDictionaryRef) query, ref); | |
} | |
// delete from Keychain | |
(void) SecItemDelete((__bridge CFDictionaryRef) query); | |
return sanityCheck; | |
} | |
// CONVERT BETWEEN SECKEYREF AND NSDATA | |
#define kPublicKeyTag "com.apple.sample.publickey" | |
static const uint8_t kFromKeyIdentifier[] = kPublicKeyTag; | |
NSData * dataFromKey(SecKeyRef givenKey) { | |
// http://stackoverflow.com/questions/16748993/ios-seckeyref-to-nsdata | |
NSData *publicTag = [[NSData alloc] initWithBytes:kFromKeyIdentifier | |
length:sizeof(kFromKeyIdentifier)]; | |
// BUILD query | |
NSMutableDictionary * queryPublicKey = rsa2048KeyQuery(publicTag); | |
queryValueToData(queryPublicKey, givenKey); | |
// MAKE query | |
CFDataRef result; | |
OSStatus sanityCheck = noErr; | |
sanityCheck = queryAddAndRemove(queryPublicKey, (CFTypeRef *)&result); | |
// SETUP result | |
NSData * publicKeyBits = nil; | |
if (sanityCheck == errSecSuccess) { | |
publicKeyBits = CFBridgingRelease(result); | |
} | |
return publicKeyBits; | |
} | |
SecKeyRef keyFromData(NSData* data, CFTypeRef keyclass) { | |
NSData *tag = [[NSData alloc] initWithBytes:kToKeyIdentifier | |
length:sizeof kToKeyIdentifier]; | |
// BUILD query | |
NSMutableDictionary * queryPublicKey = rsa2048KeyQuery(tag); | |
queryPublicKey[(__bridge id)kSecAttrKeyClass] = (__bridge id)keyclass ; | |
queryDataToValue(queryPublicKey, data); | |
// MAKE query | |
SecKeyRef keyRef = nil; | |
(void) queryAddAndRemove(queryPublicKey, (CFTypeRef *)&keyRef); | |
return keyRef; | |
} | |
// USE DER KEY DATA | |
int derEncodingGetSizeFrom(NSData* buf, int* iterator) | |
{ | |
const uint8_t* data = [buf bytes]; | |
int ret = 0; | |
// parse TLV len | |
int num_bytes = 1; | |
int itr = *iterator; | |
if (data[itr] > 0x80) { | |
num_bytes = data[itr] - 0x80; | |
itr++; | |
} | |
for (int i = 0 ; i < num_bytes; i++) { ret = (ret * 0x100) + data[itr + i]; } | |
*iterator = itr + num_bytes; | |
return ret; | |
} | |
int derSkipTagGetLength(NSData * der, int *iterator) { | |
(*iterator)++; // skip T1 | |
return derEncodingGetSizeFrom(der, iterator); // skip L1 | |
} | |
void derSkipNextTLV(NSData * der, int * iterator) { | |
int size = derSkipTagGetLength(der, iterator); // get + skip L | |
(*iterator) += size; // skip Value | |
} | |
const void *publicKeyExponent(struct id_storage *sto) { | |
if(sto == NULL || sto->publicKey == NULL) { | |
return NULL; | |
} | |
NSData* pubkey = dataFromKey(sto->publicKey); | |
if (pubkey == NULL) return NULL; | |
int iterator = 0; | |
/* | |
Public Key Data Format | |
T1,L1,V1[MODULUS_TAG,L2,V2,EXPONENT_TAG,L3,V3] | |
*/ | |
(void)derSkipTagGetLength(pubkey, &iterator); // skip L1 | |
derSkipNextTLV(pubkey, &iterator); | |
int exp_size = derSkipTagGetLength(pubkey, &iterator); // get + skip L2 | |
NSRange expRange = NSMakeRange(iterator, exp_size); | |
NSData * expData = [pubkey subdataWithRange:expRange]; // get V2 | |
return CFBridgingRetain(expData); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment