Учитывая, что SecKeyRef
, загруженный с помощью SecItemImport
из закрытого ключа RSA, есть способ получить или создать SecKeyRef
только для компонентов открытого ключа? В OpenSSL это можно сделать, скопировав модуль и публичный экспонент в новую структуру, но SecKeyRef
непрозрачен, и мне не удалось найти функцию, которая выполняет эту операцию.
Получить открытый ключ из частного SecKeyRef
Ответ 1
Как и в случае с macOS 10.12, iOS/tvOS 10 и watchOS 3, функция SecKeyCopyPublicKey существует для этого.
Ответ 2
Старый вопрос, но потому, что я сражался с ним сегодня, я нашел способ. Скажем, у вас есть базовый ключ RSA с открытым кодом (это не сертификат, он не der, pem,...), созданный на Java (открытый ключ сертификата X509), вы можете создать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]];
Немного неловко, а не мой код, был Googling на весь день, многие штуки склеены. Имейте, чтобы очистить его,... Возьмите его как взломанный, составленный из Интернета.
Протестировано на сервере, где код находится на Java, и это единственный способ сделать это. Единственный путь, который я нашел. Возможно, есть и другие способы, но только один из них работает для меня, и я могу зашифровать с помощью этого открытого ключа RSA (и наш код сервера (Java) может расшифровать его. И он работает только без заполнения (не рекомендуется) или с помощью kSecPaddingOAEP
padding на стороне iOS и RSA/NONE/OAEPWithSHA1AndMGF1Padding
на стороне Java.