/********EXTERNAL OBJECT PUBLIC METHODS  - END ********/


        /// <summary>
        /// Gets the BufferedBlockCipher loaded with Padding, Mode and Engine to Encrypt with a Symmetric Block Algorithm
        /// </summary>
        /// <param name="algorithm">string SymmetricBlockAlgorithm enum, symmetric block algorithm name</param>
        /// <param name="mode">string SymmetricBlockModes enum, symmetric block mode name</param>
        /// <param name="padding">string SymmetricBlockPadding enum, symmetric block padding name</param>
        /// <returns>BufferedBlockCipher loaded with Padding, Mode and Engine to Encrypt with a Symmetric Block Algorithm</returns>
        private BufferedBlockCipher getCipher(SymmetricBlockAlgorithm algorithm, SymmetricBlockMode mode,
                                              SymmetricBlockPadding padding)
        {
            IBlockCipher        engine        = getCipherEngine(algorithm);
            IBlockCipherPadding paddingCipher = getPadding(padding);
            IBlockCipher        bc;

            if (mode != SymmetricBlockMode.ECB)
            {
                bc = getCipherMode(engine, mode);
            }
            else
            {
                bc = engine;
            }
            // si el padding es WITHCTS el paddingCipher es null
            if (usesCTS(mode, padding))
            {
                return(new CtsBlockCipher(bc)); // no usa el paddingCipher que es el null
            }
            if (padding == SymmetricBlockPadding.NOPADDING)
            {
                return(new BufferedBlockCipher(bc));
            }
            else
            {
                return(new PaddedBufferedBlockCipher(bc, paddingCipher));
            }
        }
        /// <summary>
        /// Decrypts the given encrypted text with an AEAD encryption algorithm
        /// </summary>
        /// <param name="symmetricBlockAlgorithm">string SymmetricBlockAlgorithm enum, symmetric block algorithm name</param>
        /// <param name="symmetricBlockMode">string SymmetricBlockModes enum, symmetric block mode name</param>
        /// <param name="key">string Hexa key for the algorithm excecution</param>
        /// <param name="macSize">int macSize in bits for MAC length for AEAD Encryption algorithm</param>
        /// <param name="nonce">string Hexa nonce for MAC length for AEAD Encryption algorithm</param>
        /// <param name="encryptedInput">string Base64 text to decrypt</param>
        /// <returns></returns>
        public string DoAEADDecrypt(string symmetricBlockAlgorithm, string symmetricBlockMode,
                                    string key, int macSize, string nonce, string encryptedInput)
        {
            this.error.cleanError();
            SymmetricBlockAlgorithm algorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(symmetricBlockAlgorithm, this.error);
            SymmetricBlockMode      mode      = SymmetricBlockModeUtils.getSymmetricBlockMode(symmetricBlockMode, this.error);

            if (this.error.existsError())
            {
                return("");
            }

            IBlockCipher     engine = getCipherEngine(algorithm);
            IAeadBlockCipher bbc    = getAEADCipherMode(engine, mode);

            if (this.error.existsError() && !(string.Compare(this.error.Code, "SB016", true) == 0))
            {
                return("");
            }
            byte[] nonceBytes = SecurityUtils.GetHexa(nonce, "SB025", this.error);
            byte[] keyBytes   = SecurityUtils.GetHexa(key, "SB025", this.error);
            if (this.HasError())
            {
                return("");
            }
            KeyParameter keyParam = new KeyParameter(keyBytes);

            AeadParameters AEADparams = new AeadParameters(keyParam, macSize, nonceBytes);

            try
            {
                bbc.Init(false, AEADparams);
            }catch (Exception e)
            {
                this.error.setError("SB030", e.Message);
                return("");
            }
            byte[] out2            = Base64.Decode(encryptedInput);
            byte[] comparisonBytes = new byte[bbc.GetOutputSize(out2.Length)];
            int    length          = bbc.ProcessBytes(out2, 0, out2.Length, comparisonBytes, 0);

            try
            {
                bbc.DoFinal(comparisonBytes, length);
            }
            catch (Exception)
            {
                this.error.setError("SB012", "AEAD decryption exception");
                return("");
            }
            this.error.cleanError();
            // return System.Text.Encoding.UTF8.GetString(comparisonBytes).Trim();
            EncodingUtil eu = new EncodingUtil();

            this.error = eu.GetError();

            return(eu.getString(comparisonBytes));
        }
        /// <summary>
        /// Gets the block size lenght for the given algorithm
        /// </summary>
        /// <param name="algorithm">SymmetricBlockAlgorithm enum, algorithm name</param>
        /// <param name="error">Error type for error management</param>
        /// <returns>the specific block size for the algorithm, algorithm unknown if 0</returns>
        public static int getBlockSize(SymmetricBlockAlgorithm algorithm, Error error)
        {
            switch (algorithm)
            {
            case SymmetricBlockAlgorithm.BLOWFISH:
            case SymmetricBlockAlgorithm.CAST5:
            case SymmetricBlockAlgorithm.DES:
            case SymmetricBlockAlgorithm.GOST28147:
            case SymmetricBlockAlgorithm.RC2:
            case SymmetricBlockAlgorithm.RC532:
            case SymmetricBlockAlgorithm.SKIPJACK:
            case SymmetricBlockAlgorithm.XTEA:
            case SymmetricBlockAlgorithm.TRIPLEDES:
            case SymmetricBlockAlgorithm.TEA:
                return(64);

            case SymmetricBlockAlgorithm.AES:
            case SymmetricBlockAlgorithm.CAMELLIA:
            case SymmetricBlockAlgorithm.CAST6:
            case SymmetricBlockAlgorithm.NOEKEON:
            case SymmetricBlockAlgorithm.RC564:
            case SymmetricBlockAlgorithm.RC6:
            case SymmetricBlockAlgorithm.SEED:
            case SymmetricBlockAlgorithm.SERPENT:
            case SymmetricBlockAlgorithm.SM4:
            case SymmetricBlockAlgorithm.TWOFISH:
            case SymmetricBlockAlgorithm.DSTU7624_128:
            case SymmetricBlockAlgorithm.RIJNDAEL_128:
                return(128);

            case SymmetricBlockAlgorithm.RIJNDAEL_160:
                return(160);

            case SymmetricBlockAlgorithm.RIJNDAEL_192:
                return(192);

            case SymmetricBlockAlgorithm.RIJNDAEL_224:
                return(224);

            case SymmetricBlockAlgorithm.DSTU7624_256:
            case SymmetricBlockAlgorithm.RIJNDAEL_256:
            case SymmetricBlockAlgorithm.THREEFISH_256:
                return(256);

            case SymmetricBlockAlgorithm.DSTU7624_512:
            case SymmetricBlockAlgorithm.THREEFISH_512:
                return(512);

            case SymmetricBlockAlgorithm.THREEFISH_1024:
                return(1024);

            default:
                error.setError("SB003", "Unrecognized SymmetricBlockAlgorithm");
                return(0);
            }
        }
        private bool isValidAlgorithm(string algorithm)
        {
            SymmetricBlockAlgorithm symmetricBlockAlgorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(algorithm,
                                                                                                                      this.error);
            int blockSize = SymmetricBlockAlgorithmUtils.getBlockSize(symmetricBlockAlgorithm, this.error);

            if (this.HasError())
            {
                return(false);
            }
            if (blockSize != 64 && blockSize != 128)
            {
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Gets the key lenght for the given algorithm
        /// </summary>
        /// <param name="algorithm">SymmetricBlockAlgorithm enum, algorithm name</param>
        /// <param name="error">Error type for error management</param>
        /// <returns>array int with fixed length 3 with key, if array[0]=0 is range, else fixed values</returns>
        public static int[] getKeySize(SymmetricBlockAlgorithm algorithm, Error error)
        {
            int[] keySize = new int[3];

            switch (algorithm)
            {
            case SymmetricBlockAlgorithm.BLOWFISH:
                keySize[0] = 0;
                keySize[1] = 448;
                break;

            case SymmetricBlockAlgorithm.CAMELLIA:
            case SymmetricBlockAlgorithm.SERPENT:
            case SymmetricBlockAlgorithm.TWOFISH:
                keySize[0] = 128;
                keySize[1] = 192;
                keySize[2] = 256;
                break;

            case SymmetricBlockAlgorithm.AES:
            case SymmetricBlockAlgorithm.CAST6:
            case SymmetricBlockAlgorithm.RC6:
            case SymmetricBlockAlgorithm.RIJNDAEL_128:
            case SymmetricBlockAlgorithm.RIJNDAEL_160:
            case SymmetricBlockAlgorithm.RIJNDAEL_192:
            case SymmetricBlockAlgorithm.RIJNDAEL_224:
            case SymmetricBlockAlgorithm.RIJNDAEL_256:
                keySize[0] = 0;
                keySize[1] = 256;
                break;

            case SymmetricBlockAlgorithm.DES:
                keySize[0] = 64;
                break;

            case SymmetricBlockAlgorithm.TRIPLEDES:
                keySize[0] = 128;
                keySize[1] = 192;
                break;

            case SymmetricBlockAlgorithm.DSTU7624_128:
            case SymmetricBlockAlgorithm.DSTU7624_256:
            case SymmetricBlockAlgorithm.DSTU7624_512:
                keySize[0] = 128;
                keySize[1] = 256;
                keySize[2] = 512;
                break;

            case SymmetricBlockAlgorithm.GOST28147:
                keySize[0] = 256;
                break;

            case SymmetricBlockAlgorithm.NOEKEON:
            case SymmetricBlockAlgorithm.SEED:
            case SymmetricBlockAlgorithm.SM4:
            case SymmetricBlockAlgorithm.XTEA:
            case SymmetricBlockAlgorithm.TEA:
                keySize[0] = 128;
                break;

            case SymmetricBlockAlgorithm.RC2:
                keySize[0] = 0;
                keySize[1] = 1024;
                break;

            case SymmetricBlockAlgorithm.RC532:
            case SymmetricBlockAlgorithm.RC564:
            case SymmetricBlockAlgorithm.SKIPJACK:
            case SymmetricBlockAlgorithm.CAST5:
                keySize[0] = 0;
                keySize[1] = 128;
                break;

            case SymmetricBlockAlgorithm.THREEFISH_256:
            case SymmetricBlockAlgorithm.THREEFISH_512:
            case SymmetricBlockAlgorithm.THREEFISH_1024:
                keySize[0] = 128;
                keySize[1] = 512;
                keySize[2] = 1024;
                break;

                /*default:
                 *  error.setError("SB004", "Unrecognized SymmetricBlockAlgorithm");*/
            }
            return(keySize);
        }
        /// <summary>
        /// Mapping between SymmetricBlockAlgorithm enum representation and string name
        /// </summary>
        /// <param name="symmetricBlockAlgorithm">SymmetricBlockAlgorithm enum, algorithm name</param>
        /// <param name="error">Error type for error management</param>
        /// <returns>value of SymmetricBlockAlgorithm in string</returns>
        public static string valueOf(SymmetricBlockAlgorithm symmetricBlockAlgorithm, Error error)
        {
            switch (symmetricBlockAlgorithm)
            {
            case SymmetricBlockAlgorithm.AES:
                return("AES");

            case SymmetricBlockAlgorithm.BLOWFISH:
                return("BLOWFISH");

            case SymmetricBlockAlgorithm.CAMELLIA:
                return("CAMELLIA");

            case SymmetricBlockAlgorithm.CAST5:
                return("CAST5");

            case SymmetricBlockAlgorithm.CAST6:
                return("CAST6");

            case SymmetricBlockAlgorithm.DES:
                return("DES");

            case SymmetricBlockAlgorithm.TRIPLEDES:
                return("TRIPLEDES");

            case SymmetricBlockAlgorithm.DSTU7624_128:
                return("DSTU7624_128");

            case SymmetricBlockAlgorithm.DSTU7624_256:
                return("DSTU7624_256");

            case SymmetricBlockAlgorithm.DSTU7624_512:
                return("DSTU7624_512");

            case SymmetricBlockAlgorithm.GOST28147:
                return("GOST28147");

            case SymmetricBlockAlgorithm.NOEKEON:
                return("NOEKEON");

            case SymmetricBlockAlgorithm.RC2:
                return("RC2");

            case SymmetricBlockAlgorithm.RC6:
                return("RC6");

            case SymmetricBlockAlgorithm.RC532:
                return("RC532");

            case SymmetricBlockAlgorithm.RC564:
                return("RC564");

            case SymmetricBlockAlgorithm.RIJNDAEL_128:
                return("RIJNDAEL_128");

            case SymmetricBlockAlgorithm.RIJNDAEL_160:
                return("RIJNDAEL_160");

            case SymmetricBlockAlgorithm.RIJNDAEL_192:
                return("RIJNDAEL_192");

            case SymmetricBlockAlgorithm.RIJNDAEL_224:
                return("RIJNDAEL_224");

            case SymmetricBlockAlgorithm.RIJNDAEL_256:
                return("RIJNDAEL_256");

            case SymmetricBlockAlgorithm.SEED:
                return("SEED");

            case SymmetricBlockAlgorithm.SERPENT:
                return("SERPENT");

            case SymmetricBlockAlgorithm.SKIPJACK:
                return("SKIPJACK");

            case SymmetricBlockAlgorithm.SM4:
                return("SM4");

            case SymmetricBlockAlgorithm.THREEFISH_256:
                return("THREEFISH_256");

            case SymmetricBlockAlgorithm.THREEFISH_512:
                return("THREEFISH_512");

            case SymmetricBlockAlgorithm.THREEFISH_1024:
                return("THREEFISH_1024");

            case SymmetricBlockAlgorithm.TWOFISH:
                return("TWOFISH");

            case SymmetricBlockAlgorithm.XTEA:
                return("XTEA");

            case SymmetricBlockAlgorithm.TEA:
                return("TEA");

            default:
                error.setError("SB002", "Unrecognized SymmetricBlockAlgorithm");
                return("SymmetricBlockAlgorithm");
            }
        }
        /********EXTERNAL OBJECT PUBLIC METHODS  - BEGIN ********/



        /// <summary>
        /// Encrypts the given text with an AEAD encryption algorithm
        /// </summary>
        /// <param name="symmetricBlockAlgorithm">string SymmetricBlockAlgorithm enum, symmetric block algorithm name</param>
        /// <param name="symmetricBlockMode">string SymmetricBlockModes enum, symmetric block mode name</param>
        /// <param name="key">string Hexa key for the algorithm excecution</param>
        /// <param name="macSize">int macSize in bits for MAC length for AEAD Encryption algorithm</param>
        /// <param name="nonce">string Hexa nonce for MAC length for AEAD Encryption algorithm</param>
        /// <param name="plainText"> string UTF-8 plain text to encrypt</param>
        /// <returns></returns>
        public string DoAEADEncrypt(string symmetricBlockAlgorithm, string symmetricBlockMode,
                                    string key, int macSize, string nonce, string plainText)
        {
            this.error.cleanError();
            SymmetricBlockAlgorithm algorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(symmetricBlockAlgorithm, this.error);
            SymmetricBlockMode      mode      = SymmetricBlockModeUtils.getSymmetricBlockMode(symmetricBlockMode, this.error);

            if (this.error.existsError())
            {
                return("");
            }

            IBlockCipher     engine = getCipherEngine(algorithm);
            IAeadBlockCipher bbc    = getAEADCipherMode(engine, mode);

            if (this.error.existsError() && !(string.Compare(this.error.Code, "SB016", true) == 0))
            {
                return("");
            }
            byte[] nonceBytes = SecurityUtils.GetHexa(nonce, "SB024", this.error);
            byte[] keyBytes   = SecurityUtils.GetHexa(key, "SB024", this.error);
            if (this.HasError())
            {
                return("");
            }

            KeyParameter keyParam = new KeyParameter(keyBytes);

            AeadParameters AEADparams = new AeadParameters(keyParam, macSize, nonceBytes);

            try
            {
                bbc.Init(true, AEADparams);
            }catch (Exception e)
            {
                this.error.setError("SB029", e.Message);
                return("");
            }
            EncodingUtil eu = new EncodingUtil();

            byte[] inputBytes = eu.getBytes(plainText);
            if (eu.GetError().existsError())
            {
                this.error = eu.GetError();
                return("");
            }
            byte[] outputBytes = new byte[bbc.GetOutputSize(inputBytes.Length)];
            int    length      = bbc.ProcessBytes(inputBytes, 0, inputBytes.Length, outputBytes, 0);

            try
            {
                bbc.DoFinal(outputBytes, length);
            }
            catch (Exception)
            {
                this.error.setError("SB010", "AEAD encryption exception");
                return("");
            }
            string result = Base64.ToBase64String(outputBytes);

            if (result == null || result.Length == 0)
            {
                this.error.setError("SB011", "Error encoding base64");
                return("");
            }
            this.error.cleanError();
            return(result);
        }
        /// <summary>
        /// Build the engine
        /// </summary>
        /// <param name="algorithm">SymmetricBlockAlgorithm enum, algorithm name</param>
        /// <returns>IBlockCipher with the algorithm Engine</returns>
        internal IBlockCipher getCipherEngine(SymmetricBlockAlgorithm algorithm)
        {
            IBlockCipher engine = null;

            switch (algorithm)
            {
            case SymmetricBlockAlgorithm.AES:
                engine = new AesEngine();
                break;

            case SymmetricBlockAlgorithm.BLOWFISH:
                engine = new BlowfishEngine();
                break;

            case SymmetricBlockAlgorithm.CAMELLIA:
                engine = new CamelliaEngine();
                break;

            case SymmetricBlockAlgorithm.CAST5:
                engine = new Cast5Engine();
                break;

            case SymmetricBlockAlgorithm.CAST6:
                engine = new Cast6Engine();
                break;

            case SymmetricBlockAlgorithm.DES:
                engine = new DesEngine();
                break;

            case SymmetricBlockAlgorithm.TRIPLEDES:
                engine = new DesEdeEngine();
                break;

            case SymmetricBlockAlgorithm.DSTU7624_128:
                engine = new Dstu7624Engine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.DSTU7624_128, this.error));
                break;

            case SymmetricBlockAlgorithm.DSTU7624_256:
                engine = new Dstu7624Engine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.DSTU7624_256, this.error));
                break;

            case SymmetricBlockAlgorithm.DSTU7624_512:
                engine = new Dstu7624Engine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.DSTU7624_512, this.error));
                break;

            case SymmetricBlockAlgorithm.GOST28147:
                engine = new Gost28147Engine();
                break;

            case SymmetricBlockAlgorithm.NOEKEON:
                engine = new NoekeonEngine();
                break;

            case SymmetricBlockAlgorithm.RC2:
                engine = new RC2Engine();
                break;

            case SymmetricBlockAlgorithm.RC532:
                engine = new RC532Engine();
                break;

            case SymmetricBlockAlgorithm.RC564:
                engine = new RC564Engine();
                break;

            case SymmetricBlockAlgorithm.RC6:
                engine = new RC6Engine();
                break;

            case SymmetricBlockAlgorithm.RIJNDAEL_128:
                engine = new RijndaelEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.RIJNDAEL_128, this.error));
                break;

            case SymmetricBlockAlgorithm.RIJNDAEL_160:
                engine = new RijndaelEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.RIJNDAEL_160, this.error));
                break;

            case SymmetricBlockAlgorithm.RIJNDAEL_192:
                engine = new RijndaelEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.RIJNDAEL_192, this.error));
                break;

            case SymmetricBlockAlgorithm.RIJNDAEL_224:
                engine = new RijndaelEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.RIJNDAEL_224, this.error));
                break;

            case SymmetricBlockAlgorithm.RIJNDAEL_256:
                engine = new RijndaelEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.RIJNDAEL_256, this.error));
                break;

            case SymmetricBlockAlgorithm.SEED:
                engine = new SeedEngine();
                break;

            case SymmetricBlockAlgorithm.SERPENT:
                engine = new SerpentEngine();
                break;

            case SymmetricBlockAlgorithm.SKIPJACK:
                engine = new SkipjackEngine();
                break;

            case SymmetricBlockAlgorithm.SM4:
                engine = new SM4Engine();
                break;

            case SymmetricBlockAlgorithm.TEA:
                engine = new TeaEngine();
                break;

            case SymmetricBlockAlgorithm.THREEFISH_256:
                engine = new ThreefishEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.THREEFISH_256, this.error));
                break;

            case SymmetricBlockAlgorithm.THREEFISH_512:
                engine = new ThreefishEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.THREEFISH_512, this.error));
                break;

            case SymmetricBlockAlgorithm.THREEFISH_1024:
                engine = new ThreefishEngine(SymmetricBlockAlgorithmUtils.getBlockSize(SymmetricBlockAlgorithm.THREEFISH_1024, this.error));
                break;

            case SymmetricBlockAlgorithm.TWOFISH:
                engine = new TwofishEngine();
                break;

            case SymmetricBlockAlgorithm.XTEA:
                engine = new XteaEngine();
                break;

            default:
                this.error.setError("SB020", "Cipher " + algorithm + " not recognised.");
                break;
            }
            return(engine);
        }
        public string DoDecrypt(string symmetricBlockAlgorithm, string symmetricBlockMode,
                                string symmetricBlockPadding, string key, string IV, string encryptedInput)
        {
            this.error.cleanError();
            SymmetricBlockAlgorithm algorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(symmetricBlockAlgorithm, this.error);
            SymmetricBlockMode      mode      = SymmetricBlockModeUtils.getSymmetricBlockMode(symmetricBlockMode, this.error);
            SymmetricBlockPadding   padding   = SymmetricBlockPaddingUtils.getSymmetricBlockPadding(symmetricBlockPadding, this.error);

            if (this.error.existsError())
            {
                return("");
            }

            BufferedBlockCipher bbc = getCipher(algorithm, mode, padding);

            if (this.error.existsError() && !(string.Compare(this.error.Code, "SB016", true) == 0))
            {
                return("");
            }
            byte[] bytesKey = SecurityUtils.GetHexa(key, "SB023", this.error);
            byte[] bytesIV  = SecurityUtils.GetHexa(IV, "SB023", this.error);
            if (this.HasError())
            {
                return("");
            }

            KeyParameter keyParam = new KeyParameter(bytesKey);

            if (SymmetricBlockMode.ECB != mode && SymmetricBlockMode.OPENPGPCFB != mode)
            {
                ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, bytesIV);
                try
                {
                    bbc.Init(false, keyParamWithIV);
                }catch (Exception e)
                {
                    this.error.setError("SB027", e.Message);
                    return("");
                }
            }
            else
            {
                try
                {
                    bbc.Init(false, keyParam);
                }catch (Exception e)
                {
                    this.error.setError("SB028", e.Message);
                    return("");
                }
            }

            byte[] out2            = Base64.Decode(encryptedInput);
            byte[] comparisonBytes = new byte[bbc.GetOutputSize(out2.Length)];
            int    length          = bbc.ProcessBytes(out2, 0, out2.Length, comparisonBytes, 0);

            try
            {
                bbc.DoFinal(comparisonBytes, length);
            }
            catch (Exception)
            {
                this.error.setError("SB015", "Block decryption exception");
                return("");
            }
            this.error.cleanError();

            EncodingUtil eu = new EncodingUtil();

            this.error = eu.GetError();
            return(eu.getString(comparisonBytes));
        }
        public string DoEncrypt(string symmetricBlockAlgorithm, string symmetricBlockMode,
                                string symmetricBlockPadding, string key, string IV, string plainText)
        {
            this.error.cleanError();
            SymmetricBlockAlgorithm algorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(symmetricBlockAlgorithm, this.error);
            SymmetricBlockMode      mode      = SymmetricBlockModeUtils.getSymmetricBlockMode(symmetricBlockMode, this.error);
            SymmetricBlockPadding   padding   = SymmetricBlockPaddingUtils.getSymmetricBlockPadding(symmetricBlockPadding, this.error);

            if (this.error.existsError())
            {
                return("");
            }

            BufferedBlockCipher bbc = getCipher(algorithm, mode, padding);

            if (this.error.existsError() && !(string.Compare(this.error.Code, "SB016", true) == 0))
            {
                return("");
            }
            byte[] byteIV  = SecurityUtils.GetHexa(IV, "SB022", this.error);
            byte[] byteKey = SecurityUtils.GetHexa(key, "SB022", this.error);
            if (this.HasError())
            {
                return("");
            }
            KeyParameter keyParam = new KeyParameter(byteKey);

            if (SymmetricBlockMode.ECB != mode && SymmetricBlockMode.OPENPGPCFB != mode)
            {
                ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, byteIV);
                try{
                    bbc.Init(true, keyParamWithIV);
                }catch (Exception e)
                {
                    this.error.setError("SB025", e.Message);
                    return("");
                }
            }
            else
            {
                try
                {
                    bbc.Init(true, keyParam);
                }catch (Exception e)
                {
                    this.error.setError("SB026", e.Message);
                    return("");
                }
            }

            EncodingUtil eu = new EncodingUtil();

            byte[] inputBytes = eu.getBytes(plainText);
            if (eu.GetError().existsError())
            {
                this.error = eu.GetError();
                return("");
            }
            byte[] outputBytes = new byte[bbc.GetOutputSize(inputBytes.Length)];
            int    length      = bbc.ProcessBytes(inputBytes, 0, inputBytes.Length, outputBytes, 0);

            try
            {
                bbc.DoFinal(outputBytes, length);
            }
            catch (Exception)
            {
                this.error.setError("SB013", "Block encryption exception");
                return("");
            }
            string result = Base64.ToBase64String(outputBytes);

            if (result == null || result.Length == 0)
            {
                this.error.setError("SB014", "Error encoding base64");
                return("");
            }
            this.error.cleanError();
            return(result);
        }
        public string calculate(string plainText, string key, string algorithm, int macSize)
        {
            if (!isValidAlgorithm(algorithm))
            {
                this.error.setError("CM001", "Invalid Symmetric block algorithm for CMAC");
                return("");
            }
            SymmetricBlockAlgorithm symmetricBlockAlgorithm = SymmetricBlockAlgorithmUtils.getSymmetricBlockAlgorithm(algorithm,
                                                                                                                      this.error);
            SymmetricBlockCipher symCipher   = new SymmetricBlockCipher();
            IBlockCipher         blockCipher = symCipher.getCipherEngine(symmetricBlockAlgorithm);

            if (symCipher.HasError())
            {
                this.error = symCipher.GetError();
                return("");
            }
            if (macSize > blockCipher.GetBlockSize() * 8)
            {
                this.error.setError("CM002", "The mac length must be less or equal than the algorithm block size.");
                return("");
            }
            byte[] byteKey = SecurityUtils.GetHexa(key, "CM003", this.error);
            if (this.HasError())
            {
                return("");
            }

            EncodingUtil eu = new EncodingUtil();

            byte[] byteInput = eu.getBytes(plainText);

            ICipherParameters parms = new KeyParameter(byteKey);

            CMac mac = null;

            if (macSize != 0)
            {
                mac = new CMac(blockCipher, macSize);
            }
            else
            {
                mac = new CMac(blockCipher);
            }
            try
            {
                mac.Init(parms);
            }catch (Exception e)
            {
                this.error.setError("CM004", e.Message);
                return("");
            }
            byte[] resBytes = new byte[mac.GetMacSize()];
            mac.BlockUpdate(byteInput, 0, byteInput.Length);
            mac.DoFinal(resBytes, 0);
            string result = toHexastring(resBytes);

            if (!this.error.existsError())
            {
                return(result);
            }
            return("");
        }