/*************************************************
* Algorithms List Source File                    *
* (C) 1999-2004 The Botan Project                *
*************************************************/

#include <botan/lookup.h>
#include <botan/look_add.h>
#include <botan/look_pk.h>

#include <botan/aes.h>
#include <botan/blowfish.h>
#include <botan/cast128.h>
#include <botan/cast256.h>
#include <botan/des.h>
#include <botan/gost.h>
#include <botan/idea.h>
#include <botan/lion.h>
#include <botan/lubyrack.h>
#include <botan/misty1.h>
#include <botan/rc2.h>
#include <botan/rc5.h>
#include <botan/rc6.h>
#include <botan/safer_sk.h>
#include <botan/serpent.h>
#include <botan/skipjack.h>
#include <botan/square.h>
#include <botan/tea.h>
#include <botan/twofish.h>
#include <botan/xtea.h>

#include <botan/arc4.h>
#include <botan/isaac.h>
#include <botan/seal.h>
#include <botan/wid_wake.h>

#include <botan/adler32.h>
#include <botan/crc24.h>
#include <botan/crc32.h>
#include <botan/has160.h>
#include <botan/haval.h>
#include <botan/md2.h>
#include <botan/md4.h>
#include <botan/md5.h>
#include <botan/rmd128.h>
#include <botan/rmd160.h>
#include <botan/sha160.h>
#include <botan/sha256.h>
#include <botan/sha_64.h>
#include <botan/tiger.h>
#include <botan/whrlpool.h>
#include <botan/par_hash.h>

#include <botan/hmac.h>
#include <botan/omac.h>
#include <botan/ssl3_mac.h>
#include <botan/x919_mac.h>

#include <botan/mode_pad.h>

#include <botan/pgp_s2k.h>
#include <botan/pkcs5.h>

namespace Botan {

/*************************************************
* Load the algorithms list                       *
*************************************************/
void load_algorithms_list()
   {
   add_algorithm(new AES);
   add_algorithm(new AES_128);
   add_algorithm(new AES_192);
   add_algorithm(new AES_256);
   add_algorithm(new Blowfish);
   add_algorithm(new CAST_128);
   add_algorithm(new CAST_256);
   add_algorithm(new DES);
   add_algorithm(new DESX);
   add_algorithm(new TripleDES);
   add_algorithm(new GOST);
   add_algorithm(new IDEA);
   add_algorithm(new RC2);
   add_algorithm(new RC6);
   add_algorithm(new Serpent);
   add_algorithm(new Skipjack);
   add_algorithm(new Square);
   add_algorithm(new TEA);
   add_algorithm(new Twofish);
   add_algorithm(new XTEA);

   add_algorithm(new ARC4);
   add_algorithm(new ISAAC);
   add_algorithm(new WiderWake_41_BE);

   add_algorithm(new ANSI_X919_MAC);

   add_algorithm(new Adler32);
   add_algorithm(new CRC24);
   add_algorithm(new CRC32);
   add_algorithm(new HAS_160);
   add_algorithm(new MD2);
   add_algorithm(new MD4);
   add_algorithm(new MD5);
   add_algorithm(new RIPEMD_128);
   add_algorithm(new RIPEMD_160);
   add_algorithm(new SHA_160);
   add_algorithm(new SHA_256);
   add_algorithm(new SHA_384);
   add_algorithm(new SHA_512);
   add_algorithm(new Whirlpool);

   add_algorithm(new PKCS7_Padding);
   add_algorithm(new OneAndZeros_Padding);
   add_algorithm(new ANSI_X923_Padding);
   add_algorithm(new Null_Padding);
   }

/*************************************************
* Some macros to simplify control flow           *
*************************************************/
#define HANDLE_TYPE_ONE_U32BIT(NAME, TYPE, DEFAULT) \
   if(algo_name == NAME)                            \
      {                                             \
      if(name.size() == 1)                          \
         return new TYPE(DEFAULT);                  \
      if(name.size() == 2)                          \
         return new TYPE(to_u32bit(name[1]));       \
      throw Invalid_Algorithm_Name(algo_spec);      \
      }

#define HANDLE_TYPE_TWO_U32BIT(NAME, TYPE, DEFAULT)               \
   if(algo_name == NAME)                                          \
      {                                                           \
      if(name.size() == 1)                                        \
         return new TYPE(DEFAULT);                                \
      if(name.size() == 2)                                        \
         return new TYPE(to_u32bit(name[1]));                     \
      if(name.size() == 3)                                        \
         return new TYPE(to_u32bit(name[1]), to_u32bit(name[2])); \
      throw Invalid_Algorithm_Name(algo_spec);                    \
      }

#define HANDLE_TYPE_ONE_STRING(NAME, TYPE)     \
   if(algo_name == NAME)                       \
      {                                        \
      if(name.size() == 2)                     \
         return new TYPE(name[1]);             \
      throw Invalid_Algorithm_Name(algo_spec); \
      }

/*************************************************
* Try to get a currently unloaded block cipher   *
*************************************************/
BlockCipher* try_to_get_bc(const std::string& algo_spec)
   {
   std::vector<std::string> name = parse_algorithm_name(algo_spec);
   if(name.size() == 0)
      return 0;

   const std::string algo_name = deref_alias(name[0]);
   HANDLE_TYPE_ONE_U32BIT("MISTY1", MISTY1, 8);
   HANDLE_TYPE_ONE_U32BIT("SAFER-SK", SAFER_SK, 10);
   HANDLE_TYPE_ONE_U32BIT("RC5", RC5, 12);
   HANDLE_TYPE_ONE_STRING("Luby-Rackoff", LubyRackoff);

   if(algo_name == "Lion")
      {
      if(name.size() != 4)
         throw Invalid_Algorithm_Name(algo_spec);
      return new Lion(name[1], name[2], to_u32bit(name[3]));
      }
   return 0;
   }

/*************************************************
* Try to get a currently unloaded stream cipher  *
*************************************************/
StreamCipher* try_to_get_sc(const std::string& algo_spec)
   {
   std::vector<std::string> name = parse_algorithm_name(algo_spec);
   if(name.size() == 0)
      return 0;

   const std::string algo_name = deref_alias(name[0]);
   HANDLE_TYPE_ONE_U32BIT("RC4_drop", ARC4, 768);
   HANDLE_TYPE_ONE_U32BIT("MARK-4", ARC4, 256);
   HANDLE_TYPE_ONE_U32BIT("SEAL-3.0-BE", SEAL, 4096);
   return 0;
   }

/*************************************************
* Try to get a currently unloaded hash           *
*************************************************/
HashFunction* try_to_get_hash(const std::string& algo_spec)
   {
   std::vector<std::string> name = parse_algorithm_name(algo_spec);
   if(name.size() == 0)
      return 0;

   const std::string algo_name = deref_alias(name[0]);
   HANDLE_TYPE_TWO_U32BIT("HAVAL", HAVAL, 32);
   HANDLE_TYPE_TWO_U32BIT("Tiger", Tiger, 24);

   if(algo_name == "Parallel")
      {
      if(name.size() < 2)
         throw Invalid_Algorithm_Name(algo_spec);
      name.erase(name.begin());
      return new Parallel(name);
      }
   return 0;
   }

/*************************************************
* Try to get a currently unloaded MAC            *
*************************************************/
MessageAuthenticationCode* try_to_get_mac(const std::string& algo_spec)
   {
   std::vector<std::string> name = parse_algorithm_name(algo_spec);
   if(name.size() == 0)
      return 0;

   const std::string algo_name = deref_alias(name[0]);
   HANDLE_TYPE_ONE_STRING("OMAC", OMAC);
   HANDLE_TYPE_ONE_STRING("HMAC", HMAC);
   HANDLE_TYPE_ONE_STRING("SSL3-MAC", SSL3_MAC);
   return 0;
   }

/*************************************************
* Try to get a currently unloaded S2K            *
*************************************************/
S2K* try_to_get_s2k(const std::string& algo_spec)
   {
   std::vector<std::string> name = parse_algorithm_name(algo_spec);
   if(name.size() == 0)
      return 0;

   const std::string algo_name = deref_alias(name[0]);
   HANDLE_TYPE_ONE_STRING("OpenPGP-S2K", OpenPGP_S2K);
   HANDLE_TYPE_ONE_STRING("PBKDF1", PKCS5_PBKDF1);
   HANDLE_TYPE_ONE_STRING("PBKDF2", PKCS5_PBKDF2);
   return 0;
   }

}
