0

I'm trying to sign and verify a challenge with elliptic curve algorithms using Apple tools.

Using the SecKeyCreateWithData I can use/import already generated public/private keys, this works great. Then I call the sign() function which takes SecKeyAlgorithm parameter. In my case is ecdsaSignatureDigestX962 because I use secp256r1 curve (NIST P-256). So the signature doesn't failed but then the verify always crash with :

Can't verify/wrong signature Unmanaged<CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-67808 "EC signature verification failed (ccerr -7)" UserInfo={NSDescription=EC signature verification failed (ccerr -7)})

Here is my complete code if someone has an idea :

import UIKit

class SecureEnclave: UIViewController {

    var publicKey: SecKey!
    var privateKey: SecKey!
    var signature: Data!

    override func viewDidLoad() {
        super.viewDidLoad()

        if #available(iOS 10.0, *) {

            var error: Unmanaged<CFError>?

            //Step 1: Private Key
            let privKeyUInt8: [UInt8] = [0x04,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0x**,0xde,0x0a,0x37,0x02,0xfc,0xc6,0x04,0x5b,0x03,0xd7,0x12,0x03,0x26,0x6a,0x4b,0x3d,0x05,0x55,0x5d,0x90,0xe1,0xa4,0xcf,0xd1,0x78,0xf7,0x95,0xda,0xa3,0x9c,0x**,0x2c,0x37,0x4f,0x**,0xfa,0x28,0x2e,0x64,0x7a,0x22,0x7f,0x47,0x9a,0x98,0x1a,0x2c,0x9b,0x2d,0x28,0x96,0xe0,0x**,0x07,0x33,0x06,0x10,0x5a,0x95,0x85,0x9c,0xc3,0xfd,0x43,0xf4,0x81,0x95,0xf4,0xe5,0x6d,0xb2,0x**,0x**,0x**,0x87,0x6d,0xc1,0x52,0x89,0xd3,0x05]

            let CFPrivData = CFDataCreate(nil, privKeyUInt8, privKeyUInt8.count)
            let optionsPrivKey: [String: Any] = [
                                                    kSecAttrKeyType as String         : kSecAttrKeyTypeEC,
                                                    kSecAttrKeyClass as String        : kSecAttrKeyClassPrivate,
                                                ]

            guard let privKey = SecKeyCreateWithData(CFPrivData!, optionsPrivKey as CFDictionary, &error) else {
                 let error = error!.takeRetainedValue() as Error
                 return print(error)
            }

            self.privateKey = privKey

            //Step 2: Public Key
            let pubKeyUInt8: [UInt8] = [0x04,0x09,0x44,0x11,0xc6,0xbe,0x9f,0x31,0x88,0xa0,0x23,0xe7,0xf1,0x77,0x13,0xef,0xde,0x0a,0x37,0x02,0xfc,0xc6,0x04,0x5b,0x03,0xd7,0x12,0x03,0x26,0x6a,0x4b,0x3d,0x05,0x55,0x5d,0x90,0xe1,0xa4,0xcf,0xd1,0x78,0xf7,0x95,0xda,0xa3,0x9c,0x18,0x2c,0x37,0x4f,0x1b,0xfa,0x28,0x2e,0x64,0x7a,0x22,0x7f,0x47,0x9a,0x98,0x1a,0x2c,0x9b,0x2d]

            let CFPubData = CFDataCreate(nil, pubKeyUInt8, pubKeyUInt8.count)

            let optionsPubKey: [String: Any] = [kSecAttrKeyType as String: kSecAttrKeyTypeEC,
                                          kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
                                          kSecAttrKeySizeInBits as String: 256]

            guard let pubKey = SecKeyCreateWithData(CFPubData!, optionsPubKey as CFDictionary, &error) else {
                let error = error!.takeRetainedValue() as Error
                return print(error)
            }

            self.publicKey = pubKey

            //Step 3: Signing/Verifing

            let challengeString = "Hello"
            let challengeData = challengeString.data(using: .utf8)

            self.sign(algorithm: .ecdsaSignatureDigestX962, data: challengeData!)

        } else {
            print("unsupported")
        }

    }

    private func sign(algorithm: SecKeyAlgorithm, data: Data) {

        guard SecKeyIsAlgorithmSupported(self.privateKey!, .sign, algorithm) else {
            print("Algorith not supported - Can't sign")
            return
        }

        // SecKeyCreateSignature call is blocking when the used key
        // is protected by biometry authentication. If that's not the case,
        // dispatching to a background thread isn't necessary.
        DispatchQueue.global().async {
            var error: Unmanaged<CFError>?
            let signature = SecKeyCreateSignature(self.privateKey!, algorithm, data as CFData, &error) as Data?

            DispatchQueue.main.async {
                self.signature = signature

                guard signature != nil else {
                    print((error!.takeRetainedValue() as Error).localizedDescription)
                    return
                }
                print("Signature : OK !")

                //Step 4: Verifing

                let algorithm: SecKeyAlgorithm = .ecdsaSignatureDigestX962
                guard SecKeyIsAlgorithmSupported(self.publicKey, .verify, algorithm) else {
                    print("Algorith not supported - Can't verify")
                    return
                }

                var error: Unmanaged<CFError>?
                guard SecKeyVerifySignature(self.publicKey, algorithm, data as CFData, self.signature as CFData, &error) else {
                    print("Can't verify/wrong signature \(error!)")
                    return
                }
                print("Signature check: OK")
            }
        }
    }
}
Silvering
  • 756
  • 1
  • 6
  • 33
  • I hope you did not paste any sensitive private key now..? You partially obfuscated it? Why you wrote `0x**`? Why aren;y you using Apples new library `CryptoKit`? It has support for that curve. Also try to simplify the code snippet a bit, remove all UI related stuff, that has nothing to do with what is going on. Also neater to use a hex string for bytes, rather than `[UInt8]`. – Sajjon Apr 24 '20 at 14:57
  • more helpful would be to see your tests, like this: https://github.com/Sajjon/EllipticCurveKit/blob/master/Tests/EllipticCurveKitTests/CurveTests/Secp256r1/Secp256r1_PointArthmeticTests.swift And then your minimal code (ought to be minimal, since you ought to use CryptoKit, or the open source variant of it github.com/apple/swift-crypto ) – Sajjon Apr 24 '20 at 15:06
  • `ecdsaSignatureDigestX962` implies you are verifying a hash, while you are verifying `data`, which is not the hash, but the plaintext. (This goes for the signature operation as well, which can cause problems). Change this to `ecdsaSignatureMessageX962` and try again. Message means the input it plain text, which needs to be hashed in order to be signed or verified. Digest means the input data is already hashed and should not be hashed before signature or verification – Bram Dec 28 '20 at 21:34

0 Answers0