简体   繁体   中英

Simple in browser symmetric AES encryption

I've been asked to write a simple encryption add-on to a simple knowledge-base/article app. Nothing complicated, no fancy multitude of options, just simple symmetric encryption.

So I've been looking for some JS libraries/examples on how to do it and, surprisingly, I did not find many. Most of the google hits are about how bad the encryption in the browser is. So could you suggest a simplest library or link that I could investigate?

In the mean time, the simplest/accessible way I found was the built in Web Cryptography API. After fiddling for a bit I came up with this:

function strtoarr (str) {
  return new TextEncoder().encode(str)
}

function arrtostr (arr) {
  return new TextDecoder().decode(arr)
}

function salt() {
  var vector = new Uint8Array(16)
  crypto.getRandomValues(vector)
  return Array.from(vector)
}

function encrypt (txt, pas, slt, fnc) {
  var vector = new Uint8Array(slt)
  crypto.subtle.digest({name: 'SHA-256'}, strtoarr(pas)).then((res) => {
    crypto.subtle.importKey('raw', res, {name: 'AES-CBC'}, false, ['encrypt', 'decrypt']).then((key) => {
      crypto.subtle.encrypt({name: 'AES-CBC', iv: vector}, key, strtoarr(txt)).then((res) => {
        fnc(Array.from(new Uint8Array(res)), Array.from(vector))
      })
    })
  })
}

function decrypt (cyp, pas, slt, fnc) {
  var data = new Uint8Array(cyp)
  var vector = new Uint8Array(slt)
  crypto.subtle.digest({name: 'SHA-256'}, strtoarr(pas)).then((res) => {
    crypto.subtle.importKey('raw', res, {name: 'AES-CBC'}, false, ['encrypt', 'decrypt']).then((key) => {
      crypto.subtle.decrypt({name: 'AES-CBC', iv: vector}, key, data).then((res) => {
        fnc(arrtostr(res))
      }, () => {
        fnc(null)
      })
    })
  })
}

Now, this works although quite cumbersome. Surely, some one has done it in a less messy and simpler way? The multiple layers of "thenables" just do not look clean to me.

And last question. What is the best way to save the resulting cypher and vector on Mongodb? At the moment, I output it as an Array. Mongodb gets it as array of long integers. If I don't cast it into an Array, and output it as a Typed Array then Mongodb gets it as an Object - not an Array. If I try to save it as "text" then things stop working completely and I cannot decrypt it back.

How do you people do it? How do you save it on the DB? If it is "text", what is the best way to "armor" a Typed Array? I'd like an output similar to GPG armored output so I can safely save it on a DB and then turn it back into Typed Array ready to by consumed by decryption function.

See crypto-js for a very robust in-browser AES implementation.

I normally stringify the cypher and vector and then encrypt that string using an asymmetric algorithm for storage in the db.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM