SWIFT。验证文档签名问题。 64 字节而不是 71

SWIFT. Verification of the document signature issue. 64 bytes instead of 71

我的任务是验证元数据的签名合规性,但出于某种原因,我使用了所有方法 return 'false'。该文档通过 C# 以下列方式签名:

//Cert format X509Certificate2
var ecdsa = cert.GetECDsaPrivateKey());
byte[] signature;
signature = ecdsa.SignData(bufferedFileStream, HashAlgorithmName.SHA512);

我们得到大小为 64 字节的签名

但是 swift 本机方法生成大小为 71 字节的签名:

let signature = SecKeyCreateSignature(privateKey,
                                      .ecdsaSignatureMessageX962SHA256,
                                      fileData as CFData,
                                      &signError)

使用 ECDSA NIST p256 生成的证书 签名。算法 - ecdsa-with-SHA256

到目前为止,我尝试了3种检查方式:

//1
SecKeyVerifySignature(publicKey,
                      .ecdsaSignatureMessageX962SHA256,
                      fileData as CFData,
                      signature as! CFData,
                      &error)
//2
SecKeyRawVerify(publicKey,
                .PKCS1SHA512,
                hashedDataBytes,
                digestLength,
                signatureBytes,
                signatureData.count)
//3
let publicKeyP265 = try! P256.Signing.PublicKey(x963Representation: bytesArray)
let ecdsaSignature = try! P256.Signing.ECDSASignature(rawRepresentation: signature)             
let result = publicKeyP265.isValidSignature(ecdsaSignature, for: fileData)

每种方法的结果都是阴性

到目前为止,我还没有成功并验证签名,也许有人遇到过类似的问题。

使用ECDSA和P256时签名的大小与摘要的大小不同。 ECDSA 签名通常编码为 DER 格式。您将拥有 DER 字节的开销以及额外的符号字节(无论整数是否有符号或无符号)。

下面我使用 python 和加密库编写了一个简单示例。您可以看到签名的输出大小几乎总是 70 或更多。我还打印了 DER 签名的十六进制表示。

此处哈希的大小很可能无关紧要。签名的最大区别与EC密钥的密钥大小有关。

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec

message = b'Hello World'

for i in range(0, 10):
    sig = ec.generate_private_key(ec.SECP256R1()).sign(message, ec.ECDSA(hashes.SHA512()))
    print(f'{i}: {len(sig)} {sig.hex()}')

# 0: 71 30450221008466be7ca99fd80bc37527c078c30d07b725dd79feeb29816723259d27ccc367022051f1df8edbf82f528d587ce4db49e99b67cc6e8e61d83d90bfa050195c940721
# 1: 72 3046022100f478984dc0bccfb789713ab2ebb1636115ddaf55c7e8e44ba0c3b076e286def8022100a7ece3201a6cf521838a497510aede841bdc5ab2c59d225c2675a52b221419f6
# 2: 71 3045022100c6e8cfc1872f7aaa4d5c348bee5956ec7dc91422c07f382c402ac6d4265339f802206464c4e7d5d17b0bf28ba9b73cd16d4f1d59aa51d30144431a9367d3eb4fad78
# 3: 71 304502206ee73053a0479de84d1f5786705d121d9342bf1cc6d189fdfd30d55600e72b12022100efb16d5f5a4c7c1d60346e4c22395c955fa2abb2eb30f6649b1ee2c6921ac65a
# 4: 71 304502203a4f2ccec95a94b8b564a5abc837e39b33d338ad4c5ae421316644caac905722022100f78091452346154de97efdf7635c0c6bf74129e4868cd1c870f9b6ccbd20deac
# 5: 71 3045022100d960be8e6196de3e20098438783dfd8347163e5e78c631c592f1198ce3ffe1ef0220537a8e6efcbdcea3f15949c2896c88bd1b164474d34a367a33459e1db31b93d1
# 6: 72 3046022100a08a9e9cedec4341958b6690114a8e5569059e6c0bff3687acc3f49b53f3e105022100857932764645c8a195f4dd18820f12560be2ba2785fc745d49204aace2ebcfd8
# 7: 71 304502210087af13607c190d1656b0fc5d31b303f2616a92a7f516d5f528e8da59a61c0105022009094047f82158a6aca1b17ce6b276dc7122b7ecfebda7c517b6ab8770e40955
# 8: 71 3045022100885d72c1b31058f024d73d2a096cc662d847caf9db59b8483dd963fb70e6c3950220147ee83c980e2d866228c152e5c711817d3e60e60b7abff867ab9bd15b658777
# 9: 70 304402203eeb8b566a3198888bada3d346ab0caf7e14a882d1521120bee679209af2e4200220636100e9a6cd10386a9830a6c2885ee1fdfe00958473adb4bab1a85a0e3c8b11

因此,为了回答您的问题,请使用 DER 格式设置签名:

var ecdsa = cert.GetECDsaPrivateKey();
byte[] signature;
signature = ecdsa.SignData(bufferedFileStream, HashAlgorithmName.SHA512, DSASignatureFormat.Rfc3279DerSequence);

您可以找到函数 here and the supported formats here 的文档。

我用下一个代码解决了我的问题:

    let publicKeyP265 = try! P256.Signing.PublicKey(x963Representation: bytesArray)
    let ecdsaSignature = try! P256.Signing.ECDSASignature(rawRepresentation: signature)
    let fileDataDigest = SHA512.hash(data: fileData)
    
    let result = publicKeyP265.isValidSignature(ecdsaSignature, for: fileDataDigest)

我希望它对其他人有用。