最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Simple in browser symmetric AES encryption - Stack Overflow

programmeradmin8浏览0评论

I've been asked to write a simple encryption add-on to a simple knowledge-base/article app. Nothing plicated, 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 pletely 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.

I've been asked to write a simple encryption add-on to a simple knowledge-base/article app. Nothing plicated, 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 pletely 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.

Share Improve this question asked Jan 19, 2016 at 7:32 r.sendeckyr.sendecky 10.4k10 gold badges43 silver badges64 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 2

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.

发布评论

评论列表(0)

  1. 暂无评论