为什么 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 得到相同的结果。
这是在 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 得到相同的结果。