为什么 C# 中的签名算法给出的结果与 Javascript 中的结果不同

Why does signing algorithm in C# give different result than the one in Javascript

这是在 C# 中使用证书中的私钥对数据进行签名的算法,该证书由我和客户端使用,以便定义唯一的密钥来识别用户:

X509Certificate2 keyStore = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "Certifikatat\" + certPath, certPass, X509KeyStorageFlags.Exportable);
RSA privateKey = keyStore.GetRSAPrivateKey();
byte[] iicSignature = privateKey.SignData(Encoding.ASCII.GetBytes("K31418036C|2022-5-16 13:30:41|406|st271ir481|al492py609|zz463gy579|340"), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
byte[] iic = ((HashAlgorithm)CryptoConfig,CreateFromName("MD5")).ComputeHash(iicSignature);

然后我使用 Bouncy Castle 将私钥传递给我的 Javascript:

X509Certificate2 keyStore = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "Certifikatat\" + certPath, certPass, X509KeyStorageFlags.Exportable);
RSA privateKey = keyStore.GetRSAPrivateKey();
var eky = DotNetUtilities.GetRsaKeyPair(privateKey);
Pkcs8Generator pkcs8Gen = new Pkcs8Generator(eky.Private);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pkcs8 = pkcs8Gen.Generate();
PemWriter pemWriter = new PemWriter(new StringWriter());
pemWriter.WriteObject(pkcs8);
pemWriter.Writer.Flush();
return pemWriter.Writer.ToString();

这是Javascript中使用的算法:

window.crypto.subtle.importKey(
    "pkcs8",
    pemToArrayBuffer(pkcs8Pem), {
      name: "RSASSA-PKCS1-v1_5",
      hash: {
        name: "SHA-256"
      },
    },
    false, ["sign"]
  )
  .then(function(privateKey) {
    console.log(privateKey);
    // Sign: RSA with SHA256 and PKCS#1 v1.5 padding
    window.crypto.subtle.sign({
          name: "RSASSA-PKCS1-v1_5",
        },
        privateKey,
        new TextEncoder().encode("K31418036C|2022-5-16 13:30:41|406|st271ir481|al492py609|zz463gy579|340")
      )
      .then(function(signature) {
      var iic = md5(signature);
        console.log(ab2b64(signature));
      })
      .catch(function(err) {
        console.error(err);
      });
  })
  .catch(function(err) {
    console.error(err);
  });

function ab2b64(arrayBuffer) {
  return window.btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}

function removeLines(str) {
  str = str.replace("\r", "");
  return str.replace("\n", "");
}

function base64ToArrayBuffer(b64) {
  var byteString = atob(b64);
  var byteArray = new Uint8Array(byteString.length);
  for (var i = 0; i < byteString.length; i++) {
    byteArray[i] = byteString.charCodeAt(i);
  }
  return byteArray;
}

function pemToArrayBuffer(pem) {
  var b64Lines = removeLines(pem);
  var b64Prefix = b64Lines.replace('-----BEGIN PRIVATE KEY-----', '');
  var b64Final = b64Prefix.replace('-----END PRIVATE KEY-----', '');
  return base64ToArrayBuffer(b64Final);
}

由于某种原因返回的签名不同。我需要它是完全相同的结果,否则一切都毫无意义,因为客户不会被验证。 结果如下:

C#:
57CF663ACBEDE6305309682BA7261412

Javascript:
c099d176dcd95c59d748d6066dcd462e

我不得不将我的签名转换为 base64,然后用 atob() 对其进行编码,之后我需要 this md5 库来散列数据,然后使用 .toUpperCase() 重现正确的结果.

完整的代码如下所示:

md5(atob(ab2b64(signature))).toUpperCase();

现在我从 C# 和 JS 得到相同的结果。