我有兴趣构建一个供个人使用的小型应用程序,该应用程序将使用JavaScript在客户端加密和解密信息。加密的信息将存储在服务器上的数据库中,但不会存储在解密版本中。
它不必具有超级duper的安全性,但是我想使用当前不间断的算法。
理想情况下,我可以做类似的事情
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>
这是一个可靠的加密库,具有很多功能。它实现了哈希,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
或使用其他CDN,例如https://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:
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'
利用SJCL,CryptoJS和/或WebCrypto的现有答案不一定是错误的,但是它们并不像您最初怀疑的那样安全。通常,您要使用libsodium。首先,我将解释原因,然后再解释。
为什么不选择SJCL,CryptoJS,WebCrypto等?
简短的答案:为了使您的加密实际上是安全的,这些库希望您做出太多选择,例如,块密码模式(CBC,CTR,GCM;如果您不能确定我刚刚列出的三个中的哪一个是安全的,使用和在什么样的约束,你不应该有这种选择的负担在所有)。
除非您的职位是密码学工程师,否则您就无法安全地实施它。
为什么要避免使用CryptoJS?
CryptoJS提供了一些构建基块,希望您知道如何安全地使用它们。它甚至默认为CBC模式(archived)。
为什么CBC模式不好?
为什么要避免使用WebCrypto?
WebCrypto是委员会制定的杂烩标准,目的是与密码学工程正交。具体来说,WebCrypto旨在取代Flash,而不是提供安全性。
为什么要避免SJCL?
SJCL的公共API和文档恳求用户使用人类记住的密码来加密数据。如果有的话,这几乎是您在现实世界中想要做的事情。
此外:其默认的PBKDF2舍入计数大约是您希望的86倍。AES-128-CCM可能还不错。
在以上三个选项中,SJCL哭泣的可能性最小。但是有更好的选择。
为什么Libsodium更好?
您无需在密码模式,哈希函数和其他不必要选项的菜单之间进行选择。您绝不会冒险修改参数并从协议中删除所有安全性。
相反,libsodium只是为您提供了针对最大安全性和简约API进行了调整的简单选项。
crypto_box()
/crypto_box_open()
提供经过身份验证的公钥加密。- 有问题的算法将X25519(Curve25519上的ECDH)和XSalsa20-Poly1305结合在一起,但是您无需知道(甚至不在乎)就可以安全地使用它
crypto_secretbox()
/crypto_secretbox_open()
提供共享密钥验证的加密。- 有问题的算法是XSalsa20-Poly1305,但是您不需要知道/关心
另外,libsodium具有数十种流行编程语言的绑定,因此libsodium很可能在尝试与另一个编程堆栈进行互操作时才可以工作。同样,libsodium往往非常快而不会牺牲安全性。
如何在JavaScript中使用Libsodium?
首先,您需要决定一件事:
- 您是否只想加密/解密数据(也许仍然以某种方式安全地使用数据库查询中的纯文本),而不必担心细节?要么...
- 您需要实施特定协议吗?
如果选择了第一个选项,请获取CipherSweet.js。
该文档可在线获得。EncryptedField
在大多数情况下就足够了,但是如果您要加密很多不同的字段,则EncryptedRow
和EncryptedMultiRows
API可能会更容易。
使用CipherSweet,您甚至不需要知道安全地使用它的随机数/ IV。
此外,这可以处理int
/float
加密,而不会通过密文大小泄露有关内容的事实。
否则,您将需要sodium-plus,它是各种libsodium包装器的用户友好前端。使用Sodium-Plus,您可以编写易于审计和推理的高性能,异步,跨平台代码。
要安装sodium-plus,只需运行...
npm install sodium-plus
当前没有用于浏览器支持的公共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());
})();
钠加的文档可在Github上找到。
如果您需要分步教程,那么这篇dev.to文章将为您提供所需的内容。
现代浏览器现在支持该crypto.subtle
API,该API使用以下方法之一提供本机加密和解密功能(不少于异步!):AES-CBC,AES-CTR,AES-GCM或RSA-OAEP。
https://www.w3.org/TR/WebCryptoAPI/#dfn-Crypto
在实施上述任何一项之前,请参阅Scott Arciszewski的答案。
我希望您对我将要分享的内容非常小心,因为我几乎没有安全知识(很有可能我误用了下面的API),所以我们非常乐意更新此答案在社区的帮助下。
正如@richardtallent在他的回答中提到的那样,Web Crypto API受到支持,因此本示例使用该标准。在撰写本文时,全球浏览器支持达到95.88%。
我将使用Web Crypto 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)}`)
从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;
}
您可以在此处找到更多示例(我不是所有者):// https://github.com/diafygi/webcrypto-examples
不再支持CryptoJS。如果您想继续使用它,可以切换到以下网址:
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
使用crypto()和解密()
要使用SimpleCrypto,首先要创建一个带有密钥(密码)的SimpleCrypto实例。创建SimpleCrypto实例时必须定义密钥参数。
要加密和解密数据,只需使用实例中的crypto()和crypto()函数。这将使用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;
}
文章标签:encryption , javascript
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!