Advertisement
Guest User

WebCrypto Example

a guest
Nov 16th, 2017
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. // Helpers    /////////////////////////////////////////////
  3.  
  4. // Taken from https://github.com/google/closure-library/blob/e877b1eac410c0d842bcda118689759512e0e26f/closure/goog/crypt/crypt.js
  5. // Apache Licensed
  6. stringToUtf8ByteArray = function(str) {
  7.   // TODO(user): Use native implementations if/when available
  8.   var out = [], p = 0;
  9.   for (var i = 0; i < str.length; i++) {
  10.     var c = str.charCodeAt(i);
  11.     if (c < 128) {
  12.       out[p++] = c;
  13.     } else if (c < 2048) {
  14.       out[p++] = (c >> 6) | 192;
  15.       out[p++] = (c & 63) | 128;
  16.     } else if (
  17.         ((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
  18.         ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
  19.       // Surrogate Pair
  20.       c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
  21.       out[p++] = (c >> 18) | 240;
  22.       out[p++] = ((c >> 12) & 63) | 128;
  23.       out[p++] = ((c >> 6) & 63) | 128;
  24.       out[p++] = (c & 63) | 128;
  25.     } else {
  26.       out[p++] = (c >> 12) | 224;
  27.       out[p++] = ((c >> 6) & 63) | 128;
  28.       out[p++] = (c & 63) | 128;
  29.     }
  30.   }
  31.   return new Uint8Array(out);
  32. };
  33.  
  34. // Taken from https://github.com/google/closure-library/blob/e877b1eac410c0d842bcda118689759512e0e26f/closure/goog/crypt/crypt.js
  35. // Apache Licensed
  36. utf8ByteArrayToString = function(bytes) {
  37.   // TODO(user): Use native implementations if/when available
  38.   let out = [], pos = 0, c = 0;
  39.   while (pos < bytes.length) {
  40.     let c1 = bytes[pos++];
  41.     if (c1 < 128) {
  42.       out[c++] = String.fromCharCode(c1);
  43.     } else if (c1 > 191 && c1 < 224) {
  44.       let c2 = bytes[pos++];
  45.       out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
  46.     } else if (c1 > 239 && c1 < 365) {
  47.       // Surrogate Pair
  48.       let c2 = bytes[pos++];
  49.       let c3 = bytes[pos++];
  50.       let c4 = bytes[pos++];
  51.       let u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) -
  52.           0x10000;
  53.       out[c++] = String.fromCharCode(0xD800 + (u >> 10));
  54.       out[c++] = String.fromCharCode(0xDC00 + (u & 1023));
  55.     } else {
  56.       let c2 = bytes[pos++];
  57.       let c3 = bytes[pos++];
  58.       out[c++] =
  59.           String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
  60.     }
  61.   }
  62.   return out.join('');
  63. };
  64.  
  65. function byteArrayToHexString(byteArray) {
  66.     if (!byteArray) {
  67.         return '';
  68.     }
  69.  
  70.     var hexStr = '';
  71.     for (var i = 0; i < byteArray.length; i++) {
  72.         var hex = (byteArray[i] & 0xff).toString(16);
  73.         hex = (hex.length === 1) ? '0' + hex : hex;
  74.         hexStr += hex;
  75.     }
  76.     return hexStr.toUpperCase();
  77. }
  78.  
  79. function hexStringToByteArray(hexString) {
  80.   let result = new Uint8Array(hexString.length/2), i = 0;
  81.   while (hexString.length >= 2) {
  82.     result[i++] = parseInt(hexString.substring(0, 2), 16);
  83.     hexString = hexString.substring(2, hexString.length);
  84.   }
  85.   return result;
  86. }
  87.  
  88. //            /////////////////////////////////////////////
  89.  
  90. // Crypto     /////////////////////////////////////////////
  91. // Uses Web Crypto API (SubtleCrypto)
  92.  
  93. var _crypto = window.crypto || window.msCrypto;
  94. if (!_crypto)
  95. {
  96.     alert("Cryptography API Not Supported.");
  97.     throw 'Cryptography API Not Supported.';
  98. }
  99.  
  100. var _algorithm = "AES-CBC";
  101. var _key_size = 256;
  102. var _pbkdf_iterations = 100;
  103.  
  104. // Do not change this once used in production
  105. var _defaultSalt = "af95a2b25229d227269a54fdec562d93";
  106.  
  107. // Generates a new Key
  108. function _generateKey()
  109. {
  110.     // Extractable is set to false so that underlying key details cannot be accessed.
  111.     return crypto.subtle.generateKey({name: _algorithm, length: _key_size}, false, ["encrypt", "decrypt"]);
  112. }
  113.  
  114. // Derives a key from the given password.
  115. // Salt is not required. If supplied should be a hex string.
  116. function deriveKey(passphrase, salt)
  117. {  
  118.     if (typeof(salt) === 'undefined')
  119.     {
  120.         salt = _defaultSalt;
  121.     }
  122.    
  123.     return passphrase == null || passphrase.length < 10 ?
  124.         Promise.reject("Password must be at least 10 characters") :
  125.         crypto.subtle.importKey(
  126.             'raw',
  127.             stringToUtf8ByteArray(passphrase),
  128.             { name: 'PBKDF2'},
  129.             false,
  130.             ['deriveBits', 'deriveKey' ]
  131.         ).then(function(passwordKey) {
  132.             return crypto.subtle.deriveKey(
  133.                 {
  134.                     "name": 'PBKDF2',
  135.                     "salt": hexStringToByteArray(salt),
  136.                     "iterations": _pbkdf_iterations,
  137.                     "hash": 'SHA-256'
  138.                 },
  139.                 passwordKey,
  140.                 { "name": _algorithm, "length": _key_size },
  141.                 false, // Extractable is set to false so that underlying key details cannot be accessed.
  142.                 [ "encrypt", "decrypt" ]
  143.             );
  144.         });
  145. }
  146.  
  147.  
  148. function encryptData(keyObject, data)
  149. {
  150.     let iv = crypto.getRandomValues(new Uint8Array(16));
  151.    
  152.     return crypto.subtle.encrypt(
  153.         {name: _algorithm, iv: iv},
  154.         keyObject,
  155.         data
  156.     ).then(function(encryptedData) {
  157.         return {
  158.             iv:iv,
  159.             data:encryptedData
  160.         }
  161.     });
  162. }
  163.  
  164. function decryptData(keyObject, iv, encryptedData)
  165. {  
  166.     return crypto.subtle.decrypt(
  167.         {name: _algorithm, iv: iv},
  168.         keyObject,
  169.         encryptedData
  170.     );
  171. }
  172.  
  173. // Usage      /////////////////////////////////////////////
  174.  
  175. var theKey= null;
  176.  
  177. function fromPassword() {
  178.     var password = prompt("Please enter key derivation password. This should be at least 10 characters - ideally random. Unicode is supported.");
  179.     if (password !== null)
  180.     {
  181.         deriveKey(password)
  182.             .then(function(keyObject) {
  183.                 theKey = keyObject;
  184.                
  185.             }).catch(function(err) {
  186.                 alert(err);
  187.             });
  188.     }
  189. };
  190.  
  191. function encrypt_data() {
  192.     var data = stringToUtf8ByteArray(document.getElementById('cleartext').value);
  193.    
  194.     encryptData(theKey, data).then(function(encryptedData) {
  195.         document.getElementById('cleartext').value = "";
  196.         document.getElementById('encrypted').value = byteArrayToHexString(new Uint8Array(encryptedData.data));
  197.         document.getElementById('iv').value = byteArrayToHexString(encryptedData.iv);
  198.     });
  199. };
  200.  
  201. function decrypt_data() {
  202.     var encryptedData = hexStringToByteArray(document.getElementById('encrypted').value);
  203.     var iv_plain = document.getElementById('iv').value;
  204.     var iv = hexStringToByteArray(document.getElementById('iv').value);
  205.     document.getElementById('cleartext').value = "";
  206.    
  207.     decryptData(theKey, iv, encryptedData).then(function(data) {
  208.         document.getElementById('cleartext').value = utf8ByteArrayToString(new Uint8Array(data));
  209.     }).catch(function (err) {
  210.         document.getElementById('cleartext').value = "[Error - Wrong Key?]: " + err;
  211.     });
  212. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement