JavaScript字符串加密和解密?

时间:2013-08-16 17:40:22

标签: encryption javascript

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

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

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

这样的事情
var gibberish = encrypt(string, salt, key);

生成编码的字符串,类似

var sensical = decrypt(gibberish, key);

稍后解码。

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

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

12 个答案:

答案 0 :(得分:127)



 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"></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>
&#13;
&#13;
&#13;

答案 1 :(得分:48)

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算法被认为是不间断的

修改:

似乎在线网址已关闭&amp;你可以使用下面给出的链接&amp; amp;将相应的文件放在应用程序的根文件夹中。

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 :(得分:12)

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

为什么不使用SJCL,CryptoJS,WebCrypto等?

简短答案:为了使加密真正安全,这些库希望您做出过多选择,例如分组密码模式(CBC,CTR,GCM;如果您不能确定我刚刚列出的三种密码中的哪一种是安全使用的,并且在什么限制下使用,则完全不必为这种选择负担< / em>)。

除非您的职位是密码学工程师,否则您安全实施该任务的可能性不大。

为什么要避免使用CryptoJS?

CryptoJS提供了一些构建块,希望您知道如何安全地使用它们。 It even defaults to CBC modearchived)。

为什么CBC模式不好?

阅读this write-up on AES-CBC vulnerabilities

为什么要避免使用WebCrypto?

WebCrypto是委员会制定的杂烩标准,用于与密码学工程正交的目的。具体来说,WebCrypto was meant to replace Flash, not provide security

为什么要避免SJCL?

SJCL的公共API和文档恳求用户使用人类记住的密码来加密数据。在现实世界中,这几乎是您想做的事情。

此外:其默认的PBKDF2轮次计数约为86 times as small as you want it to be。 AES-128-CCM可能很好。

在上述三个选项中,SJCL哭泣的可能性最小。但是还有更好的选择。

为什么锂钠更好?

您无需在密码模式,哈希函数和其他不必要选项的菜单之间进行选择。您将永远不会risk screwing up your parameters and removing all security from your protocol

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

  • crypto_box() / crypto_box_open()提供经过身份验证的公钥加密。
    • 有问题的算法将X25519(Curve25519上的ECDH)和XSalsa20-Poly1305结合在一起,但是您不必知道(甚至不在乎)安全地使用它
  • crypto_secretbox() / crypto_secretbox_open()提供共享密钥身份验证加密。
    • 有问题的算法是XSalsa20-Poly1305,但您无需了解/护理

此外,libsodium具有bindings in dozens of popular programming languages,因此在尝试与另一个编程堆栈进行互操作时,libsodium很可能会正常工作。此外,libsodium往往会非常快而又不牺牲安全性。

如何在JavaScript中使用Libsodium?

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

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

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

文档为available onlineEncryptedField足以满足大多数使用情况,但是如果您有很多要加密的字段,则EncryptedRowEncryptedMultiRows API可能会更容易。

有了CipherSweet,您甚至不必知道随机数/ IV是什么,就可以安全地使用它。

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

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

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

npm install sodium-plus

当前没有用于浏览器支持的公共CDN。这将很快改变。但是,您可以根据需要从the latest Github release抢购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上提供了sodium-plus的文档。

如果您要逐步学习,this dev.to article会提供您所需的内容。

答案 3 :(得分:11)

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

这些是功能

git pull

您可以按以下方式使用它们:

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('')
}

答案 4 :(得分:9)

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

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

答案 5 :(得分:9)

此代码基于@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

答案 6 :(得分:3)

不再支持CryptoJS。如果您想继续使用它,可以切换到此网址:

import requests my_url = requests.get('http://www.vivoelfutbol.com.mx/futbolmexicano.php') from bs4 import BeautifulSoup as soup page_soup = soup(my_url.text, "html.parser") containers = page_soup.findAll("div", {"class":"bordermitad"})[0].findAll("div", {"class":"det"}) #dates = page_soup.findAll("div", {"class":"bordermitad"})[0].findAll("div", {"class":"tif"}) #for result in dates: #date = result.text.strip() #print(date + "\n") calendario = [] for result2 in containers: time = result2.find('div', {'class':'hor'}).text hometeam = result2.find('a').text score = result2.find('a', {'title':'Analisis y Antecedentes'}).text awayteam = result2.find('div', {'class':'eqvc'}).text calendario.append((time, hometeam, score, awayteam)) #print("\n" + time + " " + hometeam + " " + score + " " + awayteam + "\n") import os import pandas as pd df = pd.DataFrame(calendario, columns=['Hora', 'Equipo_1', 'Marcador', 'Equipo 2']) if not os.path.isfile('Marcadores_futbol_mexico.csv'): df.to_csv('Marcadores_futbol_mexico.csv', index=True) else: df.to_csv('Marcadores_futbol_mexico.csv', mode ='a')

答案 7 :(得分:3)

你可以使用这些函数很容易第一个加密所以你只需调用函数并发送你想要加密的文本并从 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 

答案 8 :(得分:3)

crypt.subtle AES-GCM,自包含,经过测试:

async function aesGcmEncrypt(plaintext, password)

async function aesGcmDecrypt(ciphertext, password) 

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

答案 9 :(得分:1)

简单功能,


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

答案 10 :(得分:0)

使用SimpleCrypto

使用加密()和解密()

  

要使用SimpleCrypto,请首先使用以下命令创建一个SimpleCrypto实例:   私钥(密码)。密钥参数必须在以下情况下定义   创建一个SimpleCrypto实例。

     

要加密和解密数据,只需使用crypto()和crypten()   实例中的功能。这将使用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.");

答案 11 :(得分:0)

在实施任何一项之前,请参阅Scott Arciszewski's answer

我希望您对我将要分享的内容非常小心,因为我几乎没有安全知识(很可能会滥用下面的API),所以我非常欢迎您在社区的帮助下更新此答案

正如@richardtallent在他的answer中提到的那样,Web Crypto API受到支持,因此本示例使用该标准。在撰写本文时,有一个95.88% of global browser support

我将使用Web Crypto API共享一个示例

在继续之前,请注意(Quoting from 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