我正在创建一个使用服务器和客户端之间安全通信的iPhone Objective-C应用程序。我想遵循的协议是这样的:
使用服务器的公共RSA密钥(硬编码)编译和分发客户端。我们称之为Kspub。 (对于Key Server Public)
客户端生成随机AES密钥。我们称这个密钥为Kcaes(用于密钥客户端AES)
客户端使用Kspub加密Kcaes,并生成加密文本:Kspub(Kcaes)
客户端将Kspub(Kcaes)发送到服务器。
服务器使用服务器的私钥Kspri解密Kspub(Kcaes)。这恢复了Kcaes。现在,客户端和服务器共享一个通用的AES密钥,Kcaes。
要验证这一点,服务器会使用Kcaes加密Kcaes。这会产生加密文本Kcaes(Kcaes)。
服务器将Kcaes(Kcaes)发送给客户端。
客户端使用Kcaes密钥解密Kcaes(Kcaes)。这产生了Kcaes。如果这与原始Kcaes匹配,则客户端知道它已建立安全连接。
客户端和服务器现在可以使用对称密钥Kca安全地交换信息。
我已经实现了服务器端和客户端密钥生成,加密和解密方法。目前,iPhone上生成的密钥对存储在其密钥链中。这是问题所在:
我似乎无法在Apple的Keychain或Security API中找到从文本文件导入公共RSA密钥的方法。如何通过文本文件导入密钥并将其存储在SecKeyRef对象中?
谢谢!
答案 0 :(得分:0)
您通过SecItemAdd
执行此操作,传递:
包含项目类键值对(Keychain Item Class Keys and Values)和可选属性键值对(Attribute Item Keys and Values)的字典,用于指定项目的属性值。
OSStatus err = SecItemAdd((CFDictionaryRef)
[NSDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassKey, kSecClass,
kSecAttrKeyTypeRSA, kSecAttrKeyType,
keyTagUTF8, kSecAttrApplicationTag,
kSecAttrKeyClassPrivate, kSecAttrKeyClass,
keyData, kSecValueData,
nil],
NULL);
确保要存储和检索的属性完全匹配。
答案 1 :(得分:0)
SecKeyCreateWithData
将接受PKCS#1以及x509公钥格式的RSA数据。
因为该问题提到的是文本而不是二进制文件,所以我假定公钥采用标准PEM格式。首先,您要剥离PEM标头和新行:
NSMutableString *pemString = [textFileString mutableCopy];
[pemString replaceOccurrencesOfString:@"-----BEGIN PUBLIC KEY-----" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];
[pemString replaceOccurrencesOfString:@"-----END PUBLIC KEY-----" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];
[pemString replaceOccurrencesOfString:@"\n" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pemString length])];
现在剩下的是Base64字符串,可以将其解码为二进制数据。我想指出,苹果公司的原生Base64方法不能容忍padding issues和other standards。
CFDataRef data = (__bridge CFDataRef) [NSData dataWithBase64EncodedString... // Your preferred base64 method here
现在您可以通过SecKeyRef
获得SecKeyCreateWithData
。
if (data)
{
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dictionary)
{
CFDictionarySetValue(dictionary, kSecAttrKeyClass, kSecAttrKeyClassPublic);
CFDictionarySetValue(dictionary, kSecAttrIsPermanent, kCFBooleanFalse);
CFDictionarySetValue(dictionary, kSecAttrKeyType, kSecAttrKeyTypeRSA);
CFErrorRef error = NULL;
SecKeyRef publicKey = SecKeyCreateWithData(data, dictionary, &error);
if (publicKey)
{
if (error)
{
CFShow(error);
CFRelease(error);
}
//...
CFRelease(publicKey);
}
CFRelease(dictionary);
}
}
您可以在此处保留引用,也可以决定通过SecItemAdd
等将其保存在钥匙串中。