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.
 
 
 
 
 
 

96 line
2.9 KiB

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