2017-02-22 4 views
0

Ich versuche, einen Prototyp zu schreiben, der eine Reihe von Ecliptic Curve-Schlüsseln (256 Bit) generiert und dann eine Nachricht mit dem privaten Schlüssel signiert. Ich habe Code, der die Schlüssel erzeugt und verwaltet, was gut funktioniert, aber wenn ich versuche, SecKeyRawSign aufzurufen, bekomme ich einen Fehler von -50 errSecParam. Der Code, um die Schlüssel zu generieren sieht wie folgt aus:SecKeyRawSign gibt beim Signieren mit EC-Schlüssel -50 zurück

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)") 
    } 
} 

Der Code zur Unterzeichnung wie folgt aussieht:

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() 
} 

Offensichtlich ist die letzte Wache in der Signum-Funktion wird ausgelöst, und es ist der Rückkehr errSecParam.

Hat jemand erfolgreich Datensignierung in iOS mit EC-Schlüsseln durchgeführt? Wenn ja, siehst du hier etwas Offensichtliches? Tangential gibt es eine Möglichkeit, mehr Informationen über den Fehler selbst zu erhalten.

Edit: Um ein wichtiges Detail hinzuzufügen, wenn ich nichts anderes mache, als diesen Code zu ändern, um stattdessen 2048 Bit RSA-Schlüssel zu generieren, funktioniert der Code gut. Schlüssel generieren und die Nachricht ist signiert. Es ist nur mit 256-Bit-EC-Schlüsseln, dass es fehlschlägt. Gibt es eine alternative Methode für ECDSA in iOS?

Antwort

0

Ich löste das. Der Puffer, den ich erstellte, um die Signatur zu halten, war zu klein. Ich änderte es, um SecKeyGetBlockSize() * 4 zu verwenden, und reduzierte den Puffer dann nach dem Anruf auf SignaturLength. Meine einzige Frage an diesem Punkt ist, ob es einen besseren Weg geben würde, die Länge herauszufinden (außer SecKeyRawSign aufzurufen, es ausfallen zu lassen und dann die Puffergröße auf die zurückgegebene Größe einzustellen).

Das neue Zeichen-Code sieht wie folgt aus:

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() 
} 
Verwandte Themen