JavaScript字符串加密和解密
JavaScript string encryption and decryption?
我有兴趣构建一个小型个人应用程序,该应用程序将使用JavaScript在客户端加密和解密信息。加密的信息将存储在服务器上的数据库中,但永远不会是解密的版本。
它不一定是超级安全的,但我想使用目前未中断的算法。
理想情况下,我可以做一些类似的事情
var gibberish = encrypt(string, salt, key);
生成编码字符串,以及类似的东西
var sensical = decrypt(gibberish, key);
以便稍后对其进行解码。
到目前为止,我已经看到:http://bitwiseshiftleft.github.io/sjcl/
我还应该看看其他图书馆吗?
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>
CryptoJS怎么样?
这是一个坚实的加密库,有很多功能。它实现了散列器、HMAC、PBKDF2和密码。在这种情况下,你需要密码。查看项目主页上的快速入门技巧。
你可以用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>
至于安全性,在我写这篇文章的时候,AES算法被认为是完整的
编辑:
似乎在线URL已关闭&您可以使用下载的文件进行加密从下面给定的链接&将相应的文件放在应用程序的根文件夹中。
https://code.google.com/archive/p/crypto-js/downloads
或使用其他类似CDNhttps://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js
我创建了一个不安全但简单的文本密码/解密实用程序。没有与任何外部库的依赖关系。
这些是功能:
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('');
}
// To create a cipher
const myCipher = cipher('mySecretSalt')
//Then cipher any text:
console.log(myCipher('the secret string'))
//To decipher, you need to create a decipher and use it:
const myDecipher = decipher('mySecretSalt')
console.log(myDecipher("7c606d287b6d6b7a6d7c287b7c7a61666f"))
此代码基于@Jorgeblom的上述答案
@Jorgeblom我的伙计,这是一个奇妙的小型加密库:D我有点碰它,因为我不喜欢我必须分配盐并再次调用它,但总的来说,对于我的需求来说,这是绝对完美的。
const crypt = (salt, text) => {
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
.split("")
.map(textToChars)
.map(applySaltToChar)
.map(byteHex)
.join("");
};
const decrypt = (salt, encoded) => {
const textToChars = (text) => text.split("").map((c) => c.charCodeAt(0));
const applySaltToChar = (code) => textToChars(salt).reduce((a, b) => a ^ b, code);
return encoded
.match(/.{1,2}/g)
.map((hex) => parseInt(hex, 16))
.map(applySaltToChar)
.map((charCode) => String.fromCharCode(charCode))
.join("");
};
你用它
// encrypting
const encrypted_text = crypt("salt", "Hello"); // -> 426f666665
// decrypting
const decrypted_string = decrypt("salt", "426f666665"); // -> Hello
利用SJCL、CryptoJS和/或WebCrypto的现有答案不一定是错误的,但它们并不像您最初怀疑的那样安全。一般来说,你想使用利钠。首先我会解释为什么,然后解释如何。
为什么不SJCL,CryptoJS,WebCrypto等
简短回答:为了使加密真正安全,这些库希望您做出太多选择,例如分组密码模式(CBC、CTR、GCM;如果您无法判断我刚才列出的三种模式中的哪一种是安全的,以及在什么限制下,您根本不应该有这种选择的负担)。
除非你的职位是密码工程师,否则你很难安全地实现它。
为什么要避免CryptoJS
CryptoJS提供了一些构建块,希望您知道如何安全地使用它们。它甚至默认为CBC模式(存档)。
为什么CBC模式不好
阅读这篇关于AES-CBC漏洞的文章。
为什么要避免WebCrypto
WebCrypto是一个由委员会设计的便签标准,用于与密码学工程正交的目的。具体来说,WebCrypto旨在取代Flash,而不是提供安全性。
为什么要避免SJCL
SJCL的公共API和文档要求用户使用人工密码加密数据。这是你在现实世界中很少想做的事情。
此外:它默认的PBKDF2轮数大约是你想要的86倍。AES-128-CCM可能很好。
在以上三种选择中,SJCL最不可能以眼泪收场。但也有更好的选择。
为什么利钠钠更好
您不需要在密码模式、哈希函数和其他不必要的选项菜单之间进行选择。您永远不会冒险搞砸您的参数并从您的协议中删除所有安全性。
相反,libsodium只是为您提供了一些经过优化的简单选项,以实现最大的安全性和最小的API。
crypto_box()
/crypto_box_open()
提供经过身份验证的公钥加密。- 有问题的算法结合了X25519(Curve25519上的ECDH)和XSalsa20-Poly1305,但您不需要知道(甚至不需要关心)这一点就可以安全地使用它
crypto_secretbox()
/crypto_secretbox_open()
提供共享密钥认证加密。- 有问题的算法是XSalsa20-Poly1305,但您不需要知道/关心
此外,libsodium在数十种流行的编程语言中都有绑定,因此当试图与另一个编程堆栈进行互操作时,libsodeum很可能只工作。此外,在不牺牲安全性的情况下,libsodium往往速度非常快。
如何在JavaScript中使用Libsodium
首先,你需要决定一件事:
- 你只是想加密/解密数据(也许仍然可以在数据库查询中安全地使用明文)而不担心细节吗?或者
- 您需要实施特定的协议吗
如果您选择了第一个选项,则获取CipherSweet.js.
该文档可在线获取。EncryptedField
对于大多数用例来说已经足够了,但是如果有很多不同的字段要加密,那么EncryptedRow
和EncryptedMultiRows
API可能会更容易。
使用CipherSweet,您甚至不需要知道nonce/IV是什么就可以安全地使用它。
此外,它处理int
/float
加密,而不会通过密文大小泄露有关内容的事实。
否则,您将需要钠加,这是各种libsodium包装的用户友好前端。Nadium Plus允许您编写易于审计和推理的高性能异步跨平台代码。
要安装钠+,只需运行。。。
npm install sodium-plus
目前没有用于浏览器支持的公共CDN。这种情况很快就会改变。但是,如果需要的话,你可以从最新的Github版本中获取sodium-plus.min.js
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());
})();
钠加的文档可以在Github上找到。
如果你想要一个循序渐进的教程,这篇dev.to文章有你想要的。
现代浏览器现在支持crypto.subtle
API,它使用以下方法之一提供本机加密和解密功能(异步!):AES-CBC、AES-CTR、AES-GCM或RSA-OAEP。
https://www.w3.org/TR/WebCryptoAPI/#dfn-加密
crypt.subtable AES-GCM,自包含,已测试:
async function aesGcmEncrypt(plaintext, password)
async function aesGcmDecrypt(ciphertext, password)
https://gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a
在实现这些之前,请参阅Scott Arciszewski的回答。
我希望非常小心我将要分享的内容,因为我几乎没有安全知识(我很有可能滥用了下面的API),所以非常欢迎在社区的帮助下更新这个答案。
正如@richardtallent在他的回答中提到的,有对WebCryptoneneneba API的支持,所以这个示例使用该标准。截至本文撰写之时,全球浏览器支持率为95.88%。
我将分享一个使用WebCryptoneneneba API 的例子
在我们继续之前,请注意(引用MDN):
此API提供了许多低级加密原语。很容易滥用它们,而且所涉及的陷阱可能非常微妙。
即使假设您正确使用了基本的加密功能,安全密钥管理和整体安全系统设计也极难做到,而且通常是专业安全专家的领域。
安全系统设计和实现中的错误会使系统的安全性完全失效。
如果您不确定自己知道自己在做什么,则可能不应该使用此API。
我非常尊重安全性,我甚至大胆地使用了MDN的附加部件您已收到警告
现在,以实际的例子。。。
JSFiddle:
在此处找到:https://jsfiddle.net/superjose/rm4e0gqa/5/
注:
注意await
关键字的使用。在async
函数中使用它,或者使用.then()
和.catch()
。
生成密钥:
// 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.
加密:
const encryptedUri = await crypto.subtle.encrypt({
name: 'RSA-OAEP'
}, key.publicKey, stringToArrayBuffer(stringToEncrypt))
console.log('The encrypted string is', encryptedUri);
解密
const msg = await crypto.subtle.decrypt({
name: 'RSA-OAEP',
}, key.privateKey, encryptedUri);
console.log(`Derypted Uri is ${arrayBufferToString(msg)}`)
从字符串来回转换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;
}
你可以在这里找到更多的例子(我不是所有者)://https://github.com/diafygi/webcrypto-examples
你可以使用这些函数,它非常容易第一个用于加密的函数,所以你只需调用该函数并发送你想要加密的文本,然后从encryptWithAES函数中获取结果并将其发送到解密函数,如下所示:
const CryptoJS = require("crypto-js");
//The Function Below To Encrypt Text
const encryptWithAES = (text) => {
const passphrase = "My Secret Passphrase";
return CryptoJS.AES.encrypt(text, passphrase).toString();
};
//The Function Below To Decrypt Text
const decryptWithAES = (ciphertext) => {
const passphrase = "My Secret Passphrase";
const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase);
const originalText = bytes.toString(CryptoJS.enc.Utf8);
return originalText;
};
let encryptText = encryptWithAES("YAZAN");
//EncryptedText==> //U2FsdGVkX19GgWeS66m0xxRUVxfpI60uVkWRedyU15I=
let decryptText = decryptWithAES(encryptText);
//decryptText==> //YAZAN
CryptoJS不再受支持。如果你想继续使用它,你可以切换到这个网址:
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
2021年12月更新
使用MDN Web文档:提供的加密api
https://developer.mozilla.org/en-US/docs/Web/API/Crypto
老答案
使用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.");
简单函数:
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;
}
- 制作我自己的加密/解密系统
- 使用 SJCL 在 Javascript 中加密,在 PHP 中解密
- AES-CTR 在 Go 中加密,在 CryptoJS 中解密
- react本机AES加密匹配Java解密算法
- RSA使用jsencrypt加密,使用bouncy-castle解密
- 用JavaScript加密字符串,用RSA技术用PHP解密
- RSA在JS和Python之间加密和解密(pycrypto)
- 与PHP解密相匹配的Javascript加密
- javascript中的AES加密和java中的解密
- 如何使用forge加密和解密pdf blob并存储在localStorage中
- 用PHP mcrypt加密的Javascript解密Blowfish CBC
- 在Visual Basic中加密AES,然后在服务器到客户端中解密AES
- Node.js对外部PHP aes-256-cbc进行解密,然后对其进行加密
- javascript->php加密解密-需要澄清和方法请
- python解密在jsencrypt中加密的文本
- AES JavaScript加密和Java解密
- 在 PHP 中加密字符串,在 Node.js 中解密
- 使用 Python 加密并在 jQuery/Javascript 中解密
- 如何使用 CryptoJS 解密加密字符串 (SHA512)
- 加密 JS 在解密加密消息时引发的异常