JavaScript 字符串加密和解密?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18279141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript string encryption and decryption?
提问by jeremiahs
I'm interested in building a small app for personal use that will encrypt and decrypt information on the client side using JavaScript. The encrypted information will be stored in a database on a server, but never the decrypted version.
我有兴趣构建一个供个人使用的小应用程序,它将使用 JavaScript 在客户端加密和解密信息。加密信息将存储在服务器上的数据库中,但绝不会是解密版本。
It doesn't have to be super duper secure, but I would like to use a currently unbroken algorithm.
它不必是超级安全的,但我想使用当前未破坏的算法。
Ideally I'd be able to do something like
理想情况下,我可以做类似的事情
var gibberish = encrypt(string, salt, key);
to generate the encoded string, and something like
生成编码字符串,以及类似的东西
var sensical = decrypt(gibberish, key);
to decode it later.
稍后解码。
So far I've seen this: http://bitwiseshiftleft.github.io/sjcl/
到目前为止,我已经看到了这个:http: //bitwiseshiftleft.github.io/sjcl/
Any other libraries I should look at?
我应该看看其他图书馆吗?
回答by Tomas Kirda
var encrypted = CryptoJS.AES.encrypt("Message", "Secret Passphrase");
//U2FsdGVkX18ZUVvShFSES21qHsQEqZXMxQ9zgHy+bu0=
var decrypted = CryptoJS.AES.decrypt(encrypted, "Secret Passphrase");
//4d657373616765
document.getElementById("demo1").innerHTML = encrypted;
document.getElementById("demo2").innerHTML = decrypted;
document.getElementById("demo3").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
Full working sample actually is:
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js" integrity="sha256-/H4YS+7aYb9kJ5OKhFYPUjSJdrtV6AeyJOtTkw6X72o=" crossorigin="anonymous"></script>
<br><br>
<label>encrypted</label>
<div id="demo1"></div>
<br>
<label>decrypted</label>
<div id="demo2"></div>
<br>
<label>Actual Message</label>
<div id="demo3"></div>
回答by ovidb
How about CryptoJS?
It's a solid crypto library, with a lot of functionality. It implements hashers, HMAC, PBKDF2 and ciphers. In this case ciphers is what you need. Check out the quick-start quide on the project's homepage.
这是一个可靠的加密库,具有很多功能。它实现了哈希器、HMAC、PBKDF2 和密码。在这种情况下,密码就是您所需要的。查看项目主页上的快速入门指南。
You could do something like with the AES:
你可以用 AES 做类似的事情:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script>
var encryptedAES = CryptoJS.AES.encrypt("Message", "My Secret Passphrase");
var decryptedBytes = CryptoJS.AES.decrypt(encryptedAES, "My Secret Passphrase");
var plaintext = decryptedBytes.toString(CryptoJS.enc.Utf8);
</script>
As for security, at the moment of my writing AES algorithm is thought to be unbroken
至于安全性,在我编写 AES 算法的那一刻被认为是完整的
Edit :
编辑 :
Seems online URL is down & you can use the downloaded files for encryption from below given link & place the respective files in your root folder of the application.
似乎在线 URL 已关闭,您可以从下面给定的链接中使用下载的文件进行加密,并将相应的文件放在应用程序的根文件夹中。
https://code.google.com/archive/p/crypto-js/downloads
https://code.google.com/archive/p/crypto-js/downloads
or used other CDN like https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js
或使用其他 CDN,如https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js
回答by Jorgeblom
I created an insecure but simple text cipher/decipher util. No dependencies with any external library.
我创建了一个不安全但简单的文本密码/解密工具。不依赖任何外部库。
These are the functions
这些是功能
const cipher = salt => {
const textToChars = text => text.split('').map(c => c.charCodeAt(0));
const byteHex = n => ("0" + Number(n).toString(16)).substr(-2);
const applySaltToChar = code => textToChars(salt).reduce((a,b) => a ^ b, code);
return text => text.split('')
.map(textToChars)
.map(applySaltToChar)
.map(byteHex)
.join('');
}
const decipher = salt => {
const textToChars = text => text.split('').map(c => c.charCodeAt(0));
const applySaltToChar = code => textToChars(salt).reduce((a,b) => a ^ b, code);
return encoded => encoded.match(/.{1,2}/g)
.map(hex => parseInt(hex, 16))
.map(applySaltToChar)
.map(charCode => String.fromCharCode(charCode))
.join('');
}
And you can use them as follows:
您可以按如下方式使用它们:
// To create a cipher
const myCipher = cipher('mySecretSalt')
//Then cipher any text:
myCipher('the secret string') // --> "7c606d287b6d6b7a6d7c287b7c7a61666f"
//To decipher, you need to create a decipher and use it:
const myDecipher = decipher('mySecretSalt')
myDecipher("7c606d287b6d6b7a6d7c287b7c7a61666f") // --> 'the secret string'
回答by richardtallent
Modern browsers now support the crypto.subtle
API, which provides native encryption and decryption functions (async no less!) using one of these method: AES-CBC, AES-CTR, AES-GCM, or RSA-OAEP.
现代浏览器现在支持crypto.subtle
API,它使用以下方法之一提供本机加密和解密功能(异步不少!):AES-CBC、AES-CTR、AES-GCM 或 RSA-OAEP。
回答by Scott Arciszewski
The existing answers which leverage SJCL, CryptoJS, and/or WebCrypto aren't necessarily wrongbut they're not as safe as you might initially suspect. Generally you want to use libsodium. First I'll explain why, then how.
利用 SJCL、CryptoJS 和/或 WebCrypto 的现有答案不一定是错误的,但它们并不像您最初怀疑的那样安全。通常你想使用 libsodium。首先我将解释为什么,然后解释如何。
Why Not SJCL, CryptoJS, WebCrypto, etc.?
为什么不是 SJCL、CryptoJS、WebCrypto 等?
Short answer:In order for your encryption to actually be secure, these libraries expect you to make too many choices e.g. the block cipher mode (CBC, CTR, GCM; if you can't tell which of the three I just listed is secure to use and under what constraints, you shouldn't be burdened with this sort of choice at all).
简短回答:为了让您的加密真正安全,这些库希望您做出太多选择,例如分组密码模式(CBC、CTR、GCM;如果您无法分辨我刚刚列出的三个中的哪一个是安全的使用和在什么样的约束,你不应该有这种选择的负担在所有)。
Unless your job title is cryptography engineer, the odds are stacked against you implementing it securely.
除非你的职位是密码学工程师,否则你安全地实施它的可能性很大。
Why to Avoid CryptoJS?
为什么要避免 CryptoJS?
CryptoJS offers a handful of building blocks and expects you to know how to use them securely. It even defaults to CBC mode(archived).
CryptoJS 提供了一些构建块,并希望您知道如何安全地使用它们。它甚至默认为 CBC 模式(已存档)。
Why is CBC mode bad?
为什么 CBC 模式不好?
Read this write-up on AES-CBC vulnerabilities.
Why to Avoid WebCrypto?
为什么要避免 WebCrypto?
WebCrypto is a potluck standard, designed by committee, for purposes that are orthogonal to cryptography engineering. Specifically, WebCrypto was meant to replace Flash, not provide security.
WebCrypto 是一个便餐标准,由委员会设计,用于与密码工程正交的目的。具体来说,WebCrypto 旨在取代 Flash,而不是提供安全性。
Why to Avoid SJCL?
为什么要避免 SJCL?
SJCL's public API and documentation begs users to encrypt data with a human-remembered password. This is rarely, if ever, what you want to do in the real world.
SJCL 的公共 API 和文档要求用户使用人类记住的密码加密数据。这在现实世界中很少(如果有的话)您想要做的。
Additionally: Its default PBKDF2 round count is roughly 86 times as small as you want it to be. AES-128-CCM is probably fine.
另外:它的默认 PBKDF2 轮数大约是您希望的 86 倍。AES-128-CCM 可能没问题。
Out of the three options above, SJCL is the least likely to end in tears. But there are better options available.
在上述三个选项中,SJCL 最不可能以眼泪收场。但是有更好的选择。
Why is Libsodium Better?
为什么 Libsodium 更好?
You don't need to choose between a menu of cipher modes, hash functions, and other needless options. You'll never risk screwing up your parameters and removing all security from your protocol.
您无需在密码模式菜单、散列函数和其他不必要的选项之间进行选择。您永远不会冒着搞砸参数和从协议中删除所有安全性的风险。
Instead, libsodiumjust gives you simple options tuned for maximum security and minimalistic APIs.
相反,libsodium只是为您提供针对最大安全性和简约 API 进行调整的简单选项。
crypto_box()
/crypto_box_open()
offer authenticated public-key encryption.- The algorithm in question combines X25519 (ECDH over Curve25519) and XSalsa20-Poly1305, but you don't need to know (or even care) about that to use it securely
crypto_secretbox()
/crypto_secretbox_open()
offer shared-key authenticated encryption.- The algorithm in question is XSalsa20-Poly1305, but you don't need to know/care
crypto_box()
/crypto_box_open()
提供经过身份验证的公钥加密。- 有问题的算法结合了 X25519(ECDH over Curve25519)和 XSalsa20-Poly1305,但你不需要知道(甚至关心)它来安全地使用它
crypto_secretbox()
/crypto_secretbox_open()
提供共享密钥认证加密。- 有问题的算法是 XSalsa20-Poly1305,但你不需要知道/关心
Additionally, libsodium has bindings in dozens of popular programming languages, so it's very likely that libsodium will just workwhen trying to interoperate with another programming stack. Also, libsodium tends to be very fast without sacrificing security.
此外,libsodium绑定了数十种流行的编程语言,因此当尝试与另一个编程堆栈进行互操作时,libsodium 很可能会正常工作。此外,libsodium 在不牺牲安全性的情况下往往非常快。
How to Use Libsodium in JavaScript?
如何在 JavaScript 中使用 Libsodium?
First, you need to decide one thing:
首先,你需要决定一件事:
- Do you just want to encrypt/decrypt data (and maybe still somehow use the plaintext in database queries securely) and not worry about the details? Or...
- Do you need to implement a specific protocol?
- 您是否只想加密/解密数据(并且可能仍然以某种方式安全地使用数据库查询中的明文)而不担心细节?或者...
- 您需要实现特定的协议吗?
If you selected the first option, get CipherSweet.js.
如果您选择了第一个选项,请获取CipherSweet.js。
The documentation is available online. EncryptedField
is sufficient for most use cases, but the EncryptedRow
and EncryptedMultiRows
APIs may be easier if you have a lot of distinct fields you want to encrypt.
该文档可在线获取。EncryptedField
对于大多数用例来说已经足够了,但是如果您有很多不同的字段要加密,则EncryptedRow
和EncryptedMultiRows
API 可能会更容易。
With CipherSweet, you don't need to even know what a nonce/IV isto use it securely.
使用 CipherSweet,您甚至不需要知道 nonce/IV 是什么就可以安全地使用它。
Additionally, this handles int
/float
encryption without leaking facts about the contents through ciphertext size.
此外,这种处理int
/float
加密不会通过密文大小泄露有关内容的事实。
Otherwise, you'll want sodium-plus,which is a user-friendly frontend to various libsodium wrappers. Sodium-Plus allows you to write performant, asynchronous, cross-platform code that's easy to audit and reason about.
否则,您将需要钠加,它是各种 libsodium 包装器的用户友好前端。钠加允许您编写易于审计和推理的高性能、异步、跨平台代码。
To install sodium-plus, simply run...
要安装钠加,只需运行...
npm install sodium-plus
There is currently no public CDN for browser support. This will change soon. However, you can grab sodium-plus.min.js
from the latest Github releaseif you need it.
目前没有用于浏览器支持的公共 CDN。这将很快改变。但是,如果需要,您可以sodium-plus.min.js
从最新的 Github 版本中获取。
const { SodiumPlus } = require('sodium-plus');
let sodium;
(async function () {
if (!sodium) sodium = await SodiumPlus.auto();
let plaintext = 'Your message goes here';
let key = await sodium.crypto_secretbox_keygen();
let nonce = await sodium.randombytes_buf(24);
let ciphertext = await sodium.crypto_secretbox(
plaintext,
nonce,
key
);
console.log(ciphertext.toString('hex'));
let decrypted = await sodium.crypto_secretbox_open(
ciphertext,
nonce,
key
);
console.log(decrypted.toString());
})();
The documentation for sodium-plusis available on Github.
可以在 Github 上找到关于 salt -plus的文档。
If you'd like a step-by-step tutorial, this dev.to articlehas what you're looking for.
如果您需要分步教程,这篇 dev.to 文章可以满足您的需求。
回答by Jose A
Before implementying any of this, please see Scott Arciszewski's answer.
在实施任何这些之前,请参阅Scott Arciszewski 的回答。
I want you to be very carefulwith what I'm about to share as I have little to no security knowledge (There's a high chance that I'm misusing the API below), so I'd be more than welcome to update this answer with the help of the community.
我希望您对我将要分享的内容非常小心,因为我几乎没有安全知识(我很有可能滥用下面的 API),所以我非常欢迎更新这个答案在社区的帮助下。
As @richardtallent mentioned in his answer, there's support for the Web Crypto API, so this example uses the standard. As of this writing, there's a 95.88% of global browser support.
正如@richardtallent 在他的回答中提到的,支持 Web Crypto API,因此本示例使用标准。在撰写本文时,全球浏览器支持 95.88%。
I'm going to be sharing an example using the Web Crypto API
我将分享一个使用 Web Crypto API 的示例
Before we proceed, please note (Quoting from MDN):
在我们继续之前,请注意(引自 MDN):
This API provides a number of low-level cryptographic primitives. It's very easy to misuse them, and the pitfallsinvolved can be very subtle.
Even assuming you use the basic cryptographic functions correctly, secure key management and overall security system design are extremely hard to get rightand are generally the domain of specialist security experts.
Errors in security system design and implementation can make the security of the system completely ineffective.
If you're not sure you know what you are doing, you probably shouldn't be using this API.
此 API 提供了许多低级加密原语。这是很容易滥用它们,和陷阱参与可以非常微妙。
即使假设您正确使用了基本的加密功能,安全密钥管理和整体安全系统设计也很难做到正确,并且通常是专业安全专家的领域。
安全系统设计和实施中的错误会使系统的安全性完全失效。
如果您不确定自己知道自己在做什么,则可能不应该使用此 API。
I respect security a lot, and I even bolded additional parts from MDN... You've been warned
Now, to the actual example...
我非常尊重安全性,我什至在 MDN 中加粗了其他部分......你已经被警告
现在,到实际例子......
JSFiddle:
JSFiddle:
Found here: https://jsfiddle.net/superjose/rm4e0gqa/5/
在这里找到:https: //jsfiddle.net/superjose/rm4e0gqa/5/
Note:
笔记:
Note the use of await
keywords. Use it inside an async
function or use .then()
and .catch()
.
注意await
关键字的使用。在async
函数内部使用它或使用.then()
and .catch()
。
Generate the key:
生成密钥:
// https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey
// https://developer.mozilla.org/en-US/docs/Web/API/RsaHashedKeyGenParams
// https://github.com/diafygi/webcrypto-examples#rsa-oaep---generatekey
const stringToEncrypt = 'https://localhost:3001';
// https://github.com/diafygi/webcrypto-examples#rsa-oaep---generatekey
// The resultant publicKey will be used to encrypt
// and the privateKey will be used to decrypt.
// Note: This will generate new keys each time, you must store both of them in order for
// you to keep encrypting and decrypting.
//
// I warn you that storing them in the localStorage may be a bad idea, and it gets out of the scope
// of this post.
const key = await crypto.subtle.generateKey({
name: 'RSA-OAEP',
modulusLength: 4096,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {name: 'SHA-512'},
}, true,
// This depends a lot on the algorithm used
// Go to https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
// and scroll down to see the table. Since we're using RSA-OAEP we have encrypt and decrypt available
['encrypt', 'decrypt']);
// key will yield a key.publicKey and key.privateKey property.
Encrypt:
加密:
const encryptedUri = await crypto.subtle.encrypt({
name: 'RSA-OAEP'
}, key.publicKey, stringToArrayBuffer(stringToEncrypt))
console.log('The encrypted string is', encryptedUri);
Decrypt
解密
const msg = await crypto.subtle.decrypt({
name: 'RSA-OAEP',
}, key.privateKey, encryptedUri);
console.log(`Derypted Uri is ${arrayBufferToString(msg)}`)
Converting ArrayBuffer back and forth from String (Done in TypeScript):
从 String 来回转换 ArrayBuffer(在 TypeScript 中完成):
private arrayBufferToString(buff: ArrayBuffer) {
return String.fromCharCode.apply(null, new Uint16Array(buff) as unknown as number[]);
}
private stringToArrayBuffer(str: string) {
const buff = new ArrayBuffer(str.length*2) // Because there are 2 bytes for each char.
const buffView = new Uint16Array(buff);
for(let i = 0, strLen = str.length; i < strLen; i++) {
buffView[i] = str.charCodeAt(i);
}
return buff;
}
You can find more examples here (I'm not the owner): // https://github.com/diafygi/webcrypto-examples
您可以在此处找到更多示例(我不是所有者):// https://github.com/diafygi/webcrypto-examples
回答by Murtaza Hussain
Use SimpleCrypto
使用简单加密
Using encrypt() and decrypt()
使用 encrypt() 和decrypt()
To use SimpleCrypto, first create a SimpleCrypto instance with a secret key (password). Secret key parameter MUST be defined when creating a SimpleCrypto instance.
To encrypt and decrypt data, simply use encrypt() and decrypt() function from an instance. This will use AES-CBC encryption algorithm.
要使用 SimpleCrypto,首先创建一个带有密钥(密码)的 SimpleCrypto 实例。创建 SimpleCrypto 实例时必须定义密钥参数。
要加密和解密数据,只需使用实例中的 encrypt() 和decrypt() 函数即可。这将使用 AES-CBC 加密算法。
var _secretKey = "some-unique-key";
var simpleCrypto = new SimpleCrypto(_secretKey);
var plainText = "Hello World!";
var chiperText = simpleCrypto.encrypt(plainText);
console.log("Encryption process...");
console.log("Plain Text : " + plainText);
console.log("Cipher Text : " + cipherText);
var decipherText = simpleCrypto.decrypt(cipherText);
console.log("... and then decryption...");
console.log("Decipher Text : " + decipherText);
console.log("... done.");
回答by Dmytro Lopushanskyy
CryptoJS is no longer supported. If you want to continue using it, you may switch to this url:
不再支持 CryptoJS。如果你想继续使用它,你可以切换到这个网址:
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
回答by Omi
Simple functions,
简单的功能,
function?Encrypt(value)?
{
var result="";
??for(i=0;i<value.length;i++)
??{
if(i<value.length-1)
{
result+=value.charCodeAt(i)+10;
result+="-";
}
else
{
result+=value.charCodeAt(i)+10;
}
??}
??return?result;
}
function?Decrypt(value)
{
var result="";
var array = value.split("-");
??for(i=0;i<array.length;i++)
??{
????result+=String.fromCharCode(array[i]-10);
??}
??return?result;
}