Подписание и проверка на iOS с использованием RSA
Как подписать и проверить некоторые данные на iOS с помощью ключа RSA (желательно с использованием собственной системы libcommonCrypto
)?
2 ответа
Поскольку в Stackru и документах Apple практически не было никаких знаний о подписи и проверке, мне пришлось вручную просматривать файлы заголовков iOS и находить SecKeyRawSign
а также SecKeyRawVerify
, Следующие строки кода, кажется, работают.
Подписание NSData (используя SHA256 с RSA):
NSData* PKCSSignBytesSHA256withRSA(NSData* plainData, SecKeyRef privateKey)
{
size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey);
uint8_t* signedHashBytes = malloc(signedHashBytesSize);
memset(signedHashBytes, 0x0, signedHashBytesSize);
size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
uint8_t* hashBytes = malloc(hashBytesSize);
if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {
return nil;
}
SecKeyRawSign(privateKey,
kSecPaddingPKCS1SHA256,
hashBytes,
hashBytesSize,
signedHashBytes,
&signedHashBytesSize);
NSData* signedHash = [NSData dataWithBytes:signedHashBytes
length:(NSUInteger)signedHashBytesSize];
if (hashBytes)
free(hashBytes);
if (signedHashBytes)
free(signedHashBytes);
return signedHash;
}
Проверка (с использованием SHA256 с RSA):
BOOL PKCSVerifyBytesSHA256withRSA(NSData* plainData, NSData* signature, SecKeyRef publicKey)
{
size_t signedHashBytesSize = SecKeyGetBlockSize(publicKey);
const void* signedHashBytes = [signature bytes];
size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH;
uint8_t* hashBytes = malloc(hashBytesSize);
if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) {
return nil;
}
OSStatus status = SecKeyRawVerify(publicKey,
kSecPaddingPKCS1SHA256,
hashBytes,
hashBytesSize,
signedHashBytes,
signedHashBytesSize);
return status == errSecSuccess;
}
Альтернативы (OpenSSL):
Существует очень хорошая альтернатива, которая использует OpenSSL напрямую вместо libCommonCrypto. MIHCrypto - это хорошо разработанная библиотека-обёртка Objective-C для OpenSSL, которая делает работу с криптографией очень простой. Смотрите пример ниже.
Генерация ключа очень проста:
MIHAESKeyFactory *factory = [[MIHAESKeyFactory alloc] init];
id<MIHSymmetricKey> aesKey = [factory generateKey];
Или загрузка ключа из файла:
NSData *privateKeyData = [[NSFileManager defaultManager] contentsAtPath:"mykey.pem"];
MIHRSAPrivateKey *privateKey = [[MIHRSAPrivateKey alloc] initWithData:privateKeyData];
Теперь подпишите что-нибудь:
NSError *signingError = nil;
NSData *message = // load something to sign from somewhere
NSData *signature = [privateKey signWithSHA256:message error:&signingError]
Для большего количества примеров просмотрите страницу MIHCrypto.
На самом деле это намного проще, не нужно создавать хеш вручную.
func validateRSASignature(signedData: Data, signature: Data, publicKeyData: Data) -> Bool {
// Create a SecKey instance from the public key data.
let publicKey: SecKey! = SecKeyCreateWithData(publicKeyData as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic
] as NSDictionary, nil)
// Verify the RSA signature.
return SecKeyVerifySignature(publicKey,
.rsaSignatureMessagePKCS1v15SHA512,
signedData as NSData,
signature as NSData,
nil)
}
Это должно быть возможно, начиная с iOS 10. Возможно, вы захотите расширить обработку ошибок, если ваши ключевые данные и другие входные данные различаются.