给定从 RSA 私钥SecKeyRef
加载的使用,有没有办法仅为公钥组件获取或创建一个?在 OpenSSL 中,这可以通过将模数和公共指数复制到新结构来完成,但它是不透明的,我一直无法找到执行此操作的函数。SecItemImport
SecKeyRef
SecKeyRef
问问题
813 次
2 回答
1
从 macOS 10.12、iOS/tvOS 10 和 watchOS 3 开始,现在存在功能SecKeyCopyPublicKey来执行此操作。
于 2016-09-13T18:25:52.223 回答
0
老问题,但是因为我今天正在与之斗争,所以我找到了一种方法。假设您有用 Java (X509 证书公钥)创建的 base64 编码的公共 RSA 密钥(它不是证书,不是 der、pem...),您可以通过SecKeyRef
以下方式创建:
- (NSData *)stripPublicKeyHeader2:(NSData *)keyBits {
// Skip ASN.1 public key header
if (keyBits == nil) {
return nil;
}
unsigned int len = [keyBits length];
if (!len) {
return nil;
}
unsigned char *c_key = (unsigned char *)[keyBits bytes];
unsigned int idx = 0;
if (c_key[idx++] != 0x30) {
return nil;
}
if (c_key[idx] > 0x80) {
idx += c_key[idx] - 0x80 + 1;
}
else {
idx++;
}
if (idx >= len) {
return nil;
}
if (c_key[idx] != 0x30) {
return nil;
}
idx += 15;
if (idx >= len - 2) {
return nil;
}
if (c_key[idx++] != 0x03) {
return nil;
}
if (c_key[idx] > 0x80) {
idx += c_key[idx] - 0x80 + 1;
}
else {
idx++;
}
if (idx >= len) {
return nil;
}
if (c_key[idx++] != 0x00) {
return nil;
}
if (idx >= len) {
return nil;
}
// Now make a new NSData from this buffer
return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}
- (SecKeyRef)publicKey:(NSData *)d_key withTag:(NSString *)tag
{
NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];
NSDictionary *saveDict = @{
(__bridge id) kSecClass : (__bridge id) kSecClassKey,
(__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
(__bridge id) kSecAttrApplicationTag : d_tag,
(__bridge id) kSecAttrKeyClass : (__bridge id) kSecAttrKeyClassPublic,
(__bridge id) kSecValueData : d_key
};
OSStatus secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL );
if (secStatus == errSecDuplicateItem ) {
SecItemDelete((__bridge CFDictionaryRef)saveDict);
secStatus = SecItemAdd((__bridge CFDictionaryRef)saveDict, NULL );
}
if ( secStatus != noErr ) {
return NULL;
}
NSDictionary *queryDict = @{
(__bridge id) kSecClass : (__bridge id) kSecClassKey,
(__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA,
(__bridge id) kSecAttrApplicationTag : tag,
(__bridge id) kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPublic,
(__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue
};
// Now fetch the SecKeyRef version of the key
SecKeyRef keyRef = nil;
secStatus = SecItemCopyMatching((__bridge CFDictionaryRef)queryDict,
(CFTypeRef *)&keyRef);
if ( secStatus != noErr ) {
return NULL;
}
return keyRef;
}
NSData *keyData = [[NSData alloc] initWithBase64EncodedString:@"base64encoded X509 private key"
options:0];
certificateData = [self stripPublicKeyHeader2:keyData];
SecKeyRef key = [self publicKey:certificateData withTag:[[NSUUID UUID] UUIDString]];
有点尴尬,不是我的代码,整天在谷歌上搜索,很多部分粘在一起。必须清理它,......把它当作从互联网上编译的黑客。
针对代码在 Java 中的服务器进行了测试,这是唯一的方法。我找到的唯一方法。也许还有另一种方法,但只有这个对我有用,我可以用这个 RSA 公钥加密(我们的服务器代码(Java)可以解密它。它只在没有填充(不推荐)或有kSecPaddingOAEP
填充的情况下工作iOS 端和RSA/NONE/OAEPWithSHA1AndMGF1Padding
Java 端。
于 2014-12-12T19:20:12.673 回答