来自 Apple CryptoKit 的 P256 DER 签名无法通过 OpenSSL 验证(无效签名)

P256 DER signature from Apple CryptoKit unable to be verified by OpenSSL (invalid signature)

在 iOS 我正在使用以下代码生成一对私钥和 public 密钥:

extension Data {
    var hexString: String {
        return map { String(format: "%02hhx", [=10=]) }.joined()
    }
}

let privateKey = P256.Signing.PrivateKey()
let publicKey = privateKey.publicKey

print("private key: " + privateKey.rawRepresentation.hexString)
print("public key: " + "04" + publicKey.rawRepresentation.hexString)

let message = "A message to sign"
let signature = try! privateKey.signature(for: message.data(using: .utf8)!)

print("DER signature: " + signature.derRepresentation.hexString)
print("base64 DER signature: " + signature.derRepresentation.base64EncodedString())

从我得到的代码:

private key: b02f6fd1c1a9986f0e8cc84cd84a5061e46582e9620981d6dadbc0d503c2be4f
public key: 043fbd15edf44c644e2cdaba55db35170521e5c4bd09156b4930cc5721d64be694191e32f33b7a0b583ca301bd76fb2f93df774eddac72add74ef938d236ad1673

DER signature: 304502200ded05de61c062e9b8c5a3af9b18cdb05bd8d19597494869c150d00f490a3a30022100cf1ca3c6a9c8c1f5fb32e8d101179f64c49f9d69d3043dcd2371fff9a5dd74b3
base64 DER signature: MEUCIA3tBd5hwGLpuMWjr5sYzbBb2NGVl0lIacFQ0A9JCjowAiEAzxyjxqnIwfX7MujRARefZMSfnWnTBD3NI3H/+aXddLM=

我尝试通过工具 here 用密钥验证 DER 签名,站点确定签名有效。

但是,如果我尝试使用 OpenSSL 使用以下 Ruby 代码验证相同的结果:

group = OpenSSL::PKey::EC::Group.new('prime256v1')
key = OpenSSL::PKey::EC.new(group)

public_key_hex = '043fbd15edf44c644e2cdaba55db35170521e5c4bd09156b4930cc5721d64be694191e32f33b7a0b583ca301bd76fb2f93df774eddac72add74ef938d236ad1673'
public_key_bn = OpenSSL::BN.new(public_key_hex, 16)
public_key = OpenSSL::PKey::EC::Point.new(group, public_key_bn)    
key.public_key = public_key

data = 'A message to sign'
signature_base64 = 'MEUCIA3tBd5hwGLpuMWjr5sYzbBb2NGVl0lIacFQ0A9JCjowAiEAzxyjxqnIwfX7MujRARefZMSfnWnTBD3NI3H/+aXddLM='
signature = Base64.decode64(signature_base64)
key.dsa_verify_asn1(data, signature)

签名被判定为无效:

irb(main):074:0> key.dsa_verify_asn1(data, signature)
=> false

我认为这可能是由于签名的一些格式问题,但我没有任何想法或方向可以寻找。是这样吗?还是我漏掉了什么?

Ruby 代码不会隐式散列数据,这意味着这必须显式完成:

...
dataHash = OpenSSL::Digest::SHA256.digest(data)
verified = key.dsa_verify_asn1(dataHash, signature)
print verified # true

通过此修复,使用 Ruby 代码的验证成功。