2017-02-22 146 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() 
} 
相关问题