Son*_*yen 19 iphone rsa pem der public-key
我需要将我的iPhone应用程序与系统集成,他们需要通过给定的公钥加密数据,有3种不同格式的文件.xml .der和.pem,我研究过并发现了一些关于从中获取SecKeyRef的文章DER/PEM,但它们总是返回零.以下是我的代码:
NSString *pkFilePath = [[NSBundle mainBundle] pathForResource:@"PKFile" ofType:@"der"];
NSData *pkData = [NSData dataWithContentsOfFile:pkFilePath];
SecCertificateRef cert;
cert = SecCertificateCreateWithData(NULL, (CFDataRef) pkData);
assert(cert != NULL);
OSStatus err;
if (cert != NULL) {
err = SecItemAdd(
(CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:
(id) kSecClassCertificate, kSecClass,
(id) cert, kSecValueRef,
nil
],
NULL
);
if ( (err == errSecSuccess) || (err == errSecDuplicateItem) ) {
CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL);
SecPolicyRef policy = SecPolicyCreateBasicX509();
SecTrustRef trust;
SecTrustCreateWithCertificates(certs, policy, &trust);
SecTrustResultType trustResult;
SecTrustEvaluate(trust, &trustResult);
if (certs) {
CFRelease(certs);
}
if (trust) {
CFRelease(trust);
}
return SecTrustCopyPublicKey(trust);
}
}
return NULL;
Run Code Online (Sandbox Code Playgroud)
问题发生在SecCertificateCreateWithData,它总是返回nil,即使通过读取文件也没问题.有人这样做请帮助我,谢谢!
编辑:证书文件是MD5签名.
Wer*_*her 54
我在同样的问题上苦苦挣扎,终于找到了解决方案.我的问题是我需要使用外部私钥和公钥来加密/解密iOS应用程序中的数据,并且不想使用钥匙串.事实证明,您还需要一个用于iOS安全库的签名证书才能读取密钥数据,当然文件必须采用正确的格式.程序基本如下:
假设你有一个PEM格式的私钥(使用----- BEGIN RSA私钥-----和-----结束RSA私钥-----标记):rsaPrivate.pem
//Create a certificate signing request with the private key
openssl req -new -key rsaPrivate.pem -out rsaCertReq.csr
//Create a self-signed certificate with the private key and signing request
openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey rsaPrivate.pem -out rsaCert.crt
//Convert the certificate to DER format: the certificate contains the public key
openssl x509 -outform der -in rsaCert.crt -out rsaCert.der
//Export the private key and certificate to p12 file
openssl pkcs12 -export -out rsaPrivate.p12 -inkey rsaPrivate.pem -in rsaCert.crt
Run Code Online (Sandbox Code Playgroud)
现在您有两个与iOS安全框架兼容的文件:rsaCert.der(公钥)和rsaPrivate.p12(私钥).假设文件已添加到您的包中,下面的代码将读入公钥:
- (SecKeyRef)getPublicKeyRef {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"rsaCert" ofType:@"der"];
NSData *certData = [NSData dataWithContentsOfFile:resourcePath];
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
SecKeyRef key = NULL;
SecTrustRef trust = NULL;
SecPolicyRef policy = NULL;
if (cert != NULL) {
policy = SecPolicyCreateBasicX509();
if (policy) {
if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) {
SecTrustResultType result;
OSStatus res = SecTrustEvaluate(trust, &result);
//Check the result of the trust evaluation rather than the result of the API invocation.
if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
key = SecTrustCopyPublicKey(trust);
}
}
}
}
if (policy) CFRelease(policy);
if (trust) CFRelease(trust);
if (cert) CFRelease(cert);
return key;
}
Run Code Online (Sandbox Code Playgroud)
要读入私钥,请使用以下代码:
SecKeyRef getPrivateKeyRef() {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"rsaPrivate" ofType:@"p12"];
NSData *p12Data = [NSData dataWithContentsOfFile:resourcePath];
NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
SecKeyRef privateKeyRef = NULL;
//change to the actual password you used here
[options setObject:@"password_for_the_key" forKey:(id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import((CFDataRef) p12Data,
(CFDictionaryRef)options, &items);
if (securityError == noErr && CFArrayGetCount(items) > 0) {
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
SecIdentityRef identityApp =
(SecIdentityRef)CFDictionaryGetValue(identityDict,
kSecImportItemIdentity);
securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
if (securityError != noErr) {
privateKeyRef = NULL;
}
}
[options release];
CFRelease(items);
return privateKeyRef;
}
Run Code Online (Sandbox Code Playgroud)
从iOS 10开始,实际上可以导入PEM私钥,而无需将它们转换为PKCS#12(这是一种非常通用的容器格式,用于与加密相关的所有内容),因此也无需在命令行或静态上使用OpenSSL将应用与其关联.在macOS上,甚至可以使用与此处提到的功能不同的10.7(但到目前为止iOS不存在).但是,下面描述的方式也适用于macOS 10.12及更高版本.
要导入证书,只需删除证书即可
-----BEGIN CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)
和
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)
行,然后对剩下的数据运行base64解码,结果是标准DER格式的证书,可以只用它SecCertificateCreateWithData()来获取SecCertificateRef.这在iOS 10之前一直有效.
要导入私钥,可能需要一些额外的工作.如果私钥被包装
-----BEGIN RSA PRIVATE KEY-----
Run Code Online (Sandbox Code Playgroud)
那很容易.同样,需要剥离第一行和最后一行,其余数据需要进行base64解码,结果是PKCS#1格式的RSA密钥.这种格式只能保存RSA密钥并且可以直接读取,只需将解码后的数据输入SecKeyCreateWithData()即可获得SecKeyRef.该attributes词典只需要下面的键/值对:
kSecAttrKeyType: kSecAttrKeyTypeRSAkSecAttrKeyClass: kSecAttrKeyClassPrivate kSecAttrKeySizeInBits:CFNumberRef然后使用密钥中的位数(例如1024,2048等)如果不知道,这个信息实际上可以从原始密钥数据中读取,这是ASN.1数据(它有点超出了这个答案的范围) ,但我将在下面提供一些有关如何解析该格式的有用链接).这个值可能是可选的!在我的测试中,实际上没有必要设置这个值; 如果不存在,API会自行确定该值,并且以后总是正确设置.如果私钥被包装-----BEGIN PRIVATE KEY-----,则base64编码数据不是PKCS#1格式,而是PKCS#8格式,但是,这只是一个更通用的容器,也可以保存非RSA密钥但是对于RSA密钥该容器的内部数据等于PKCS#1,因此可以说对于RSA密钥PKCS#8是带有额外标头的PKCS#1,您需要做的就是剥离该额外的标头.只需删除base64解码数据的前26个字节,然后再次使用PKCS#1.是的,它真的那么简单.
要了解有关PEM编码中PKCS#x格式的更多信息,请查看此站点.要了解有关ASN.1格式的更多信息,这里有一个很好的网站.如果您需要一个简单但功能强大且交互式的在线ASN.1解析器来使用不同的格式,可以直接读取PEM数据,以及base64和hexdump中的ASN.1,请尝试使用此站点.
非常重要:在向上面创建的钥匙串添加私钥时,请注意这样的私钥不包含公钥哈希,但公钥哈希对于他们的钥匙串API形成身份很重要(SecIdentityRef),因为使用公钥哈希是API如何找到属于导入证书的正确私钥(a SecIdentityRef只是SecKeyRef一个私钥和一个SecCertificateRef形成组合对象的证书,它是公钥哈希,它绑定他们在一起).因此,当您计划将私钥添加到钥匙串时,请确保手动设置公钥哈希,否则您将无法获得该身份的标识,如果没有,您就无法使用钥匙串API执行签名或解密等任务数据.公钥哈希必须存储在一个名为kSecAttrApplicationLabel(愚蠢的名称,我知道,但它实际上不是标签,用户无法看到的任何东西,请查看文档)的属性中.例如:
OSStatus error = SecItemAdd(
(__bridge CFDictionaryRef)@{
(__bridge NSString *)kSecClass:
(__bridge NSString *)kSecClassKey,
(__bridge NSString *)kSecAttrApplicationLabel:
hashOfPublicKey, // hashOfPublicKey is NSData *
#if TARGET_OS_IPHONE
(__bridge NSString *)kSecValueRef:
(__bridge id)privateKeyToAdd, // privateKeyToAdd is SecKeyRef
#else
(__bridge NSString *)kSecUseItemList:
@[(__bridge id)privateKeyToAdd], // privateKeyToAdd is SecKeyRef
// @[ ... ] wraps it into a NSArray object,
// as kSecUseItemList expects an array of items
#endif
},
&outReference // Can also be NULL,
// otherwise reference to added keychain entry
// that must be released with CFRelease()
);
Run Code Online (Sandbox Code Playgroud)
在这篇文章的帮助下,经过数小时的在线研究,我终于让它完美运行。这是最新版本的 Swift 代码的注释。我希望它可以帮助某人!
在像这样(PEM 格式)夹在头部和尾部之间的 base64 编码字符串中收到一个证书:
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)去掉头部和尾部,例如
// remove the header string
let offset = ("-----BEGIN CERTIFICATE-----").characters.count
let index = certStr.index(cerStr.startIndex, offsetBy: offset+1)
cerStr = cerStr.substring(from: index)
// remove the tail string
let tailWord = "-----END CERTIFICATE-----"
if let lowerBound = cerStr.range(of: tailWord)?.lowerBound {
cerStr = cerStr.substring(to: lowerBound)
}
Run Code Online (Sandbox Code Playgroud)将 base64 字符串解码为 NSData:
let data = NSData(base64Encoded: cerStr,
options:NSData.Base64DecodingOptions.ignoreUnknownCharacters)!
Run Code Online (Sandbox Code Playgroud)将其从 NSdata 格式转换为 SecCertificate:
let cert = SecCertificateCreateWithData(kCFAllocatorDefault, data)
Run Code Online (Sandbox Code Playgroud)现在,此证书可用于与从 urlSession 信任收到的证书进行比较:
certificateFromUrl = SecTrustGetCertificateAtIndex(...)
if cert == certificate {
}
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
20267 次 |
| 最近记录: |