2017-02-22 148 views
0

我試圖編寫一個生成一組黃道曲線密鑰(256位)的原型,然後使用私鑰簽署消息。我有代碼生成和管理這些效果很好的密鑰,但是當我嘗試調用SecKeyRawSign時,出現-50 errSecParam錯誤。生成密鑰的代碼如下所示:SecKeyRawSign在使用EC密鑰進行簽名時返回-50

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。

有沒有人使用EC密鑰在iOS中成功完成數據簽名?如果是這樣,你看到什麼明顯的嗎?切線方式有辦法獲得有關錯誤本身的更多信息。

編輯:要添加一個重要的細節,如果我什麼都不做,只需更改此代碼以生成2048位RSA密鑰,代碼就可以正常工作。密鑰生成並且消息被簽名。它只有256位EC密鑰纔會失敗。有沒有其他的方法可以在iOS中執行ECDSA?

回答

0

我解決了這個問題。我創建的用於保存簽名的緩衝區太小。我將它改爲使用SecKeyGetBlockSize()* 4,然後在調用後將緩衝區減少爲signatureLenght。我現在唯一的問題是,如果有更好的方法找出長度(除了調用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() 
} 
相關問題