2017-02-22 35 views
0

Я пытаюсь написать прототип, который генерирует набор ключей эклиптической кривой (256 бит), а затем подписывает сообщение с использованием закрытого ключа. У меня есть код, который генерирует и управляет ключами, которые работают хорошо, но когда я пытаюсь вызвать SecKeyRawSign, я получаю ошибку -50 errSecParam. Код для генерации ключей выглядит следующим образом:SecKeyRawSign возвращает -50 при подписании ключа EC

private func generateKeyPair() throws { 
    var error: Unmanaged<CFError>? = nil 
    let acl = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, 
               [.touchIDAny, .privateKeyUsage], &error) 

    guard error == nil else { 
     throw MessageError(message: "Could not create ACL: \(error)") 
    } 

    // We don't want the public key stored in the ecure enclave, so we create it as 
    // non permament and add it manually to the keychain later 
    let publicKeyParameters: [CFString: Any] = [ 
     kSecAttrIsPermanent: false, 
     kSecAttrApplicationTag: ViewController.KeyTag, 
     kSecAttrLabel: ViewController.PublicLabel 
    ] 

    let privateKeyParameters: [CFString: Any] = [ 
     kSecAttrIsPermanent: true, 
     kSecAttrApplicationTag: ViewController.KeyTag, 
     kSecAttrLabel: ViewController.PrivateLabel, 
     kSecAttrAccessControl: acl! 
    ] 

    var parameters: [CFString: Any] = [ 
     kSecAttrKeyType: kSecAttrKeyTypeEC, 
     kSecAttrKeySizeInBits: NSNumber(value: 256), 
     kSecPublicKeyAttrs: publicKeyParameters, 
     kSecPrivateKeyAttrs: privateKeyParameters 
    ] 

    // On the simulator we can't use the Secure Enclave 
    if hasSecureEnclave() { 
     parameters[kSecAttrTokenID] = kSecAttrTokenIDSecureEnclave 
    } 

    var pubKeyRef, privKeyRef: SecKey? 
    var result = SecKeyGeneratePair(parameters as CFDictionary, &pubKeyRef, &privKeyRef) 
    guard result == noErr else { 
     throw MessageError(message: "Could not create key pair: \(result)") 
    } 

    parameters = [ 
     kSecClass: kSecClassKey, 
     kSecAttrKeyType: kSecAttrKeyTypeEC, 
     kSecAttrApplicationTag: ViewController.KeyTag, 
     kSecAttrLabel: ViewController.PublicLabel, 
     kSecAttrKeyClass: kSecAttrKeyClassPublic, 
     kSecValueRef: pubKeyRef! 
    ] 

    result = SecItemAdd(parameters as CFDictionary, nil) 
    guard result == noErr else { 
     throw MessageError(message: "Could not add public key to keychain: \(result)") 
    } 
} 

код подписание выглядит следующим образом:

private func signWithPrivateKey(_ text: String, _ key: SecKey) throws -> String? { 
    var digest = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) 
    let data = text.data(using: .utf8)! 

    let _ = digest.withUnsafeMutableBytes { digestBytes in 
     data.withUnsafeBytes { dataBytes in 
      CC_SHA256(dataBytes, CC_LONG(data.count), digestBytes) 
     } 
    } 

    var signature = Data(count: SecKeyGetBlockSize(key)) 
    var signatureLength = signature.count 

    let result = signature.withUnsafeMutableBytes { signatureBytes in 
     digest.withUnsafeBytes { digestBytes in 
      SecKeyRawSign(key, 
          SecPadding.PKCS1SHA256, 
          digestBytes, 
          digest.count, 
          signatureBytes, 
          &signatureLength) 
     } 
    } 

    guard result == noErr else { 
     throw MessageError(message: "Could not sign data: \(result)") 
    } 

    return signature.base64EncodedString() 
} 

Очевидно, что окончательный охранник в знаковой функции в настоящее время отключен, и это возвращение errSecParam.

Кто-нибудь успешно выполнил ввод данных в iOS с помощью ключей ЕС? Если это так, вы видите что-то очевидное здесь? Тангенциально есть способ получить дополнительную информацию о самой ошибке.

Редактировать: Чтобы добавить важную деталь, если я ничего не сделаю, кроме как изменить этот код, чтобы генерировать 2048-битные ключи RSA, код работает нормально. Создаются ключи и сообщение подписывается. Только с 256-битными ключами EC он терпит неудачу. Есть ли альтернативный метод для ECDSA в iOS?

ответ

0

Я решил это. Буфер, который я создавал для хранения подписи, был слишком мал. Я изменил его, чтобы использовать SecKeyGetBlockSize() * 4, а затем уменьшив буфер до уровня подписи после вызова. Мой единственный вопрос на данный момент - это лучший способ определить длину (кроме вызова SecKeyRawSign, отказ от нее, а затем настройку размера буфера на возвращаемый размер).

Новый код знака выглядит следующим образом:

private func signWithPrivateKey(_ text: String, _ key: SecKey) throws -> String? { 
    var digest = Data(count: Int(CC_SHA256_DIGEST_LENGTH)) 
    let data = text.data(using: .utf8)! 

    let _ = digest.withUnsafeMutableBytes { digestBytes in 
     data.withUnsafeBytes { dataBytes in 
      CC_SHA256(dataBytes, CC_LONG(data.count), digestBytes) 
     } 
    } 

    var signature = Data(count: SecKeyGetBlockSize(key) * 4) 
    var signatureLength = signature.count 

    let result = signature.withUnsafeMutableBytes { signatureBytes in 
     digest.withUnsafeBytes { digestBytes in 
      SecKeyRawSign(key, 
          SecPadding.PKCS1SHA256, 
          digestBytes, 
          digest.count, 
          signatureBytes, 
          &signatureLength) 
     } 
    } 

    let count = signature.count - signatureLength 
    signature.removeLast(count) 

    guard result == noErr else { 
     throw MessageError(message: "Could not sign data: \(result)") 
    } 

    return signature.base64EncodedString() 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^