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

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

理想情况下,我可以做一些

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

来生成编码的字符串,诸如此类

var sensical = decrypt(gibberish, key);

稍后再解码。

到目前为止,我看到的是: http://bitwiseshiftleft.github.io/sjcl/

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


当前回答

简单的函数:

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;
} 

其他回答

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

这些是函数:

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

不再支持CryptoJS。如果你想继续使用它,你可以切换到这个url:

<script src=“https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js”></script>

2021年12月更新

使用MDN Web Docs提供的加密api:

https://developer.mozilla.org/en-US/docs/Web/API/Crypto


旧的答案

使用SimpleCrypto

使用encrypt()和decryption ()

要使用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.");

现有的利用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只是为您提供了一些简单的选项,以实现最大的安全性和最少的api。

Crypto_box () / crypto_box_open()提供经过身份验证的公钥加密。 所讨论的算法结合了X25519 (ECDH over Curve25519)和XSalsa20-Poly1305,但是您不需要知道(甚至不需要关心)就可以安全地使用它 Crypto_secretbox () / crypto_secretbox_open()提供共享密钥认证加密。 这里讨论的算法是XSalsa20-Poly1305,但您不需要知道/关心

此外,libsodium在许多流行的编程语言中都有绑定,因此很可能只有在尝试与另一种编程堆栈进行互操作时,libsodium才能工作。而且,libsodium的速度非常快,而且不会牺牲安全性。

如何在JavaScript中使用Libsodium ?

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

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

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

相关文档可以在网上找到。EncryptedField对于大多数用例来说已经足够了,但是如果有很多不同的字段需要加密,那么EncryptedRow和EncryptedMultiRows api可能会更容易一些。

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

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

否则,您将需要钠加,这是一个用户友好的前端,以各种libsodium包装。Sodium-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()); })();

关于sodium-plus的文档可以在Github上找到。

如果您想要一个循序渐进的教程,这篇dev.to文章可以满足您的需要。

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>