123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /*
- * 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
- */
- cryptolib.modules.symmetric = cryptolib.modules.symmetric || {};
- /**
- * Defines the symmetric ciphers.
- *
- * @namespace symmetric/cipher
- */
- cryptolib.modules.symmetric.cipher = function(box) {
- 'use strict';
- box.symmetric = box.symmetric || {};
- box.symmetric.cipher = {};
- /**
- * Allows a symmetric cipher factory to be obtained.
- *
- * @exports symmetric/cipher/factory
- */
- box.symmetric.cipher.factory = {};
- var policies = {
- cipher: {
- algorithm: box.policies.symmetric.cipher.algorithm,
- provider: box.policies.symmetric.cipher.provider,
- initializationVectorLengthBytes:
- box.policies.symmetric.cipher.initializationVectorLengthBytes
- }
- };
- for (var prop in policies.cipher.algorithm) {
- if (typeof prop !== 'undefined') {
- policies.cipher.algorithm = policies.cipher.algorithm[prop];
- }
- }
- var utils, exceptions, randomFactory;
- var f = function(box) {
- utils = box.commons.utils;
- exceptions = box.commons.exceptions;
- randomFactory =
- new box.primitives.securerandom.factory.SecureRandomFactory();
- };
- f.policies = {
- primitives: {
- secureRandom:
- {provider: box.policies.symmetric.cipher.secureRandom.provider}
- }
- };
- cryptolib('commons', 'primitives.securerandom', f);
- /**
- * Factory class that allows a symmetric cipher to be obtained.
- *
- * @class
- */
- box.symmetric.cipher.factory.SymmetricCipherFactory = function() {};
- box.symmetric.cipher.factory.SymmetricCipherFactory.prototype = {
- /**
- * Create a new symmetric cipher.
- * <p>
- * The particular cipher that is returned depends on the policies.
- *
- * @function
- * @returns a new symmetric cipher.
- */
- getCryptoSymmetricCipher: function() {
- var secureRandom;
- try {
- if (policies.cipher.provider ===
- Config.symmetric.cipher.provider.FORGE) {
- secureRandom = randomFactory.getCryptoRandomBytes();
- return this.getCryptoForgeSymmetricCipher(secureRandom);
- } else {
- throw new exceptions.CryptoLibException(
- 'No suitable provider was provided.');
- }
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'A CryptoSymmetricCipher could not be obtained.', error);
- }
- },
- /**
- * Create a new CryptoForgeSymmetricCipher.
- *
- * @function
- * @param secureRandom
- * {CryptoScytlRandomBytes} a secure source of random bytes.
- * @returns {symmetric/cipher.CryptoForgeSymmetricCipher} a new
- * CryptoForgeSymmetricCipher.
- */
- getCryptoForgeSymmetricCipher: function(secureRandom) {
- return new CryptoForgeSymmetricCipher(secureRandom);
- }
- };
- /**
- * @class
- * @param randomGenerator
- * {CryptoScytlRandomBytes} a secure random bytes generator.
- * @memberof symmetric/cipher
- */
- function CryptoForgeSymmetricCipher(randomGenerator) {
- this.converters = new utils.Converters();
- this.bitOperators = new utils.BitOperators();
- this.randomGenerator = randomGenerator;
- }
- CryptoForgeSymmetricCipher.prototype = {
- /**
- * Encrypts some data.
- *
- * @function
- * @param data
- * {String} Data to be encrypted, as string in Base64 encoded
- * format.
- * @param keyB64
- * {String} Key, as string in Base64 encoded format.
- * @returns Initialization vector concatenated with the encrypted data,
- * as string in Base64 encoded format.
- */
- encrypt: function(keyB64, dataB64) {
- try {
- var key = this.converters.base64Decode(keyB64);
- var data = this.converters.base64Decode(dataB64);
- if (key.length !== policies.cipher.algorithm.keyLengthBytes) {
- throw new exceptions.CryptolibException(
- 'Key length does not match the required by the algorithm.');
- }
- var initVec = this.randomGenerator.nextRandom(
- policies.cipher.initializationVectorLengthBytes);
- // Create a byte buffer for data.
- var dataBuffer = new box.forge.util.ByteBuffer(data);
- var cipher =
- box.forge.cipher.createCipher(policies.cipher.algorithm.name, key);
- // Only for the GCM mode
- var gcmAuthTagByteLength = policies.cipher.algorithm.tagLengthBytes;
- if (typeof gcmAuthTagBitLength !== 'undefined') {
- cipher.start({iv: initVec, tagLength: gcmAuthTagByteLength});
- } else {
- cipher.start({iv: initVec});
- }
- cipher.update(dataBuffer);
- cipher.finish();
- var encryptedData = cipher.output.getBytes().toString();
- if (typeof gcmAuthTagByteLength !== 'undefined') {
- var gcmAuthTag = cipher.mode.tag.getBytes();
- encryptedData = encryptedData + gcmAuthTag.toString();
- }
- var initVectorAndEncryptedData = initVec + encryptedData;
- var initVectorAndEncryptedDataBase64 =
- this.converters.base64Encode(initVectorAndEncryptedData);
- return initVectorAndEncryptedDataBase64;
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Data could not be symmetrically encrypted.', error);
- }
- },
- /**
- * Decrypts some encrypted data, using the initialization vector that is
- * provided
- *
- * @function
- * @param keyB64
- * {String} the key as a string in Base64 encoded format.
- * @param initVectorAndEncryptedDataBase64
- * {String} Initialization vector concatenated with the
- * encrypted data, as string in Base64 encoded format.
- * @returns Decrypted data, as string in Base64 encoded format.
- */
- decrypt: function(keyB64, initVectorAndEncryptedDataBase64) {
- try {
- var key = this.converters.base64Decode(keyB64);
- if (key.length !== policies.cipher.algorithm.keyLengthBytes) {
- throw new exceptions.CryptolibException(
- 'Key length does not match the required by the algorithm.');
- }
- var cipher = box.forge.cipher.createDecipher(
- policies.cipher.algorithm.name, key);
- var initVectorAndEncryptedData =
- this.converters.base64Decode(initVectorAndEncryptedDataBase64);
- var initVector = this.bitOperators.extract(
- initVectorAndEncryptedData, 0,
- policies.cipher.initializationVectorLengthBytes);
- var encryptedData = this.bitOperators.extract(
- initVectorAndEncryptedData,
- policies.cipher.initializationVectorLengthBytes,
- initVectorAndEncryptedData.length);
- // Only for the GCM mode
- var gcmAuthTagByteLength = policies.cipher.algorithm.tagLengthBytes;
- if (typeof gcmAuthTagByteLength !== 'undefined') {
- var offset = encryptedData.length - gcmAuthTagByteLength;
- var gcmAuthTag = this.bitOperators.extract(
- encryptedData, offset, encryptedData.length);
- encryptedData = this.bitOperators.extract(encryptedData, 0, offset);
- var gcmAuthTagBitLength =
- gcmAuthTagByteLength * box.NUMBER_OF_BITS_PER_BYTE;
- cipher.start({
- iv: initVector,
- tagLength: gcmAuthTagBitLength,
- tag: gcmAuthTag
- });
- } else {
- cipher.start({iv: initVector});
- }
- var encryptedDataBuffer = new box.forge.util.ByteBuffer(encryptedData);
- cipher.update(encryptedDataBuffer);
- cipher.finish();
- var outputBase64 =
- this.converters.base64Encode(cipher.output.getBytes().toString());
- return outputBase64;
- } catch (error) {
- throw new exceptions.CryptoLibException(
- 'Data could not be symmetrically decrypted.', error);
- }
- }
- };
- };
|