Подписание и проверка на 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. Возможно, вы захотите расширить обработку ошибок, если ваши ключевые данные и другие входные данные различаются.

Другие вопросы по тегам