/*
 * 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('Symmetric cipher ...', function() {
  'use strict';

  var _testString = 'Ox2fUJq1gAbX';
  var _testString_2 = 'mUm9EQC8mrDw';
  var _aesSecretKeyBase64 = 'BBZcaE5El25RZZzWTLTwcA==';
  var _aesSecretKeyBase64_2 = 'v3VagUVMuZJ+b+uFSjqGTw==';
  var _symmetricEncryptedDataBase64 =
      'Cvpz8/L+mTv2eFvYpxNoxt+/KJwtAOzG7hl9Dw==';
  var _symmetricInitVectorBase64 = 'LGF26O6hR2fgUsHd';

  describe('should be able to ..', function() {
    it('Encrypt and decrypt some data.', function() {
      cryptolib('symmetric.cipher', 'commons.utils', function(box) {

        var cipherFactory =
            new box.symmetric.cipher.factory.SymmetricCipherFactory();
        var converters = new box.commons.utils.Converters();

        var aesCipher = cipherFactory.getCryptoSymmetricCipher();

        var dataB64 = converters.base64Encode(_testString);

        // Encrypt data and Base64 encode result.
        var initVectorAndEncryptedDataBase64 =
            aesCipher.encrypt(_aesSecretKeyBase64, dataB64);

        // Base64 decode encrypted data and decrypt data.
        var decryptedDataB64 = aesCipher.decrypt(
            _aesSecretKeyBase64, initVectorAndEncryptedDataBase64);

        var decryptedData = converters.base64Decode(decryptedDataB64);

        // Verify that data was successfully decrypted.
        expect(decryptedData).toBe(_testString);
      });
    });
  });

  it('AES-GCM decrypt some data that was AES-GCM encrypted using Java.',
     function() {
       cryptolib('symmetric.cipher', 'commons.utils', function(box) {

         var cipherFactory =
             new box.symmetric.cipher.factory.SymmetricCipherFactory();

         var aesCipher = cipherFactory.getCryptoSymmetricCipher();

         var converters = new box.commons.utils.Converters();

         var initVectorAndEncryptedDataBase64 =
             _symmetricInitVectorBase64 + _symmetricEncryptedDataBase64;

         var decryptedDataB64 = aesCipher.decrypt(
             _aesSecretKeyBase64_2, initVectorAndEncryptedDataBase64);

         var decryptedData = converters.base64Decode(decryptedDataB64);

         // Verify that data was successfully decrypted.
         expect(decryptedData).toBe(_testString_2);
       });
     });

  it('throw an error when the given key does not match the required length by the cipher algorithm when encrypt',
     function() {
       cryptolib('symmetric.cipher', 'commons.utils', function(box) {

         var cipherFactory =
             new box.symmetric.cipher.factory.SymmetricCipherFactory();
         var converters = new box.commons.utils.Converters();
         var aesCipher = cipherFactory.getCryptoSymmetricCipher();
         var dataB64 = converters.base64Encode(_testString);

         expect(function() {
           aesCipher.encrypt('BBZcaE5El25RzWTLTwcA==', dataB64);
         }).toThrow();
       });
     });

  it('throw an error when the given key does not match the required length by the cipher algorithm when decrypt',
     function() {
       cryptolib('symmetric.cipher', 'commons.utils', function(box) {

         var cipherFactory =
             new box.symmetric.cipher.factory.SymmetricCipherFactory();
         var converters = new box.commons.utils.Converters();
         var aesCipher = cipherFactory.getCryptoSymmetricCipher();
         var dataB64 = converters.base64Encode(_testString);
         var initVectorAndEncryptedDataBase64 =
             aesCipher.encrypt(_aesSecretKeyBase64, dataB64);

         expect(function() {
           aesCipher.decrypt(
               'BBZcaE5El25RzWTLTwcA==', initVectorAndEncryptedDataBase64);
         }).toThrow();
       });
     });

  it('throw an error when the given algorithm is wrong.', function() {
    var f = function(box) {
      var cipherFactory =
          new box.symmetric.cipher.factory.SymmetricCipherFactory();
      var converters = new box.commons.utils.Converters();
      var aesCipher = cipherFactory.getCryptoSymmetricCipher();
      var dataB64 = converters.base64Encode(_testString);

      expect(function() {
        aesCipher.encrypt(_aesSecretKeyBase64, dataB64);
      }).toThrow();
    };
    f.policies = {
      symmetric: {
        cipher: {
          algorithm:
              {WRONG: {name: 'WRONG', keyLengthBytes: 16, tagLengthBytes: 16}},
          provider: 'Forge',
          initializationVectorLengthBytes: 12,
          secureRandom: {provider: 'Scytl'}
        }
      }
    };
    cryptolib('symmetric.cipher', 'commons.utils', f);
  });

  it('throw an error when the given provider is wrong.', function() {
    var f = function(box) {
      var cipherFactory =
          new box.symmetric.cipher.factory.SymmetricCipherFactory();

      expect(function() {
        cipherFactory.getCryptoSymmetricCipher();
      }).toThrow();
    };
    f.policies = {
      symmetric: {
        cipher: {
          algorithm: {
            AES128_GCM:
                {name: 'AES-GCM', keyLengthBytes: 16, tagLengthBytes: 16}
          },
          provider: 'WRONG',
          initializationVectorLengthBytes: 12,
          secureRandom: {provider: 'Scytl'}
        }
      }
    };
    cryptolib('symmetric.cipher', 'commons.utils', f);
  });

  describe('bug #90835', function() {
    it('if the original message contains spaces, they should be preserved',
       function() {
         cryptolib('symmetric.cipher', 'commons.utils', function(box) {
           var text = 'text with some spaces';
           var cipherFactory =
               new box.symmetric.cipher.factory.SymmetricCipherFactory();
           var converters = new box.commons.utils.Converters();

           var aesCipher = cipherFactory.getCryptoSymmetricCipher();

           var dataB64 = converters.base64Encode(text);

           // Encrypt data and Base64 encode result.
           var initVectorAndEncryptedDataBase64 =
               aesCipher.encrypt(_aesSecretKeyBase64, dataB64);

           // Base64 decode encrypted data and decrypt data.
           var decryptedDataB64 = aesCipher.decrypt(
               _aesSecretKeyBase64, initVectorAndEncryptedDataBase64);

           var decryptedData = converters.base64Decode(decryptedDataB64);

           // Verify that data was successfully decrypted.
           expect(decryptedData).toEqual(text);
         });
       });
  });
});
