我需要使用公钥在Xcode中验证数字签名的数据(使用私钥密钥在PHP中签名)。我在命令行中在iOS中生成了密钥对,两个密钥都是.pem格式。我按照this示例生成了它,然后在Xcode中验证数据。但是我一直无法以SecKeyRef格式存储和获取来自密钥链的公钥。问题是我一直从stripPublicKeyHeader函数获取NSData对象== NULL,因此我的程序在线崩溃:[peerPublicKeyAttr setObject:publicKeyData forKey:(id)CFBridgingRelease(kSecValueData)];在addPeerPublicKey函数中。 您能否检查一下代码的安静性并帮助确定问题,或者是否有人使用.pem文件中的公钥来验证签名数据?
非常感谢你。
#include <CoreFoundation/CoreFoundation.h>
#import "NSData+Base64.h"
#import "ViewController.h"
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
#include <Security/Security.h>
-(void)VerifyMyData{
NSString* path = [[NSBundle mainBundle] pathForResource:@"MY_Public_Key" ofType:@"pem"];
NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; //retrieve public key content, this is OK
NSString *publicKey;
NSString *startPublicKey = @"-----BEGIN PUBLIC KEY-----";
NSString *endPublicKey = @"-----END PUBLIC KEY-----";
NSScanner *scanner = [NSScanner scannerWithString:content];
[scanner scanUpToString:startPublicKey intoString:nil];
[scanner scanString:startPublicKey intoString:nil];
[scanner scanUpToString:endPublicKey intoString:&publicKey];
//remoteLog is our function to log our logs
[ViewController remoteLog:[NSString stringWithFormat:@"Public key path:%@",path] withlevel:SPECIAL_LOG];
[ViewController remoteLog:[NSString stringWithFormat:@"Public key content:%@",content] withlevel:SPECIAL_LOG];
[ViewController remoteLog:[NSString stringWithFormat:@"content of public key without tags: %@",publicKey] withlevel:SPECIAL_LOG];
NSData *d_key = [NSData dataFromBase64String:content];
NSData *strippedKey = [ViewController stripPublicKeyHeader:d_key];
NSString *StringtoDecode = [[NSBundle mainBundle]objectForInfoDictionaryKey:@"expirySetYear"];
if (d_key == NULL) {
[ViewController remoteLog:@"No data in d_key" withlevel:SPECIAL_LOG];
}
if (strippedKey == NULL) {
[ViewController remoteLog:@"No data in strippedKey" withlevel:SPECIAL_LOG];
}
//in this function it crashes because of strippedKey ==NULL
[ViewController addPeerPublicKey:@"MIA_KEY" keyBits:strippedKey];
}
+ (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
// Skip ASN.1 public key header
if (d_key == nil) {
[ViewController remoteLog:@"stripPublicKeyHeader: d_key == nil" withlevel:SPECIAL_LOG];
return(nil);
}
unsigned int len = [d_key length];
if (!len) {
[ViewController remoteLog:@"stripPublicKeyHeader: length of d_key == nil" withlevel:SPECIAL_LOG];
return(nil);
}
unsigned char *c_key = (unsigned char *)[d_key bytes];
unsigned int idx = 0;
if (c_key[idx++] != 0x30) {
[ViewController remoteLog:@"stripPublicKeyHeader: section 0" withlevel:SPECIAL_LOG];
return(nil);
}
if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;
// PKCS #1 rsaEncryption szOID_RSA_RSA
static unsigned char seqiod[] =
{ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
0x01, 0x05, 0x00 };
if (memcmp(&c_key[idx], seqiod, 15)) {
[ViewController remoteLog:@"stripPublicKeyHeader: section 1" withlevel:SPECIAL_LOG];
return(nil);
}
idx += 15;
if (c_key[idx++] != 0x03) {
[ViewController remoteLog:@"stripPublicKeyHeader: section 2" withlevel:SPECIAL_LOG];
return(nil);
}
if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
else idx++;
if (c_key[idx++] != '\0') {
[ViewController remoteLog:@"stripPublicKeyHeader: section 3" withlevel:SPECIAL_LOG];
return(nil);
}
// Now make a new NSData from this buffer *****THIS IS PROBABLY PROBLEM*****
return([NSData dataWithBytes:&c_key[idx] length:len - idx]);
}
+ (void)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKeyData {
OSStatus sanityCheck = noErr;
CFTypeRef persistPeer = NULL;
//[self removePeerPublicKey:peerName];
NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];
[peerPublicKeyAttr setObject:(id)CFBridgingRelease(kSecClassKey) forKey:(id)CFBridgingRelease(kSecClass)];
[peerPublicKeyAttr setObject:(id)CFBridgingRelease(kSecAttrKeyTypeRSA) forKey:(id)CFBridgingRelease(kSecAttrKeyType)];
[peerPublicKeyAttr setObject:peerTag forKey:(id)CFBridgingRelease(kSecAttrApplicationTag)];
[peerPublicKeyAttr setObject:publicKeyData forKey:(id)CFBridgingRelease(kSecValueData)];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)CFBridgingRelease(kSecReturnData)];
sanityCheck = SecItemAdd((CFDictionaryRef) CFBridgingRetain(peerPublicKeyAttr), (CFTypeRef *)&persistPeer);
if(sanityCheck == errSecDuplicateItem){
//TRC_DBG(@"Problem adding the peer public key to the keychain, OSStatus == %ld.", sanityCheck );
}
//TRC_DBG(@"SecItemAdd OSStATUS = %ld", sanityCheck);
// TRC_DBG(@"PersistPeer privatekey data after import into keychain %@", persistPeer);
persistPeer = NULL;
[peerPublicKeyAttr removeObjectForKey:(id)CFBridgingRelease(kSecValueData)];
sanityCheck = SecItemCopyMatching((CFDictionaryRef) CFBridgingRetain(peerPublicKeyAttr), (CFTypeRef*)&persistPeer);
//TRC_DBG(@"SecItemCopying OSStATUS = %ld", sanityCheck);
// TRC_DBG(@"SecItem copy matching returned this public key data %@", persistPeer);
// The nice thing about persistent references is that you can write their value out to disk and
// then use them later. I don't do that here but it certainly can make sense for other situations
// where you don't want to have to keep building up dictionaries of attributes to get a reference.
//
// Also take a look at SecKeyWrapper's methods (CFTypeRef)getPersistentKeyRefWithKeyRef:(SecKeyRef)key
// & (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef.
//[peerTag release];
//[peerPublicKeyAttr release];
if (persistPeer) CFRelease(persistPeer);
}
答案 0 :(得分:0)
看起来你应该是Base64解码publicKey
,而不是content
?这可以解释为什么您在NULL
中获得stripPublicKeyHeader
。