JavaScript 字符串加密和解密?

IT技术 encryption javascript
2021-01-29 04:03:57

我有兴趣构建一个供个人使用的小应用程序,它将使用 JavaScript 在客户端加密和解密信息。加密信息将存储在服务器上的数据库中,但绝不会是解密版本。

它不必是超级安全的,但我想使用当前未破坏的算法。

理想情况下,我可以做类似的事情

var gibberish = encrypt(string, salt, key);

生成编码字符串,以及类似的东西

var sensical = decrypt(gibberish, key);

稍后解码。

到目前为止,我已经看到了这个:http : //bitwiseshiftleft.github.io/sjcl/

我应该看看其他图书馆吗?

6个回答

 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>

Encrypted 实际上是一个对象,但是可以调用 encrypted.toString() 来获取字符串。稍后您将能够解密该字符串:jsbin.com/kofiqokoku/1
2021-03-14 04:03:57
我会选择这个:github.com/brix/crypto-js它也可以通过 NPM 获得
2021-03-14 04:03:57
但是我们如何才能保护秘密密码呢?
2021-03-31 04:03:57
似乎crypto js是一个存档项目。github 上有一个克隆:github.com/sytelus/CryptoJS但已经两年没有更新了。这仍然是 js 加密的最佳选择吗?
2021-03-31 04:03:57
@stom 存储方式和位置取决于您。我不知道是否有真正安全的方式将它存储在浏览器中。从服务器请求它们并存储在内存中。
2021-04-06 04:03:57

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

或使用其他 CDN,如https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/aes-min.js

但是我们如何才能保护秘密密码呢?
2021-03-13 04:03:57
@shaijut 你没有。在加密/解密明文时,您甚至不会将它保存在 RAM 中以外的任何地方。密码应仅存储在用户的大脑(或密码管理器)中
2021-03-17 04:03:57
在播放了一点之后,组件是分离的部分。您需要知道要使用哪些组件(以及按什么顺序)才能使其工作。汇总文件包含您只需使用一个脚本参考即可使其工作所需的一切(因为已经完成了艰苦的工作,所以效果会更好)。
2021-03-20 04:03:57
3.1.2文件夹下的rollups和components有什么区别?
2021-04-01 04:03:57

我创建了一个不安全但简单的文本密码/解密实用程序。不依赖任何外部库。

这些是功能:

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"))

好吧,至少他们使用声音加密。你所做的基本上是一个 Caesar Chipher(对每个字符应用相同的密钥)en.wikipedia.org/wiki/Caesar_cipher#Breaking_the_cipher关于其他答案......我希望很明显,所谓的“秘密”是预计保密(由用户)
2021-03-14 04:03:57
另一个帖子,有人盲目使用let. 😒︎
2021-03-24 04:03:57
的长度byteHex应该扩展到,4因为最大值charCode2^16 - 1(i.e. 65535),这将是ffff编码为基数 16 时的长度。修复:const byteHex = n => ("000" + Number(n).toString(16)).substr(-4);return encoded => encoded.match(/.{1,4}/g)
2021-04-04 04:03:57
let myDecipher = decipher('CartelSystem') - 这个盐也能解密字符串。您不必知道“mySecretSalt”这个确切的词
2021-04-06 04:03:57
这不是 a) 超级破碎和不安全并且 b) “盐”实际上是您的“秘密密钥”,因为盐不会是私有的?我认为发布这样的代码而没有任何评论是非常危险的,这个有趣的代码不适合任何现实世界使用。赞成票的数量令人担忧。crypto.stackexchange.com/questions/11466/...
2021-04-07 04:03:57

利用 SJCL、CryptoJS 和/或 WebCrypto 的现有答案不一定是错误的,但它们并不像您最初怀疑的那样安全。通常你想使用 libsodium首先我将解释为什么,然后解释如何。

为什么不是 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 更好?

您无需在密码模式菜单、散列函数和其他不必要的选项之间进行选择。您永远不会冒着搞砸参数和从协议中删除所有安全性的风险

相反,libsodium只是为您提供针对最大安全性和简约 API 进行调整的简单选项。

  • crypto_box()/crypto_box_open()提供经过身份验证的公钥加密。
    • 有问题的算法结合了 X25519(ECDH over Curve25519)和 XSalsa20-Poly1305,但你不需要知道(甚至关心)它来安全地使用它
  • crypto_secretbox()/crypto_secretbox_open()提供共享密钥认证加密。
    • 有问题的算法是 XSalsa20-Poly1305,但你不需要知道/关心

此外,libsodium绑定了数十种流行的编程语言,因此当尝试与另一个编程堆栈进行互操作时,libsodium 很可能会正常工作此外,libsodium 在不牺牲安全性的情况下往往非常快。

如何在 JavaScript 中使用 Libsodium?

首先,你需要决定一件事:

  1. 您是否只想加密/解密数据(并且可能仍然以某种方式安全地在数据库查询中使用明文)而不担心细节?或者...
  2. 您需要实现特定的协议吗?

如果您选择了第一个选项,请获取CipherSweet.js

该文档可在线获取EncryptedField对于大多数用例来说已经足够了,但是如果您有很多不同的字段要加密,则EncryptedRowEncryptedMultiRowsAPI 可能会更容易。

使用 CipherSweet,您甚至不需要知道 nonce/IV 是什么就可以安全地使用它。

此外,这种处理int/float加密不会通过密文大小泄露有关内容的事实。

否则,您将需要钠加它是各种 libsodium 包装器的用户友好前端。钠加允许您编写易于审计和推理的高性能、异步、跨平台代码。

要安装钠加,只需运行...

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 上找到关于 salt -plus的文档

如果您需要分步教程,这篇 dev.to 文章可以满足您的需求。

投反对票,因为他是 GitHub 上项目的维护者(可能是负责人)(偏见),因此没有零指示/承认......
2021-03-23 04:03:57
@MaciejUrbański 是的,他非常好。
2021-03-29 04:03:57
更持久的反对 WebCrypto 的论点会很好-您似乎只是链接了匿名评论,说 WebCrypto 的设计并未考虑安全性
2021-04-05 04:03:57
你和钠项目有什么关系?
2021-04-09 04:03:57

现代浏览器现在支持crypto.subtleAPI,它使用以下方法之一提供本机加密和解密功能(异步不少!):AES-CBC、AES-CTR、AES-GCM 或 RSA-OAEP。

https://www.w3.org/TR/WebCryptoAPI/#dfn-Crypto

crypt.subtle AES-GCM,自包含,经过测试: async function aesGcmEncrypt(plaintext, password) async function aesGcmDecrypt(ciphertext, password) gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a
2021-03-23 04:03:57
在上述选项中,只有 AES-GCM 和 RSA-OAEP 是合理的。:(
2021-03-25 04:03:57