123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- /*
- * Copyright 2018 Scytl Secure Electronic Voting SA
- *
- * All rights reserved
- *
- * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
- */
- describe('derivation module: ', function() {
- 'use strict';
- it('should exist', function() {
- cryptolib('primitives.derivation', function(box) {
- expect(box.primitives.derivation).toBeDefined();
- });
- });
- it('should contain a PBKDF generator factory', function() {
- cryptolib('primitives.derivation', function(box) {
- var pbkdfGeneratorFactory =
- new box.primitives.derivation.factory.SecretKeyGeneratorFactory();
- expect(pbkdfGeneratorFactory).toBeDefined();
- });
- });
- describe('PBKDF generator factory', function() {
- it('should generate a secretKey.', function() {
- cryptolib(
- 'primitives.derivation', 'commons.utils', 'primitives.securerandom',
- function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var secureRandomFactory =
- new box.primitives.securerandom.factory.SecureRandomFactory();
- var cryptoRandomBytes = secureRandomFactory.getCryptoRandomBytes();
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var salt = cryptoRandomBytes.nextRandom(20);
- var saltB64 = converters.base64Encode(salt);
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).toBeDefined();
- expect(converters.base64Decode(secretKeyB64).length)
- .toBe(box.policies.primitives.derivation.pbkdf.keyLengthBytes);
- });
- });
- it('should generate a secretKey with hash SHA256 and salt length 32 bytes.',
- function() {
- cryptolib(
- 'primitives.derivation', 'commons.utils',
- 'primitives.securerandom', function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory =
- new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var secureRandomFactory = new box.primitives.securerandom
- .factory.SecureRandomFactory();
- var cryptoRandomBytes =
- secureRandomFactory.getCryptoRandomBytes();
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var salt = cryptoRandomBytes.nextRandom(32);
- var saltB64 = converters.base64Encode(salt);
- var secretKeyB64 =
- cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).toBeDefined();
- expect(converters.base64Decode(secretKeyB64).length)
- .toBe(box.policies.primitives.derivation.pbkdf
- .keyLengthBytes);
- };
- f.policies = {
- primitives: {
- secureRandom: {
- provider: Config.primitives.secureRandom.provider.SCYTL
- },
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 32,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib(
- 'primitives.derivation', 'commons.utils',
- 'primitives.securerandom', f);
- });
- });
- it('should generate a secretKey that matches one created with another engine, if the policies and parameters are the same.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var calculatedKey = 'vD80dK3PvPrQkALIY87oi7agHGoOCGGhvkZFuNASgL8=';
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var saltB64 = 'CpHq+38iqF3Ls7j97qBQ2A9Diy8=';
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).toEqual(calculatedKey);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should generate a secretKey that does not match one created with another engine, if the key lengths are different.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var calculatedKey = 'vD80dK3PvPrQkALIY87oi7agHGoOCGGhvkZFuNASgL8=';
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var saltB64 = 'CpHq+38iqF3Ls7j97qBQ2A9Diy8=';
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).not.toEqual(calculatedKey);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 16,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should generate a secretKey that does not match one created with another engine, if the number of iterations are different.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var calculatedKey = 'T5dDOwtsmPEnIYuCqUAldZZo4tO86FgcO7GAgDhaxYc=';
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var saltB64 = 'CpHq+38iqF3Ls7j97qBQ2A9Diy8=';
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).not.toEqual(calculatedKey);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 8000
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should generate a secretKey that does not match one created with another engine, if the password is different.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var calculatedKey = 'T5dDOwtsmPEnIYuCqUAldZZo4tO86FgcO7GAgDhaxYc=';
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('Scytl');
- var saltB64 = 'CpHq+38iqF3Ls7j97qBQ2A9Diy8=';
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).not.toEqual(calculatedKey);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should generate a secretKey that does not match one created with another engine, if the salt is different.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var calculatedKey = 'T5dDOwtsmPEnIYuCqUAldZZo4tO86FgcO7GAgDhaxYc=';
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- var saltB64 = 'cpHq+38iqF3Ls7j97qBQ2A9Diy8=';
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).not.toEqual(calculatedKey);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should generate a secretKey that does not match one created with another engine, if the hash algorithm is different.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var saltB64 = 'T4DtI/lcymMpBjJ7Ib9xpyS6xpuB5/+G68X3dT66eJs=';
- var generatedKeySHA1 =
- 'Ol8LDensA6B3CNhguSJrcuAnHAaB1NnGL0VfgbzDi34=';
- var encodedPassword = converters.base64Encode('scytl');
- var secretKeyB64 = cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- expect(secretKeyB64).not.toEqual(generatedKeySHA1);
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 32,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when an unsupported provider is specified in the policy.',
- function() {
- var f = function(box) {
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- expect(function() {
- pbkdfGeneratorFactory.createPBKDF();
- }).toThrow();
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'WRONG',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when an unsupported hash algorithm is specified in the policy.',
- function() {
- var f = function(box) {
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- expect(function() {
- pbkdfGeneratorFactory.createPBKDF();
- }).toThrow();
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'WRONG',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when an unsupported minimum salt length is specified in the policy.',
- function() {
- var f = function(box) {
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- expect(function() {
- pbkdfGeneratorFactory.createPBKDF();
- }).toThrow();
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 21,
- keyLengthBytes: 32,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when an unsupported key length is specified in the policy.',
- function() {
- var f = function(box) {
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- expect(function() {
- pbkdfGeneratorFactory.createPBKDF();
- }).toThrow();
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 33,
- iterations: 1
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when an unsupported number of iterations is specified in the policy.',
- function() {
- var f = function(box) {
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- expect(function() {
- pbkdfGeneratorFactory.createPBKDF();
- }).toThrow();
- };
- f.policies = {
- primitives: {
- derivation: {
- pbkdf: {
- provider: 'Forge',
- hash: 'SHA256',
- saltLengthBytes: 20,
- keyLengthBytes: 32,
- iterations: 2
- }
- }
- }
- };
- cryptolib('primitives.derivation', 'commons.utils', f);
- });
- it('should throw an error when a salt with length less than the minimum specified in the policy is used.',
- function() {
- var f = function(box) {
- var converters = new box.commons.utils.Converters();
- var secureRandomFactory =
- new box.primitives.securerandom.factory.SecureRandomFactory();
- var randomByteGenerator = secureRandomFactory.getCryptoRandomBytes();
- var salt = randomByteGenerator.nextRandom(
- box.policies.primitives.derivation.pbkdf.saltLengthBytes - 1);
- var saltB64 = converters.base64Encode(salt);
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var encodedPassword = converters.base64Encode('scytl');
- expect(function() {
- cryptoPbkdfSecretKeyGenerator.generateSecret(
- encodedPassword, saltB64);
- }).toThrow();
- };
- cryptolib(
- 'primitives.securerandom', 'primitives.derivation',
- 'commons.utils', f);
- });
- it('should produce the same results when using SJCL or Forge as the cryptographic service provider.',
- function() {
- cryptolib(
- 'primitives.derivation', 'commons.utils',
- 'primitives.securerandom', function(box) {
- var converters = new box.commons.utils.Converters();
- var pbkdfGeneratorFactory = new box.primitives.derivation.factory
- .SecretKeyGeneratorFactory();
- var secureRandomFactory = new box.primitives.securerandom.factory
- .SecureRandomFactory();
- var cryptoRandomBytes =
- secureRandomFactory.getCryptoRandomBytes();
- var cryptoPbkdfSecretKeyGenerator =
- pbkdfGeneratorFactory.createPBKDF();
- var password =
- generateRandomString(Math.floor(Math.random() * 128) + 1);
- var passwordB64 = converters.base64Encode(password);
- var salt = cryptoRandomBytes.nextRandom(20);
- var saltB64 = converters.base64Encode(salt);
- var secretKeyFromSjclB64 =
- cryptoPbkdfSecretKeyGenerator.generateSecret(
- passwordB64, saltB64);
- var iterations =
- cryptolibPolicies.primitives.derivation.pbkdf.iterations;
- var keyLengthBytes =
- cryptolibPolicies.primitives.derivation.pbkdf.keyLengthBytes;
- var secretKeyFromForge = forge.pkcs5.pbkdf2(
- password, salt, iterations, keyLengthBytes,
- getHashGenerator(
- cryptolibPolicies.primitives.derivation.pbkdf.hash,
- Config.primitives.derivation.pbkdf.hash));
- var secretKeyFromForgeB64 =
- converters.base64Encode(secretKeyFromForge);
- expect(secretKeyFromForgeB64).toBe(secretKeyFromSjclB64);
- });
- });
- });
- });
- function generateRandomString(length) {
- 'use strict';
- var allowedChars =
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,-./:;<=>?@[\]^_`{|}~';
- var str = '';
- for (var i = 0; i < length; i++) {
- str += allowedChars.charAt(Math.floor(Math.random() * allowedChars.length));
- }
- return str;
- }
- function getHashGenerator(algorithm, config) {
- 'use strict';
- if (algorithm === config.SHA256) {
- return forge.sha256.create();
- } else {
- throw 'Hash algorithm \'' + algorithm + '\' is unsupported';
- }
- }
|