如何将 Rsa 密钥对(字符串)转换为加密密钥以签署数据
How to convert Rsa Key Pair (string) to Crypto key to sign data
我使用此 C# 方法将私钥作为字符串发送到我的 javascript:
public static string SignData(string certPath,string certPass)
{
X509Certificate2 keyStore = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "Certifikatat\" + certPath, certPass, X509KeyStorageFlags.Exportable);
RSA privateKey = keyStore.GetRSAPrivateKey();
TextWriter textWriter = new StringWriter();
var eky = DotNetUtilities.GetRsaKeyPair(privateKey);
PemWriter pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(eky);
pemWriter.Writer.Flush();
return pemWriter.Writer.ToString();
}
现在我需要将字符串转换为 CryptoKey
以便用于对某些数据进行签名。
我尝试了以下代码:
window.crypto.subtle.importKey(
"pkcs8",
pemToArrayBuffer(pk),
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
},
false,
["sign"]
)
.then(function (publicKey) {
//returns a publicKey (or privateKey if you are importing a private key)
console.log(publicKey);
})
.catch(function (err) {
console.error(err);
});
}
function removeLines(str) {
str = str.replace("\r", "");
return str.replace("\n", "");
}
function base64ToArrayBuffer(b64) {
var byteString = btoa(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 RSA PRIVATE KEY-----', '');
var b64Final = b64Prefix.replace('----- END RSA PRIVATE KEY-----', '');
return base64ToArrayBuffer(b64Final);
}
pk
是 rsa 密钥对,现在我需要转换它以便供以下人员使用:
var signature = window.crypto.subtle.sign("RSA_PKCS1_SHA256", pks, bytes);
pks
应该是pk
字符串生成的CryptoKey
。
C#代码导出的密钥不是PKCS#8格式,而是PKCS#1格式。由于 WebCrypto API 仅支持 PKCS#8 格式,因此必须更改:
...
Org.BouncyCastle.OpenSsl.Pkcs8Generator pkcs8Gen = new Org.BouncyCastle.OpenSsl.Pkcs8Generator(eky.Private);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pkcs8 = pkcs8Gen.Generate();
Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(new StringWriter());
pemWriter.WriteObject(pkcs8);
...
中间的两行负责转换为 PKCS#8 格式的密钥。
此外,在base64ToArrayBuffer()
中的JavaScript代码中,btoa()
函数必须替换为atob()
函数。此外,在 pemToArrayBuffer()
中,必须删除 PKCS#8 页眉和页脚,而不是 PKCS#1,即 -----BEGIN PRIVATE KEY-----
和 -----END PRIVATE KEY-----
。
进行这些更改后,在 C# 代码中导出 PKCS#8 密钥,在 JavaScript 代码中将 PKCS#8 密钥导入 CryptoKey
。
完整 JavaScript 代码(包括签名):
var pkcs8Pem = `-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3
u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W
2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T
+IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1
XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6D
Ko0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjI
sXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH
7nWP7CIvcQwB
-----END PRIVATE KEY-----`; // For simplicity, a 512 bit demo key. In practice, keys >= 2048 bits must be used for security reasons!
// Import PKCS#8 key into CryptoKey
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('The quick brown fox jumps over the lazy dog')
)
.then(function(signature){
console.log(ab2b64(signature)); // jIPK2Jftokn+yeuiMQYdWF2vyZF3Jn4+cbuKP84HzGZjv033ry4cGUXSprtC6yXwQiKLWR/BjNqC2Syq6ERnDA==
})
.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 = btoa(b64);
var byteString = atob(b64); // Fix
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 RSA PRIVATE KEY-----', '');
//var b64Final = b64Prefix.replace('----- END RSA PRIVATE KEY-----', '');
var b64Prefix = b64Lines.replace('-----BEGIN PRIVATE KEY-----', ''); // Fix
var b64Final = b64Prefix.replace('-----END PRIVATE KEY-----', ''); // fix
return base64ToArrayBuffer(b64Final);
}
我使用此 C# 方法将私钥作为字符串发送到我的 javascript:
public static string SignData(string certPath,string certPass)
{
X509Certificate2 keyStore = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "Certifikatat\" + certPath, certPass, X509KeyStorageFlags.Exportable);
RSA privateKey = keyStore.GetRSAPrivateKey();
TextWriter textWriter = new StringWriter();
var eky = DotNetUtilities.GetRsaKeyPair(privateKey);
PemWriter pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(eky);
pemWriter.Writer.Flush();
return pemWriter.Writer.ToString();
}
现在我需要将字符串转换为 CryptoKey
以便用于对某些数据进行签名。
我尝试了以下代码:
window.crypto.subtle.importKey(
"pkcs8",
pemToArrayBuffer(pk),
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
},
false,
["sign"]
)
.then(function (publicKey) {
//returns a publicKey (or privateKey if you are importing a private key)
console.log(publicKey);
})
.catch(function (err) {
console.error(err);
});
}
function removeLines(str) {
str = str.replace("\r", "");
return str.replace("\n", "");
}
function base64ToArrayBuffer(b64) {
var byteString = btoa(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 RSA PRIVATE KEY-----', '');
var b64Final = b64Prefix.replace('----- END RSA PRIVATE KEY-----', '');
return base64ToArrayBuffer(b64Final);
}
pk
是 rsa 密钥对,现在我需要转换它以便供以下人员使用:
var signature = window.crypto.subtle.sign("RSA_PKCS1_SHA256", pks, bytes);
pks
应该是pk
字符串生成的CryptoKey
。
C#代码导出的密钥不是PKCS#8格式,而是PKCS#1格式。由于 WebCrypto API 仅支持 PKCS#8 格式,因此必须更改:
...
Org.BouncyCastle.OpenSsl.Pkcs8Generator pkcs8Gen = new Org.BouncyCastle.OpenSsl.Pkcs8Generator(eky.Private);
Org.BouncyCastle.Utilities.IO.Pem.PemObject pkcs8 = pkcs8Gen.Generate();
Org.BouncyCastle.OpenSsl.PemWriter pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(new StringWriter());
pemWriter.WriteObject(pkcs8);
...
中间的两行负责转换为 PKCS#8 格式的密钥。
此外,在base64ToArrayBuffer()
中的JavaScript代码中,btoa()
函数必须替换为atob()
函数。此外,在 pemToArrayBuffer()
中,必须删除 PKCS#8 页眉和页脚,而不是 PKCS#1,即 -----BEGIN PRIVATE KEY-----
和 -----END PRIVATE KEY-----
。
进行这些更改后,在 C# 代码中导出 PKCS#8 密钥,在 JavaScript 代码中将 PKCS#8 密钥导入 CryptoKey
。
完整 JavaScript 代码(包括签名):
var pkcs8Pem = `-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA2gdsVIRmg5IH0rG3
u3w+gHCZq5o4OMQIeomC1NTeHgxbkrfznv7TgWVzrHpr3HHK8IpLlG04/aBo6U5W
2umHQQIDAQABAkEAu7wulGvZFat1Xv+19BMcgl3yhCdsB70Mi+7CH98XTwjACk4T
+IYv4N53j16gce7U5fJxmGkdq83+xAyeyw8U0QIhAPIMhbtXlRS7XpkB66l5DvN1
XrKRWeB3RtvcUSf30RyFAiEA5ph7eWXbXWpIhdWMoe50yffF7pW+C5z07tzAIH6D
Ko0CIQCyveSTr917bdIxk2V/xNHxnx7LJuMEC5DcExorNanKMQIgUxHRQU1hNgjI
sXXZoKgfaHaa1jUZbmOPlNDvYYVRyS0CIB9ZZee2zubyRla4qN8PQxCJb7DiICmH
7nWP7CIvcQwB
-----END PRIVATE KEY-----`; // For simplicity, a 512 bit demo key. In practice, keys >= 2048 bits must be used for security reasons!
// Import PKCS#8 key into CryptoKey
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('The quick brown fox jumps over the lazy dog')
)
.then(function(signature){
console.log(ab2b64(signature)); // jIPK2Jftokn+yeuiMQYdWF2vyZF3Jn4+cbuKP84HzGZjv033ry4cGUXSprtC6yXwQiKLWR/BjNqC2Syq6ERnDA==
})
.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 = btoa(b64);
var byteString = atob(b64); // Fix
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 RSA PRIVATE KEY-----', '');
//var b64Final = b64Prefix.replace('----- END RSA PRIVATE KEY-----', '');
var b64Prefix = b64Lines.replace('-----BEGIN PRIVATE KEY-----', ''); // Fix
var b64Final = b64Prefix.replace('-----END PRIVATE KEY-----', ''); // fix
return base64ToArrayBuffer(b64Final);
}