gpt4 book ai didi

ios - Objective-C : Unable to fetch SecKeyRef from PEM private key

转载 作者:技术小花猫 更新时间:2023-10-29 11:03:59 30 4
gpt4 key购买 nike

我是 Objective C 和 iOS 编程的新手。

我正在使用使用 openssl 生成的简单公钥/私钥(PEM 格式)来加密和解密需要在服务器和客户端之间交换的数据。我在 Java 服务器和客户端中成功运行了它。

当我在 Java 中使用公钥加密数据并在 Objective C/iOS 中使用私钥解密时,问题就开始了。我查看了几个示例并将一些代码放在一起,但是当我一直调用 SecItemCopyMatching 作为从私钥创建 SecKeyRef 的一部分时,我收到错误 -25300。

顺便说一句,这里不涉及证书,它只是普通 key 。这是我正在做的:

  1. 读取 PEM 私钥和 Base64 解码。
  2. 使用 SecItemCopyMatching 从解码的字符串生成 SecKeyRef。
  3. 使用 SecKeyDecrypt 解密。

我的问题是第 2 步返回状态 -25300 (errSecItemNotFound –25300
找不到该项目。适用于 iOS 2.0 及更高版本。)

这是我生成 SecKeyRef 的代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *challenge = @"2KFqc46DNSWrizzv69lJN25o62xEYQw/QLcMiT2V1XLER9uJbOu+xH2qgTuNWa1HZ9SW3Lq+HovtkhFmjmf08QkVQohHmxCJXVyCgVhPBleScAgQ8AoP3tmV0RqGb2mJrb19ybeYP7uZ2piVtF4cRwU1gO3VTooCUK3cX4wS7Tc=";
NSLog(@"challenge, %@", challenge);

NSData *incomingData = [self base64DataFromString:challenge];
uint8_t *challengeBuffer = (uint8_t*)[incomingData bytes];
NSLog(@"challengeBuffer: %s", challengeBuffer);

[self decryptWithPrivateKey:challengeBuffer];

free(challengeBuffer);

return YES;
}

// Generate a SecKeyRef from the private key in the private.pem file.
- (SecKeyRef)getPrivateKeyRef {
NSString *startPrivateKey = @"-----BEGIN RSA PRIVATE KEY-----";
NSString *endPrivateKey = @"-----END RSA PRIVATE KEY-----";
NSString* path = [[NSBundle mainBundle] pathForResource:@"private"
ofType:@"pem"];
NSString* content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
NSLog(@"Private Key: %@", content);

NSString *privateKey;
NSScanner *scanner = [NSScanner scannerWithString:content];
[scanner scanUpToString:startPrivateKey intoString:nil];
[scanner scanString:startPrivateKey intoString:nil];
[scanner scanUpToString:endPrivateKey intoString:&privateKey];

NSData *privateTag = [self dataWithBase64EncodedString:privateKey];
NSLog(@"Decoded String: %@", privateTag);

OSStatus status = noErr;
SecKeyRef privateKeyReference = NULL;

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

// Set the private key query dictionary.
[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
//[queryPrivateKey setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnRef];


// Get the key.
status = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
NSLog(@"status: %ld", status);

if(status != noErr)
{
privateKeyReference = NULL;
}

return privateKeyReference;
}

// Decrypt data
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer {
OSStatus status = noErr;

SecKeyRef privateKeyRef = [self getPrivateKeyRef];

size_t plainBufferSize = SecKeyGetBlockSize(privateKeyRef);
uint8_t *plainBuffer = malloc(plainBufferSize);

size_t cipherBufferSize = strlen((char *)cipherBuffer);
NSLog(@"decryptWithPrivateKey: length of input: %lu", cipherBufferSize);

// Error handling
status = SecKeyDecrypt(privateKeyRef,
PADDING,
cipherBuffer,
cipherBufferSize,
&plainBuffer[0],
&plainBufferSize
);
NSLog(@"decryption result code: %ld (size: %lu)", status, plainBufferSize);
NSLog(@"FINAL decrypted text: %s", plainBuffer);
}

这几天我一直在头疼,我觉得我需要在这里得到一些帮助。任何人任何指针?我可以花更多时间获得 iOS 提供的加密领域知识和支持,但我根本不进行任何 iOS 编程,这是一次性的事情。

我只需要一些指导,我可以努力让它发挥作用。

TIA。

最佳答案

不幸的是,iOS 上的安全框架要求私钥采用 PKCS12 格式,并带有密码。公钥可以是 X509 armored DER 或 PKCS12,但私钥必须是 PKCS12。您尝试使用的私钥是 PEM 格式的 RSA key 。

如果您有权访问 key ,则可以使用 openssl command line tools 对其进行转换:

openssl pkcs12 -export -nocerts -inkey privatekey.pem -out privatekey.p12

这将创建一个带有私钥的 PKCS12 文件,并且需要一个密码。如果您无法控制私钥(例如,如果私钥来自服务器等外部来源),那您就不走运了。

但我们假设您能够执行上述步骤,将麻烦的 PEM RSA 私钥转换为 PKCS12。从 PKCS12 数据中提取私钥并不难:

  1. 将 PKCS12 作为 NSData 加载。如果这是文件系统上的资源,您可以使用 dataWithContentsOfURL: 执行此操作。
  2. 使用 SecPKCS12Import 导入带有密码的 PKCS12 数据。
  3. 从导入的项目中提取SecIdentityRef
  4. SecIdentityRef复制私钥

这样做的函数是:

OSStatus    SecKeyPrivatePKCS12Import(CFDataRef keyData, CFStringRef passphrase, SecKeyRef *privateKey){
OSStatus status = errSecSuccess;
CFDictionaryRef secImportOptions = NULL;
CFArrayRef secImportItems = NULL;

if ((keyData != NULL) && (CFStringGetLength(passphrase) > 0) ){
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { passphrase };

secImportOptions = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

status = SecPKCS12Import((CFDataRef) keyData, (CFDictionaryRef)secImportOptions, &secImportItems);
if (CFArrayGetCount(secImportItems) > 0){
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(secImportItems, 0);
SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
SecIdentityCopyPrivateKey(identityApp, privateKey);
}
}

return status;
}

从 Objective-C 调用它看起来像:

OSStatus status = errSecSuccess;

status = SecKeyPrivatePKCS12Import((_bridge CFDataRef)data, (_bridge CFStringRef)passphrase, &privateKey);
if (privateKey == NULL){
// Check the status value for why it failed
}

假设“data”是包含 PKCS12 数据的 NSData 实例,“passphrase”是代表密码的 NSString 实例。成功时,“privateKey”会填充从 PKCS12 数据导入的私钥。

关于ios - Objective-C : Unable to fetch SecKeyRef from PEM private key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19697629/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com