1

我一直在试图让两部 iPhone 交换公钥(它们都是在设备上生成的)。密钥生成正常,我已经测试过我可以使用它们来加密数据等。现在我的目标是使用 XMPP 消息交换密钥,因此我提取我的密钥并对它们进行 base64 编码以进行交换。交换了两个密钥,收到它们后,我尝试使用以下功能将它们保存在钥匙串中:

- (BOOL)storePublicKeyForContact:(WIMContactDetails *)contact publicKey:(NSString *)publicKey {

OSStatus sanityCheck = noErr;
NSString *contactTagString = contact.buddyFirstName;
contactTagString = [contactTagString stringByAppendingString:contact.buddyFacebookID];
NSLog(@"This is my public key identifier %@", contactTagString);
NSData *contactPublicTag = [NSData dataWithBytes:[contactTagString UTF8String] length:[contact.buddyPublicKeyIdentifier length]];

NSData *publicKeyBits = [NSData dataFromBase64String:publicKey];


//First deleting any existing keys
NSMutableDictionary *thePublicKey = [[NSMutableDictionary alloc] init];
[thePublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[thePublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[thePublicKey setObject:contactPublicTag forKey:(__bridge id)kSecAttrApplicationTag];
SecItemDelete((CFDictionaryRef)CFBridgingRetain(thePublicKey));



//adding a persistent version of the contact's publickey


[thePublicKey setObject:publicKeyBits forKey:(__bridge id)kSecValueData];
[thePublicKey setObject:(__bridge id)kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass];
[thePublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrCanEncrypt];
[thePublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnPersistentRef];
CFTypeRef persistKey = nil;
sanityCheck = SecItemAdd((CFDictionaryRef) CFBridgingRetain(thePublicKey), (CFTypeRef *)&persistKey);

if (persistKey == nil || ((sanityCheck != noErr) && (sanityCheck != errSecDuplicateItem))) {
    NSLog(@"Error storing key for contact %@", contact.buddyFacebookFullName);
    NSLog(@"Error Code is %ld", sanityCheck);
    return (FALSE);
}

//Now to get the keyReference
SecKeyRef  keyRef = nil;
[thePublicKey removeObjectForKey:(__bridge id)kSecValueData];
[thePublicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef];
[thePublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
[thePublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
sanityCheck = SecItemCopyMatching((CFDictionaryRef)CFBridgingRetain(thePublicKey), (CFTypeRef *)&keyRef);
if (keyRef == nil) {
    NSLog(@"Stored key for contact %@", contact.buddyFacebookFullName);
    NSLog(@"Error: Could not retrieve stored key!");
}
[contact setBuddyPublicKeyRef:keyRef];
if ([contact getBuddyPublicKeyRef] != nil) {
    NSLog(@"Stored key for contact %@ successfully!!!", contact.buddyFacebookFullName);
}
return(TRUE);
}

现在,直到我使用 PersistentRef 添加密钥时,PersistRef 不为零,当我修改查询以使用 SecItemCopyMatching 获取 SecKeyRef 时,结果为 nil。起初,我认为这是格式错误的问题,但由于我提取了 keyBits(使用 Apple 文档中 Security Excersice 中的函数)并且我执行的唯一更改是使用 NSData+base64 .h 库对它们进行编码以进行交换,然后在尝试添加之前对其进行解码。

为了进一步参考这里我用来提取密钥的方法

- (NSString *)getMyPublicKey {
OSStatus sanityCheck = noErr;

NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

// Set the public key query dictionary.
[queryPublicKey setObject:(id)CFBridgingRelease(kSecClassKey) forKey:(id)CFBridgingRelease(kSecClass)];
[queryPublicKey setObject:publicTag forKey:(id)CFBridgingRelease(kSecAttrApplicationTag)];
[queryPublicKey setObject:(id)CFBridgingRelease(kSecAttrKeyTypeRSA) forKey:(id)CFBridgingRelease(kSecAttrKeyType)];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)CFBridgingRelease(kSecReturnData)];

CFDataRef publicKeyBitsCF;
// Get the key bits.
sanityCheck = SecItemCopyMatching((CFDictionaryRef)CFBridgingRetain(queryPublicKey), (CFTypeRef *)&publicKeyBitsCF);
NSData *publicKeyBits = (__bridge_transfer NSData *)publicKeyBitsCF;
if (sanityCheck != noErr)
{
    publicKeyBits = nil;
}


size_t keySize = SecKeyGetBlockSize([self getMyPublicKeyRef]);
NSData *data = [NSData dataWithBytes:(__bridge const void *)(publicKeyBits) length:keySize];
NSString *publicKey = [data base64EncodedString];
NSLog(@"%@",publicKey);
return publicKey;
}

任何人都对我在这里遗漏的内容有任何猜测,我确信这很愚蠢,但由于我是安全框架的新手,所以我无法弄清楚。

谢谢大家 :)

4

0 回答 0