Skip to content

Instantly share code, notes, and snippets.

@aleclaws
Last active September 1, 2021 05:32
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save aleclaws/e1eb680081f05dfa6bb5b70d89bbd69c to your computer and use it in GitHub Desktop.
Save aleclaws/e1eb680081f05dfa6bb5b70d89bbd69c to your computer and use it in GitHub Desktop.
SecKeyRef to NSData
// 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