Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

311 rader
8.3 KiB

  1. (function () {
  2. 'use strict';
  3. function utf8ToBinaryString(str) {
  4. var escstr = encodeURIComponent(str);
  5. // replaces any uri escape sequence, such as %0A,
  6. // with binary escape, such as 0x0A
  7. var binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
  8. return String.fromCharCode(parseInt(p1, 16));
  9. });
  10. return binstr;
  11. }
  12. function utf8ToBuffer(str) {
  13. var binstr = utf8ToBinaryString(str);
  14. var buf = binaryStringToBuffer(binstr);
  15. return buf;
  16. }
  17. function utf8ToBase64(str) {
  18. var binstr = utf8ToBinaryString(str);
  19. return btoa(binstr);
  20. }
  21. function binaryStringToUtf8(binstr) {
  22. var escstr = binstr.replace(/(.)/g, function (m, p) {
  23. var code = p.charCodeAt(0).toString(16).toUpperCase();
  24. if (code.length < 2) {
  25. code = '0' + code;
  26. }
  27. return '%' + code;
  28. });
  29. return decodeURIComponent(escstr);
  30. }
  31. function bufferToUtf8(buf) {
  32. var binstr = bufferToBinaryString(buf);
  33. return binaryStringToUtf8(binstr);
  34. }
  35. function base64ToUtf8(b64) {
  36. var binstr = atob(b64);
  37. return binaryStringToUtf8(binstr);
  38. }
  39. function bufferToBinaryString(buf) {
  40. var binstr = Array.prototype.map.call(buf, function (ch) {
  41. return String.fromCharCode(ch);
  42. }).join('');
  43. return binstr;
  44. }
  45. function bufferToBase64(arr) {
  46. var binstr = bufferToBinaryString(arr);
  47. return btoa(binstr);
  48. }
  49. function binaryStringToBuffer(binstr) {
  50. var buf;
  51. if ('undefined' !== typeof Uint8Array) {
  52. buf = new Uint8Array(binstr.length);
  53. } else {
  54. buf = [];
  55. }
  56. Array.prototype.forEach.call(binstr, function (ch, i) {
  57. buf[i] = ch.charCodeAt(0);
  58. });
  59. return buf;
  60. }
  61. function base64ToBuffer(base64) {
  62. var binstr = atob(base64);
  63. var buf = binaryStringToBuffer(binstr);
  64. return buf;
  65. }
  66. window.Unibabel = {
  67. utf8ToBinaryString: utf8ToBinaryString
  68. , utf8ToBuffer: utf8ToBuffer
  69. , utf8ToBase64: utf8ToBase64
  70. , binaryStringToUtf8: binaryStringToUtf8
  71. , bufferToUtf8: bufferToUtf8
  72. , base64ToUtf8: base64ToUtf8
  73. , bufferToBinaryString: bufferToBinaryString
  74. , bufferToBase64: bufferToBase64
  75. , binaryStringToBuffer: binaryStringToBuffer
  76. , base64ToBuffer: base64ToBuffer
  77. // compat
  78. , strToUtf8Arr: utf8ToBuffer
  79. , utf8ArrToStr: bufferToUtf8
  80. , arrToBase64: bufferToBase64
  81. , base64ToArr: base64ToBuffer
  82. };
  83. }());
  84. (function () {
  85. 'use strict';
  86. function bufferToHex(arr) {
  87. var i;
  88. var len;
  89. var hex = '';
  90. var c;
  91. for (i = 0, len = arr.length; i < len; i += 1) {
  92. c = arr[i].toString(16);
  93. if (c.length < 2) {
  94. c = '0' + c;
  95. }
  96. hex += c;
  97. }
  98. return hex;
  99. }
  100. function hexToBuffer(hex) {
  101. // TODO use Uint8Array or ArrayBuffer or DataView
  102. var i;
  103. var byteLen = hex.length / 2;
  104. var arr;
  105. var j = 0;
  106. if (byteLen !== parseInt(byteLen, 10)) {
  107. throw new Error("Invalid hex length '" + hex.length + "'");
  108. }
  109. arr = new Uint8Array(byteLen);
  110. for (i = 0; i < byteLen; i += 1) {
  111. arr[i] = parseInt(hex[j] + hex[j + 1], 16);
  112. j += 2;
  113. }
  114. return arr;
  115. }
  116. // Hex Convenience Functions
  117. window.Unibabel.hexToBuffer = hexToBuffer;
  118. window.Unibabel.bufferToHex = bufferToHex;
  119. }());
  120. (function () {
  121. 'use strict';
  122. if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle) {
  123. window.crypto.subtle = window.crypto.webkitSubtle;
  124. }
  125. if (!window.crypto || !window.crypto.subtle) {
  126. console.error("Your browser does not support the Web Cryptography API! LessPass will not work.");
  127. return;
  128. }
  129. function importKey(masterPassword, algo, usages) {
  130. var format = 'raw';
  131. var masterPasswordArrayBuffer = Unibabel.utf8ToBuffer(masterPassword);
  132. var extractable = false;
  133. return window.crypto.subtle.importKey(format, masterPasswordArrayBuffer, algo, extractable, usages);
  134. }
  135. function deriveKey(masterKey, salt, iterations, keylen) {
  136. var algo = {
  137. name: 'PBKDF2',
  138. salt: Unibabel.utf8ToBuffer(salt),
  139. iterations: iterations,
  140. hash: 'SHA-256',
  141. };
  142. var extractable = true;
  143. var derivedKeyAlgo = {name: 'AES-CTR', length: keylen * 8};
  144. var usages = ['encrypt', 'decrypt'];
  145. return window.crypto.subtle.deriveKey(algo, masterKey, derivedKeyAlgo, extractable, usages);
  146. }
  147. function exportKey(derivedKey) {
  148. return window.crypto.subtle.exportKey('raw', derivedKey).then(function (keyArrayBuffer) {
  149. return Unibabel.bufferToHex(new Uint8Array(keyArrayBuffer));
  150. });
  151. }
  152. function encryptLogin(login, masterPassword, options) {
  153. var _options = options !== undefined ? options : {};
  154. var iterations = _options.iterations || 8192;
  155. var keylen = _options.keylen || 32;
  156. return importKey(masterPassword, 'PBKDF2', ['deriveKey'])
  157. .then(function (key) {
  158. return deriveKey(key, login, iterations, keylen);
  159. })
  160. .then(exportKey);
  161. }
  162. function signKey(masterKey, salt) {
  163. var algo = {name: 'HMAC'};
  164. var saltArrayBuffer = Unibabel.utf8ToBuffer(salt);
  165. return window.crypto.subtle.sign(algo, masterKey, saltArrayBuffer);
  166. }
  167. function _createHmac(encryptedLogin, salt) {
  168. return importKey(encryptedLogin, {name: 'HMAC', hash: {name: 'SHA-256'}}, ['sign'])
  169. .then(function (key) {
  170. return signKey(key, salt);
  171. })
  172. .then(function (derivedHmacKey) {
  173. return Unibabel.bufferToHex(new Uint8Array(derivedHmacKey))
  174. });
  175. }
  176. function _deriveEncryptedLogin(encryptedLogin, site) {
  177. var passwordOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
  178. length: 12,
  179. counter: 1
  180. };
  181. var salt = site + passwordOptions.counter.toString();
  182. return _createHmac(encryptedLogin, salt).then(function (derivedHash) {
  183. return derivedHash.substring(0, passwordOptions.length);
  184. });
  185. }
  186. function createFingerprint(str) {
  187. return _createHmac(str, '');
  188. }
  189. function renderPassword(encryptedLogin, site, passwordOptions) {
  190. return _deriveEncryptedLogin(encryptedLogin, site, passwordOptions).then(function (derivedEncryptedLogin) {
  191. var template = passwordOptions.template || LessPass._getPasswordTemplate(passwordOptions);
  192. return LessPass._prettyPrint(derivedEncryptedLogin, template);
  193. });
  194. }
  195. function _getPasswordTemplate(passwordTypes) {
  196. var templates = {
  197. lowercase: 'vc',
  198. uppercase: 'VC',
  199. numbers: 'n',
  200. symbols: 's',
  201. };
  202. var template = '';
  203. for (var templateKey in templates) {
  204. if (passwordTypes.hasOwnProperty(templateKey) && passwordTypes[templateKey]) {
  205. template += templates[templateKey]
  206. }
  207. }
  208. return template;
  209. }
  210. function _prettyPrint(hash, template) {
  211. var password = '';
  212. _string2charCodes(hash).forEach(function (charCode, index) {
  213. var charType = _getCharType(template, index);
  214. password += _getPasswordChar(charType, charCode);
  215. });
  216. return password;
  217. }
  218. function _string2charCodes(text) {
  219. var charCodes = [];
  220. for (var i = 0; i < text.length; i++) {
  221. charCodes.push(text.charCodeAt(i));
  222. }
  223. return charCodes;
  224. }
  225. function _getCharType(template, index) {
  226. return template[index % template.length];
  227. }
  228. function _getPasswordChar(charType, index) {
  229. var passwordsChars = {
  230. V: 'AEIOUY',
  231. C: 'BCDFGHJKLMNPQRSTVWXZ',
  232. v: 'aeiouy',
  233. c: 'bcdfghjklmnpqrstvwxz',
  234. A: 'AEIOUYBCDFGHJKLMNPQRSTVWXZ',
  235. a: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz',
  236. n: '0123456789',
  237. s: '@&%?,=[]_:-+*$#!\'^~;()/.',
  238. x: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz0123456789@&%?,=[]_:-+*$#!\'^~;()/.'
  239. };
  240. var passwordChar = passwordsChars[charType];
  241. return passwordChar[index % passwordChar.length];
  242. }
  243. window.LessPass = {
  244. encryptLogin: encryptLogin,
  245. renderPassword: renderPassword,
  246. createFingerprint: createFingerprint,
  247. _createHmac: _createHmac,
  248. _deriveEncryptedLogin: _deriveEncryptedLogin,
  249. _getPasswordTemplate: _getPasswordTemplate,
  250. _prettyPrint: _prettyPrint,
  251. _string2charCodes: _string2charCodes,
  252. _getCharType: _getCharType,
  253. _getPasswordChar: _getPasswordChar,
  254. };
  255. }());