JavaScript字符串加密和解密?

jer*_*ahs 126 javascript encryption

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

它不一定非常安全,但我想使用当前不间断的算法.

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

var gibberish = encrypt(string, salt, key);
Run Code Online (Sandbox Code Playgroud)

生成编码的字符串,等等

var sensical = decrypt(gibberish, key);
Run Code Online (Sandbox Code Playgroud)

稍后解码.

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

我应该看看其他任何图书馆?

Tom*_*rda 142

 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);
Run Code Online (Sandbox Code Playgroud)
Full working sample actually is:

    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></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>
Run Code Online (Sandbox Code Playgroud)

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

小智 54

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>
Run Code Online (Sandbox Code Playgroud)

至于安全性,在我写作的那一刻,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

  • 但是,我们如何确保“秘密”密码短语呢? (2认同)

Jor*_*lom 26

我创建了一个简单的文本密码/解密工具。不依赖任何外部库。

这些是功能

let cipher = salt => {
    let textToChars = text => text.split('').map(c => c.charCodeAt(0))
    let byteHex = n => ("0" + Number(n).toString(16)).substr(-2)
    let applySaltToChar = code => textToChars(salt).reduce((a,b) => a ^ b, code)    

    return text => text.split('')
        .map(textToChars)
        .map(applySaltToChar)
        .map(byteHex)
        .join('')
}

let decipher = salt => {
    let textToChars = text => text.split('').map(c => c.charCodeAt(0))
    let saltChars = textToChars(salt)
    let 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('')
}
Run Code Online (Sandbox Code Playgroud)

您可以如下使用它们:

// To create a cipher
let myCipher = cipher('mySecretSalt')

//Then cipher any text:
myCipher('the secret string')   // --> "7c606d287b6d6b7a6d7c287b7c7a61666f"

//To decipher, you need to create a decipher and use it:
let myDecipher = decipher('mySecretSalt')
myDecipher("7c606d287b6d6b7a6d7c287b7c7a61666f")    // --> 'the secret string'
Run Code Online (Sandbox Code Playgroud)

  • let myDecipher = decipher('CartelSystem') - 这个盐也能解密字符串。您不必知道确切的词“mySecretSalt” (6认同)
  • 又一篇有人盲目使用“let”的帖子。︎ (2认同)
  • 这不是a)超级破碎和不安全b)“盐”实际上是你的“秘密密钥”,因为盐不应该是私有的?我认为发布这样的代码而不加任何评论是非常危险的,因为这个有趣的代码不适合任何现实世界的使用。点赞数之多令人担忧。https://crypto.stackexchange.com/questions/11466/randomly- generated-key-reused-with-xor (2认同)
  • 好吧,至少他们使用了健全的加密货币。你所做的基本上是凯撒密码(对每个角色应用相同的密钥)https://en.wikipedia.org/wiki/Caesar_cipher#Breaking_the_cipher 关于其他答案......我希望很明显,有一种叫做“秘密”预计将保密(由用户) (2认同)

ric*_*ent 16

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

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

  • 在以上选项中,只有AES-GCM和RSA-OAEP是合理的。:( (2认同)
  • AES-GCM 示例:https://github.com/diafygi/webcrypto-examples#aes-gcm---generatekey (2认同)

Met*_*ron 14

此代码基于@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("");
};
Run Code Online (Sandbox Code Playgroud)

你用它

// encrypting
const encrypted_text = crypt("salt", "Hello"); // -> 426f666665

// decrypting
const decrypted_string = decrypt("salt", "426f666665"); // -> Hello
Run Code Online (Sandbox Code Playgroud)

  • 你做的非常出色 (2认同)

小智 11

crypt.subtle AES-GCM,独立,经过测试:

async function aesGcmEncrypt(plaintext, password)

async function aesGcmDecrypt(ciphertext, password) 
Run Code Online (Sandbox Code Playgroud)

https://gist.github.com/chrisveness/43bcda93af9f646d083fad678071b90a

  • 谢谢!很难找到使用本机浏览器 Crypto API 的简单易用的示例。唯一的限制是 IE11... (2认同)

Sco*_*ski 10

利用SJCL,CryptoJS和/或WebCrypto的现有答案不一定是错误的,但是它们并不像您最初怀疑的那样安全。通常,您要使用libsodium。首先,我将解释原因,然后再解释。

为什么不选择SJCL,CryptoJS,WebCrypto等?

简短的答案:为了使您的加密实际上是安全的,这些库希望您做出太多选择,例如块密码模式(CBC,CTR,GCM;如果您不能确定我刚刚列出的三种加密方法中的哪一种是安全的),使用和在什么样的约束,你不应该有这种选择的负担在所有)。

除非您的职位是密码学工程师,否则您就无法安全地实施它。

为什么要避免使用CryptoJS?

CryptoJS提供了一些构建基块,希望您知道如何安全地使用它们。它甚至默认为CBC模式archived)。

为什么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(Curve25519上的ECDH)和XSalsa20-Poly1305结合在一起,但是您无需知道(甚至不在乎)就可以安全地使用它
  • crypto_secretbox()/ crypto_secretbox_open()提供共享密钥验证的加密。
    • 有问题的算法是XSalsa20-Poly1305,但是您不需要知道/关心

另外,libsodium具有数十种流行编程语言的绑定,因此libsodium很可能在尝试与另一个编程堆栈进行互操作时才可以工作。同样,libsodium往往非常快而不会牺牲安全性。

如何在JavaScript中使用Libsodium?

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

  1. 您是否只想加密/解密数据(也许仍然以某种方式安全地使用数据库查询中的纯文本),而不必担心细节?要么...
  2. 您需要实施特定协议吗?

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

该文档可在线获得EncryptedField在大多数情况下就足够了,但是如果您要加密很多不同的字段,则EncryptedRowEncryptedMultiRowsAPI可能会更容易。

有了CipherSweet,您甚至不需要知道安全地使用它的随机数/ IV

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

否则,您将需要sodium-plus它是各种libsodium包装器的用户友好前端。使用Sodium-Plus,您可以编写易于审计和推理的高性能,异步,跨平台代码。

要安装sodium-plus,只需运行...

npm install sodium-plus
Run Code Online (Sandbox Code Playgroud)

当前没有用于浏览器支持的公共CDN。这将很快改变。但是,如果需要,可以sodium-plus.min.js最新的Github版本中获取。

钠加的文档可在Github上找到。

如果您需要分步教程,那么这篇dev.to文章将为您提供所需的内容。

  • 您与钠项目有何关系? (9认同)
  • 投反对票,因为零指示/确认他是 GitHub 上该项目的维护者(可能是负责人)(偏见)...... (7认同)
  • Sodium 太像一个黑匣子了,而且它的文档也很糟糕。如果解密器和加密器是同一个实体,那没问题,但对于传输的标准化加密来说,这是很糟糕的。 (2认同)

Jos*_*e A 7

在实施任何这些之前,请参阅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()and .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.
Run Code Online (Sandbox Code Playgroud)

加密:

    const encryptedUri = await crypto.subtle.encrypt({
      name: 'RSA-OAEP'
    }, key.publicKey, stringToArrayBuffer(stringToEncrypt))
    
    console.log('The encrypted string is', encryptedUri);


Run Code Online (Sandbox Code Playgroud)

解密

   const msg = await  crypto.subtle.decrypt({
      name: 'RSA-OAEP',
    }, key.privateKey, encryptedUri);
    console.log(`Derypted Uri is ${arrayBufferToString(msg)}`)
Run Code Online (Sandbox Code Playgroud)

从 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;
  }
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到更多示例(我不是所有者):// https://github.com/diafygi/webcrypto-examples


Yaz*_*jar 7

您可以使用这些函数,第一个加密非常简单,因此您只需调用该函数并发送您想要加密的文本,然后从 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 
Run Code Online (Sandbox Code Playgroud)


Mur*_*ain 5

2021 年 12 月更新

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

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


旧答案

使用简单加密

使用加密()和解密()

要使用 SimpleCrypto,首先使用密钥(密码)创建一个 SimpleCrypto 实例。创建 SimpleCrypto 实例时必须定义密钥参数。

要加密和解密数据,只需使用实例中的 加密() 和解密() 函数即可。这将使用 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.");
Run Code Online (Sandbox Code Playgroud)

  • SimpleCrypto 使用[未经身份验证的 AES-CBC](https://github.com/danang-id/simple-crypto-js/issues/123),因此容易受到选择密文攻击。 (5认同)