You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

109 regels
3.2 KiB

  1. import crypto from 'crypto';
  2. module.exports = {
  3. encryptLogin: _encryptLogin,
  4. renderPassword: _renderPassword,
  5. createFingerprint: createFingerprint,
  6. _deriveEncryptedLogin,
  7. _getPasswordTemplate,
  8. _prettyPrint,
  9. _string2charCodes,
  10. _getCharType,
  11. _getPasswordChar,
  12. _createHmac
  13. };
  14. function _encryptLogin(login, masterPassword, {iterations = 8192, keylen = 32}={}) {
  15. return new Promise((resolve, reject) => {
  16. if (!login || !masterPassword) {
  17. reject('login and master password parameters could not be empty');
  18. }
  19. crypto.pbkdf2(masterPassword, login, iterations, keylen, 'sha256', (error, key) => {
  20. if (error) {
  21. reject('error in pbkdf2');
  22. } else {
  23. resolve(key.toString('hex'));
  24. }
  25. });
  26. })
  27. }
  28. function _renderPassword(encryptedLogin, site, passwordOptions) {
  29. return _deriveEncryptedLogin(encryptedLogin, site, passwordOptions).then(function (derivedEncryptedLogin) {
  30. const template = _getPasswordTemplate(passwordOptions);
  31. return _prettyPrint(derivedEncryptedLogin, template);
  32. });
  33. }
  34. function _createHmac(encryptedLogin, salt) {
  35. return new Promise(resolve => {
  36. resolve(crypto.createHmac('sha256', encryptedLogin).update(salt).digest('hex'));
  37. });
  38. }
  39. function _deriveEncryptedLogin(encryptedLogin, site, passwordOptions = {length: 12, counter: 1}) {
  40. const salt = site + passwordOptions.counter.toString();
  41. return _createHmac(encryptedLogin, salt).then(derivedHash => {
  42. return derivedHash.substring(0, passwordOptions.length);
  43. });
  44. }
  45. function _getPasswordTemplate(passwordTypes) {
  46. const templates = {
  47. lowercase: 'vc',
  48. uppercase: 'VC',
  49. numbers: 'n',
  50. symbols: 's',
  51. };
  52. let template = '';
  53. for (let templateKey in templates) {
  54. if (passwordTypes.hasOwnProperty(templateKey) && passwordTypes[templateKey]) {
  55. template += templates[templateKey]
  56. }
  57. }
  58. return template;
  59. }
  60. function _prettyPrint(hash, template) {
  61. let password = '';
  62. _string2charCodes(hash).forEach((charCode, index) => {
  63. const charType = _getCharType(template, index);
  64. password += _getPasswordChar(charType, charCode);
  65. });
  66. return password;
  67. }
  68. function _string2charCodes(text) {
  69. const charCodes = [];
  70. for (let i = 0; i < text.length; i++) {
  71. charCodes.push(text.charCodeAt(i));
  72. }
  73. return charCodes;
  74. }
  75. function _getCharType(template, index) {
  76. return template[index % template.length];
  77. }
  78. function _getPasswordChar(charType, index) {
  79. const passwordsChars = {
  80. V: 'AEIOUY',
  81. C: 'BCDFGHJKLMNPQRSTVWXZ',
  82. v: 'aeiouy',
  83. c: 'bcdfghjklmnpqrstvwxz',
  84. A: 'AEIOUYBCDFGHJKLMNPQRSTVWXZ',
  85. a: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz',
  86. n: '0123456789',
  87. s: '@&%?,=[]_:-+*$#!\'^~;()/.',
  88. x: 'AEIOUYaeiouyBCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz0123456789@&%?,=[]_:-+*$#!\'^~;()/.'
  89. };
  90. const passwordChar = passwordsChars[charType];
  91. return passwordChar[index % passwordChar.length];
  92. }
  93. function createFingerprint(str) {
  94. return new Promise(resolve => {
  95. resolve(crypto.createHmac('sha256', str).digest('hex'))
  96. });
  97. }