[英]JS SubtleCrypto RSA Encrypt and Decrypt
所以我試圖實現一些方法來加密然后解密一些數據。 我在這方面沒有任何經驗,我試着跟隨一些關於如何 go 的在線帖子。
當我將加密的“你好”傳遞給解密 function 時,我得到了這個:
let a = importPublicKeyAndEncrypt('hello')
CryptoKey {type: "public", extractable: true, algorithm: {…}, usages: Array(1)} W29iamVjdCBBcnJheUJ1ZmZlcl0=
importPrivateKeyAndDecrypt(a)
Promise {<pending>}
DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
at importPrivateKeyAndDecrypt (<anonymous>:26:60)
解密 function 在我使用我為 PKCS#8 看到的一篇帖子中的加密消息時正常工作,但在我生成自己的密鑰時卻沒有。
這是代碼我做錯了什么?
// PEM encoded X.509 key
const publicKey = `
-----BEGIN PUBLIC KEY-----
<removed for space>
-----END PUBLIC KEY-----`;
// PEM encoded PKCS#8 key
const privateKey = `
-----BEGIN PRIVATE KEY-----
<removed for space>
-----END PRIVATE KEY-----`;
async function importPublicKeyAndEncrypt(str) {
try {
const pub = await importPublicKey(publicKey);
console.log(pub);
const encrypted = await encryptRSA(pub, new TextEncoder().encode(str));
const encryptedBase64 = window.btoa(ab2str(encrypted));
console.log(encryptedBase64.replace(/(.{64})/g, '$1\n'));
} catch (error) {
console.log(error);
}
}
async function importPrivateKeyAndDecrypt(str) {
try {
const priv = await importPrivateKey(privateKey);
const decrypted = await decryptRSA(priv, str2ab(window.atob(str)));
console.log(decrypted);
} catch (error) {
console.log(error);
}
}
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
'spki',
getSpkiDer(spkiPem),
{
name: 'RSA-OAEP',
hash: 'SHA-256',
},
true,
['encrypt']
);
}
async function importPrivateKey(pkcs8Pem) {
return await window.crypto.subtle.importKey(
'pkcs8',
getPkcs8DerDecode(pkcs8Pem),
{
name: 'RSA-OAEP',
hash: 'SHA-256',
},
true,
['decrypt']
);
}
async function encryptRSA(key, plaintext) {
let encrypted = await window.crypto.subtle.encrypt(
{
name: 'RSA-OAEP',
},
key,
plaintext
);
return encrypted;
}
async function decryptRSA(key, ciphertext) {
let decrypted = await window.crypto.subtle.decrypt(
{
name: 'RSA-OAEP',
},
key,
ciphertext
);
return new TextDecoder().decode(decrypted);
}
function getSpkiDer(spkiPem) {
const pemHeader = '-----BEGIN PUBLIC KEY-----';
const pemFooter = '-----END PUBLIC KEY-----';
var pemContents = spkiPem.substring(
pemHeader.length,
spkiPem.length - pemFooter.length
);
var binaryDerString = window.atob(pemContents);
return str2ab(binaryDerString);
}
function getPkcs8DerDecode(pkcs8Pem) {
const pemHeader = '-----BEGIN PRIVATE KEY-----';
const pemFooter = '-----END PRIVATE KEY-----';
var pemContents = pkcs8Pem.substring(
pemHeader.length,
pkcs8Pem.length - pemFooter.length
);
var binaryDerString = window.atob(pemContents);
return str2ab(binaryDerString);
}
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
只有兩個小缺陷。
首先,在importPublicKeyAndEncrypt()
和importPrivateKeyAndDecrypt()
) 中缺少return
語句(盡管后者對於當前代碼片段不是必需的)。
此外,在調用importPublicKeyAndEncrypt()
之前,需要等待 importPublicKeyAndEncrypt() 的importPrivateKeyAndDecrypt()
。
通過這些修復,代碼可以工作:
// PEM encoded X.509 key const publicKey = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT 5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4 OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i GwIDAQAB -----END PUBLIC KEY-----`; // PEM encoded PKCS#8 key const privateKey = `-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8sw wj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqW rbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4O F2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtL zd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOW uL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEq kXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1 c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODw czdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfy qmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBX mNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyF EM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3o bhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884Jo RS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDs jRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCD JjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9 /9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3 qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpM IvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltaya j3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFal CbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdH aj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIA X4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTG Pr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6 ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLA BviZm5AFCQWfke4LZo5mOS10 -----END PRIVATE KEY-----`; async function importPublicKeyAndEncrypt(str) { try { const pub = await importPublicKey(publicKey); //console.log(pub); const encrypted = await encryptRSA(pub, new TextEncoder().encode(str)); const encryptedBase64 = window.btoa(ab2str(encrypted)); //console.log(encryptedBase64.replace(/(.{64})/g, '$1\n')); return encryptedBase64; } catch (error) { console.log(error); } } async function importPrivateKeyAndDecrypt(str) { try { const priv = await importPrivateKey(privateKey); const decrypted = await decryptRSA(priv, str2ab(window.atob(str))); //console.log(decrypted); return decrypted; } catch (error) { console.log(error); } } async function importPublicKey(spkiPem) { return await window.crypto.subtle.importKey( 'spki', getSpkiDer(spkiPem), { name: 'RSA-OAEP', hash: 'SHA-256', }, true, ['encrypt'] ); } async function importPrivateKey(pkcs8Pem) { return await window.crypto.subtle.importKey( 'pkcs8', getPkcs8DerDecode(pkcs8Pem), { name: 'RSA-OAEP', hash: 'SHA-256', }, true, ['decrypt'] ); } async function encryptRSA(key, plaintext) { let encrypted = await window.crypto.subtle.encrypt( { name: 'RSA-OAEP', }, key, plaintext ); return encrypted; } async function decryptRSA(key, ciphertext) { let decrypted = await window.crypto.subtle.decrypt( { name: 'RSA-OAEP', }, key, ciphertext ); return new TextDecoder().decode(decrypted); } function getSpkiDer(spkiPem) { const pemHeader = '-----BEGIN PUBLIC KEY-----'; const pemFooter = '-----END PUBLIC KEY-----'; var pemContents = spkiPem.substring( pemHeader.length, spkiPem.length - pemFooter.length ); var binaryDerString = window.atob(pemContents); return str2ab(binaryDerString); } function getPkcs8DerDecode(pkcs8Pem) { const pemHeader = '-----BEGIN PRIVATE KEY-----'; const pemFooter = '-----END PRIVATE KEY-----'; var pemContents = pkcs8Pem.substring( pemHeader.length, pkcs8Pem.length - pemFooter.length ); var binaryDerString = window.atob(pemContents); return str2ab(binaryDerString); } function str2ab(str) { const buf = new ArrayBuffer(str.length); const bufView = new Uint8Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } function ab2str(buf) { return String.fromCharCode.apply(null, new Uint8Array(buf)); } (async () => { let ciphertext = await importPublicKeyAndEncrypt('hello'); console.log("Ciphertext:\n", ciphertext.replace(/(.{48})/g, '$1\n')); let decryptedData = await importPrivateKeyAndDecrypt(ciphertext); console.log("Decrypted data:", decryptedData); })();
我使用 jsencrypt
客戶端:
const publicKey = `-----BEGIN PUBLIC KEY-----
keydatakeydata
-----END PUBLIC KEY-----`;
export function encrypt(text) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
let encrypted = encrypt.encrypt(text);
return encrypted.toString();
}
Node.js
function decryptString(ciphertext) {
const privateKey = fs.readFileSync('./rsa_512_priv.pem').toString();
const decrypted = crypto.privateDecrypt({
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(ciphertext, 'base64'));
return decrypted.toString("utf8");
}
使用openssl genrsa -out rsa_1024_priv.pem 1024
openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.