/*************************************************
* Base Classes Source File                       *
* (C) 1999-2003 The Botan Project                *
*************************************************/

#include <botan/base.h>
#include <botan/version.h>

namespace Botan {

/*************************************************
* SymmetricAlgorithm Constructor                 *
*************************************************/
SymmetricAlgorithm::SymmetricAlgorithm(u32bit key_min, u32bit key_max,
                                       u32bit key_mod) :
   MAXIMUM_KEYLENGTH(key_max ? key_max : key_min),
   MINIMUM_KEYLENGTH(key_min),
   KEYLENGTH_MULTIPLE(key_mod)
   {
   }

/*************************************************
* Query if the keylength is valid                *
*************************************************/
bool SymmetricAlgorithm::valid_keylength(u32bit length) const
   {
   return ((length >= MINIMUM_KEYLENGTH) &&
           (length <= MAXIMUM_KEYLENGTH) &&
           (length % KEYLENGTH_MULTIPLE == 0));
   }

/*************************************************
* Set the key                                    *
*************************************************/
void SymmetricAlgorithm::set_key(const SymmetricKey& algo_key)
   throw(Invalid_Key_Length)
   {
   set_key(algo_key, algo_key.length());
   }

/*************************************************
* Set the key                                    *
*************************************************/
void SymmetricAlgorithm::set_key(const byte algo_key[], u32bit length)
   throw(Invalid_Key_Length)
   {
   if(!valid_keylength(length))
      throw Invalid_Key_Length(name(), length);
   key(algo_key, length);
   }

/*************************************************
* BlockCipher Constructor                        *
*************************************************/
BlockCipher::BlockCipher(u32bit block, u32bit key_min, u32bit key_max,
                         u32bit key_mod) :
   SymmetricAlgorithm(key_min, key_max, key_mod),
   BLOCK_SIZE(block)
   {
   }

/*************************************************
* StreamCipher Constructor                       *
*************************************************/
StreamCipher::StreamCipher(u32bit key_min, u32bit key_max, u32bit key_mod) :
   SymmetricAlgorithm(key_min, key_max, key_mod)
   {
   }

/*************************************************
* BufferedComputation Constructor                *
*************************************************/
BufferedComputation::BufferedComputation(u32bit olen) : OUTPUT_LENGTH(olen)
   {
   }

/*************************************************
* HashFunction Constructor                       *
*************************************************/
HashFunction::HashFunction(u32bit hlen, u32bit blen) :
   BufferedComputation(hlen), HASH_BLOCK_SIZE(blen)
   {
   }

/*************************************************
* MessageAuthenticationCode Constructor          *
*************************************************/
MessageAuthenticationCode::MessageAuthenticationCode(u32bit mlen,
                                                     u32bit key_min,
                                                     u32bit key_max,
                                                     u32bit key_mod) :
   BufferedComputation(mlen),
   SymmetricAlgorithm(key_min, key_max, key_mod)
   {
   }

/*************************************************
* Default MAC verification operation             *
*************************************************/
bool MessageAuthenticationCode::verify_mac(const byte mac[], u32bit length)
   {
   SecureVector<byte> our_mac = final();
   if(our_mac.size() != length)
      return false;
   for(u32bit j = 0; j != length; j++)
      if(mac[j] != our_mac[j])
         return false;
   return true;
   }

/*************************************************
* Default StreamCipher Resync Operation          *
*************************************************/
void StreamCipher::resync(const byte[], u32bit)
   {
   throw Exception("The stream cipher " + name() +
                   " does not support resyncronization");
   }

/*************************************************
* Default StreamCipher Seek Operation            *
*************************************************/
void StreamCipher::seek(u32bit)
   {
   throw Exception("The cipher " + name() + " does not support seek()");
   }

/*************************************************
* Hashing/MACing                                 *
*************************************************/
void BufferedComputation::update(const byte in[], u32bit n)
   {
   add_data(in, n);
   }

void BufferedComputation::update(const std::string& str)
   {
   update((const byte*)str.c_str(), str.size());
   }

void BufferedComputation::update(byte in)
   {
   update(&in, 1);
   }

SecureVector<byte> BufferedComputation::final()
   {
   SecureVector<byte> output(OUTPUT_LENGTH);
   final_result(output);
   return output;
   }

SecureVector<byte> BufferedComputation::process(const byte in[], u32bit len)
   {
   update(in, len);
   return final();
   }

SecureVector<byte> BufferedComputation::process(const std::string& in)
   {
   update(in);
   return final();
   }

/*************************************************
* Default fast poll for EntropySources           *
*************************************************/
u32bit EntropySource::fast_poll(byte buf[], u32bit len)
   {
   return slow_poll(buf, len);
   }

/*************************************************
* Add entropy to internal state                  *
*************************************************/
void RandomNumberGenerator::add_entropy(const byte random[], u32bit length)
   {
   add_randomness(random, length);
   }

/*************************************************
* Add entropy to internal state                  *
*************************************************/
void RandomNumberGenerator::add_entropy(EntropySource& source, bool slowpoll)
   {
   SecureVector<byte> entropy(slowpoll ? 192 : 64);
   u32bit returned;
   if(slowpoll) returned = source.slow_poll(entropy, entropy.size());
   else         returned = source.fast_poll(entropy, entropy.size());
   add_entropy(entropy, returned);
   }

/*************************************************
* Return the version as a string                 *
*************************************************/
std::string version_string()
   {
   return "Botan " + to_string(version_major()) + "." +
                     to_string(version_minor()) + "." +
                     to_string(version_patch());
   }

/*************************************************
* Return parts of the version as integers        *
*************************************************/
u32bit version_major() { return BOTAN_VERSION_MAJOR; }
u32bit version_minor() { return BOTAN_VERSION_MINOR; }
u32bit version_patch() { return BOTAN_VERSION_PATCH; }

}
