xuyingjie / fragment

Blog Tool
MIT License
1 stars 0 forks source link

Web Cryptography API #3

Open xuyingjie opened 8 years ago

xuyingjie commented 8 years ago

http://www.w3.org/TR/WebCryptoAPI/

Example: https://github.com/diafygi/webcrypto-examples https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey

Comparion: https://jsperf.com/webcrypto-sjcl-cryptojs/11

Chromium: Access to the WebCrypto API is restricted to secure origins (which is to say https:// pages)

xuyingjie commented 8 years ago
function arrayBufferToStr(buf) {
  // return String.fromCharCode.apply(null, new Uint16Array(buf))  // >100kb string -> chrome 'Unhandled promise rejection RangeError: Maximum call stack size exceeded'
  return (new Uint16Array(buf)).reduce((str, x) => str + String.fromCharCode(x), '')
}
function strToArrayBuffer(str) {
  // return Uint16Array.from([...str], s => s.charCodeAt(0)).buffer
  // return new Uint16Array([...str].map(s => s.charCodeAt(0))).buffer
  return new TextEncoder('utf-16').encode(str)
}

//
// WebCryptoAPI
//
// concat arrayBuffer
function set(a, b) {
  var out = new Uint8Array(a.byteLength + b.byteLength)
  out.set(new Uint8Array(a))
  out.set(new Uint8Array(b), a.byteLength)
  return out.buffer
}

function importKey(passwd) {
  return new Promise((resolve, reject) => {
    window.crypto.subtle.importKey(
      'raw', // can be 'jwk' or 'raw'
      strToArrayBuffer(passwd),
      { // this is the algorithm options
        name: 'AES-GCM',
      },
      false, // whether the key is extractable (i.e. can be used in exportKey)
      ['encrypt', 'decrypt'] // can 'encrypt', 'decrypt', 'wrapKey', or 'unwrapKey'
    )
      .then(key => {
        // returns the symmetric key
        resolve(key)
      })
      .catch(err => {
        reject(err)
      })
  })
}

function encrypt(passwd, data) {
  return new Promise((resolve, reject) => {
    importKey(passwd)
      .then(key => {

        var iv = window.crypto.getRandomValues(new Uint8Array(12))
        window.crypto.subtle.encrypt({
          name: 'AES-GCM',

          // Don't re-use initialization vectors! Always generate a new iv every time your encrypt!
          // Recommended to use 12 bytes length
          // where iv is an ArrayBuffer or an ArrayBufferView with 12 random bytes (these should be generated by RandomSource.getRandomValues()).
          iv
        },
          key, // from generateKey or importKey above
          data // ArrayBuffer of data you want to encrypt
        )
          .then(encrypted => {
            // returns an ArrayBuffer containing the encrypted data
            resolve(set(iv.buffer, encrypted))
          })
          .catch(err => {
            reject(err)
          })
      })
  })
}

function decrypt(passwd, data) {
  return new Promise((resolve, reject) => {
    importKey(passwd)
      .then(key => {
        window.crypto.subtle.decrypt({
          name: 'AES-GCM',
          iv: data.slice(0, 12) // The initialization vector you used to encrypt
        },
          key, // from generateKey or importKey above
          data.slice(12) // ArrayBuffer of the data
        )
          .then(decrypted => {
            // returns an ArrayBuffer containing the decrypted data
            resolve(decrypted)
          })
          .catch(err => {
            reject(err)
          })
      })
  })
}
xuyingjie commented 8 years ago

base64_hmac_sha1

Ep: https://jswebcrypto.azurewebsites.net/demo.html#/ https://github.com/usrz/js-app-login/blob/master/index.html https://github.com/mozilla/releases-comm-central/blob/master/chat/modules/ArrayBufferUtils.jsm

function b64HmacSHA1(key, str) {
  var keyBuf = new TextEncoder('utf-8').encode(key)
  var buf = new TextEncoder('utf-8').encode(str)

  return new Promise(resolve => {
    var hmacSha1 = {name: 'hmac', hash: {name: 'sha-1'}}
    crypto.subtle.importKey('raw', keyBuf, hmacSha1, true, ['sign', 'verify']).then(out => {
      crypto.subtle.sign(hmacSha1, out, buf).then(result => {
        resolve(btoa(String.fromCharCode.apply(null, new Uint8Array(result))))
      })
    })
  })
}
xuyingjie commented 8 years ago

Documents: http://javascript.ruanyifeng.com/stdlib/arraybuffer.html

arraybuffer.byteLength
arraybuffer.slice(begin[, end])

typedarray.buffer
typedarray.byteLength
typedarray.byteOffset
typedarray.length
typedarray.set(array [,offset])
typedarray.set(typedarray [,offset])
typedarray.subarray([begin [,end]]) // 是对于TypedArray数组的一部分,再建立一个新的视图。 typedarray.slice([begin[, end]]) // 返回一个指定位置的新的TypedArray实例。 TypedArray.of(element0[, element1[, ...[, elementN]]])
TypedArray.from(source[, mapFn[, thisArg]]) // Uint16Array.from(Uint8Array.of(0, 1, 2))

// [len][json][enc]
 - export function decStr(data) {
 -  return new Promise(resolve => {
 -    var x = new Uint16Array(data)
 -    var len = x.subarray(0, 1)[0]
 -    var str = String.fromCharCode.apply(null, x.subarray(1, len + 1))
 -    var item = JSON.parse(str)
 -    if (localStorage.user) {
 -      let user = JSON.parse(localStorage.user)
 -      let buf = data.slice((len + 1) * 2)
 -      decrypt(user.passwd, buf).then(out => {
 -        item.text = arrayBufferToStr(out)
 -        resolve(item)
 -      })
 -    } else {
 -      item.text = ''
 -      resolve(item)
 -    }
 -  })
 -}
xuyingjie commented 7 years ago

new TextEncoder('utf-16').encode(str)

Note: Firefox, Chrome and Opera had support for encoding types other than utf-8 (such as: utf-16, iso-8859-2, koi8, cp1261, and gbk). As of Firebox 48 (ticket), Chrome 54 (ticket) and Opera 41, no other encoding types are available other than utf-8, in order to match the spec. In all cases, passing in an encoding type to the constructor will be ignored and a utf-8 TextEncoder will be created (Note: the TextDecoder still allows for other decoding types).

String.fromCharCode.apply(null, new Uint16Array(buf))

>100kb string -> chrome 'Unhandled promise rejection RangeError: Maximum call stack size exceeded'

xuyingjie commented 6 years ago

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

xuyingjie commented 6 years ago

https://www.w3.org/TR/WebCryptoAPI/#algorithm-overview

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