index.spec.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. /* jshint node:true, jasmine:true */
  9. 'use strict';
  10. var cryptoPolicy = require('scytl-cryptopolicy');
  11. var pbkdf = require('../lib/index');
  12. var codec = require('scytl-codec');
  13. var forge = require('node-forge');
  14. describe('The PBKDF module should be able to ...', function() {
  15. var PASSWORD = 'Test';
  16. var SALT = 'TestTestTestTestTestTestTestTest';
  17. var salt_;
  18. var tooSmallsalt_;
  19. var deriver_;
  20. var key_;
  21. var policy_;
  22. beforeAll(function() {
  23. salt_ = codec.utf8Encode(SALT);
  24. tooSmallsalt_ = codec.utf8Encode('1');
  25. deriver_ = pbkdf.newService().newDeriver();
  26. key_ = deriver_.derive(PASSWORD, salt_);
  27. });
  28. beforeEach(function() {
  29. policy_ = cryptoPolicy.newInstance();
  30. });
  31. describe('create a PBKDF service that should be able to ..', function() {
  32. describe('create a PBKDF deriver that should be able to', function() {
  33. it('derive a key of the expected length, when using the default cryptographic policy.',
  34. function() {
  35. var key = deriver_.derive(PASSWORD, salt_);
  36. expect(key).toBeDefined();
  37. expect(key.length)
  38. .toBe(policy_.primitives.keyDerivation.pbkdf.keyLengthBytes);
  39. });
  40. it('derive a key of the expected length, when using a specified cryptographic policy.',
  41. function() {
  42. policy_.primitives.keyDerivation.pbkdf.keyLengthBytes =
  43. cryptoPolicy.options.primitives.keyDerivation.pbkdf
  44. .keyLengthBytes.KL_32;
  45. var pbkdfService = pbkdf.newService({policy: policy_});
  46. var key = pbkdfService.newDeriver().derive(PASSWORD, salt_);
  47. expect(key).toBeDefined();
  48. expect(key.length)
  49. .toBe(cryptoPolicy.options.primitives.keyDerivation.pbkdf
  50. .keyLengthBytes.KL_32);
  51. });
  52. it('derive the same key every time, for a given cryptographic policy.',
  53. function() {
  54. var key = deriver_.derive(PASSWORD, salt_);
  55. expect(key).toBeDefined();
  56. expect(key).toEqual(key_);
  57. });
  58. it('derive the expected key if salt is provided as string instead of bytes',
  59. function() {
  60. var key = deriver_.derive(PASSWORD, SALT);
  61. expect(key).toBeDefined();
  62. expect(key).toEqual(key_);
  63. });
  64. it('derive different keys when different numbers of iterations are specified.',
  65. function() {
  66. policy_.primitives.keyDerivation.pbkdf.numIterations =
  67. cryptoPolicy.options.primitives.keyDerivation.pbkdf.numIterations
  68. .I_1;
  69. var pbkdfService = pbkdf.newService({policy: policy_});
  70. var key = pbkdfService.newDeriver().derive(PASSWORD, salt_);
  71. expect(key).toBeDefined();
  72. expect(key).not.toEqual(key_);
  73. });
  74. it('derive different keys when different passwords are used.',
  75. function() {
  76. var key = deriver_.derive(PASSWORD + 'a', salt_);
  77. expect(key).toBeDefined();
  78. expect(key).not.toEqual(key_);
  79. });
  80. it('derive different keys when different salts are used.', function() {
  81. var key = deriver_.derive(PASSWORD, codec.utf8Encode(SALT + 'a'));
  82. expect(key).toBeDefined();
  83. expect(key).not.toEqual(key_);
  84. });
  85. it('derive the same key for the SJCL and Forge cryptographic service providers, given a random password.',
  86. function() {
  87. var password =
  88. generateRandomString(Math.floor(Math.random() * 128) + 1);
  89. // Derive key using SJCL.
  90. var derivedKeyFromSjcl = deriver_.derive(password, salt_);
  91. // Derive key using Forge.
  92. var numIterations =
  93. policy_.primitives.keyDerivation.pbkdf.numIterations;
  94. var keyLengthBytes =
  95. policy_.primitives.keyDerivation.pbkdf.keyLengthBytes;
  96. var derivedKeyFromForgeBinaryEncoded = forge.pkcs5.pbkdf2(
  97. codec.binaryEncode(codec.utf8Encode(password)),
  98. codec.binaryEncode(salt_), numIterations, keyLengthBytes,
  99. getHashGenerator(
  100. policy_.primitives.keyDerivation.pbkdf.hashAlgorithm,
  101. cryptoPolicy.options.primitives.keyDerivation.pbkdf
  102. .hashAlgorithm));
  103. var derivedKeyFromForge =
  104. codec.binaryDecode(derivedKeyFromForgeBinaryEncoded);
  105. expect(derivedKeyFromForge).toEqual(derivedKeyFromSjcl);
  106. });
  107. it('throw an error when a salt length less than the minimum value specified in the cryptographic policy is used',
  108. function() {
  109. expect(function() {
  110. deriver_.derive(PASSWORD, tooSmallsalt_);
  111. }).toThrow();
  112. });
  113. });
  114. });
  115. });
  116. function generateRandomString(length) {
  117. var allowedChars =
  118. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,-./:;<=>?@[\]^_`{|}~';
  119. var str = '';
  120. for (var i = 0; i < length; i++) {
  121. str += allowedChars.charAt(Math.floor(Math.random() * allowedChars.length));
  122. }
  123. return str;
  124. }
  125. function getHashGenerator(algorithm, config) {
  126. if (algorithm === config.SHA256) {
  127. return forge.sha256.create();
  128. } else {
  129. throw 'Hash algorithm \'' + algorithm + '\' is unsupported';
  130. }
  131. }