text: /*
  * Cipher Modes
  * (C) 2013,2016 Jack Lloyd
  *
  * Botan is released under the Simplified BSD License (see license.txt)
  */
  
  #ifndef BOTAN_CIPHER_MODE_H__
  #define BOTAN_CIPHER_MODE_H__
  
  #include <botan/secmem.h>
  #include <botan/key_spec.h>
  #include <botan/exceptn.h>
  #include <botan/symkey.h>
  #include <string>
  #include <vector>
  
  namespace Botan {
  
  /**
  * Interface for cipher modes
  */
  class BOTAN_DLL Cipher_Mode
     {
     public:
        virtual ~Cipher_Mode() {}
  
        /*
        * Prepare for processing a message under the specified nonce
        */
        virtual void start_msg(const uint8_t nonce[], size_t nonce_len) = 0;
  
        /**
        * Begin processing a message.
        * @param nonce the per message nonce
        */
        template<typename Alloc>
        void start(const std::vector<uint8_t, Alloc>& nonce)
           {
           start_msg(nonce.data(), nonce.size());
           }
  
        /**
        * Begin processing a message.
        * @param nonce the per message nonce
        * @param nonce_len length of nonce
        */
        void start(const uint8_t nonce[], size_t nonce_len)
           {
           start_msg(nonce, nonce_len);
           }
  
        /**
        * Begin processing a message.
        */
        void start()
           {
           return start_msg(nullptr, 0);
           }
  
        /**
        * Process message blocks
        *
        * Input must be a multiple of update_granularity
        *
        * Processes msg in place and returns bytes written. Normally
        * this will be either msg_len (indicating the entire message was
        * processed) or for certain AEAD modes zero (indicating that the
        * mode requires the entire message be processed in one pass).
        *
        * @param msg the message to be processed
        * @param msg_len length of the message in bytes
        */
        virtual size_t process(uint8_t msg[], size_t msg_len) = 0;
  
        /**
        * Process some data. Input must be in size update_granularity() uint8_t blocks.
        * @param buffer in/out parameter which will possibly be resized
        * @param offset an offset into blocks to begin processing
        */
        void update(secure_vector<uint8_t>& buffer, size_t offset = 0)
           {
           BOTAN_ASSERT(buffer.size() >= offset, "Offset ok");
           uint8_t* buf = buffer.data() + offset;
           const size_t buf_size = buffer.size() - offset;
  
           const size_t written = process(buf, buf_size);
           buffer.resize(offset + written);
           }
  
        /**
        * Complete processing of a message.
        *
        * @param final_block in/out parameter which must be at least
        *        minimum_final_size() bytes, and will be set to any final output
        * @param offset an offset into final_block to begin processing
        */
        virtual void finish(secure_vector<uint8_t>& final_block, size_t offset = 0) = 0;
  
        /**
        * Returns the size of the output if this transform is used to process a
        * message with input_length bytes. Will throw if unable to give a precise
        * answer.
        */
        virtual size_t output_length(size_t input_length) const = 0;
  
        /**
        * @return size of required blocks to update
        */
        virtual size_t update_granularity() const = 0;
  
        /**
        * @return required minimium size to finalize() - may be any
        *         length larger than this.
        */
        virtual size_t minimum_final_size() const = 0;
  
        /**
        * @return the default size for a nonce
        */
        virtual size_t default_nonce_length() const = 0;
  
        /**
        * @return true iff nonce_len is a valid length for the nonce
        */
        virtual bool valid_nonce_length(size_t nonce_len) const = 0;
  
        virtual std::string name() const = 0;
  
        /**
        * Zeroise all state
        * See also reset_msg()
        */
        virtual void clear() = 0;
  
        /**
        * Resets just the message specific state and allows encrypting again under the existing key
        */
        virtual void reset() = 0;
  
        /**
        * @return true iff this mode provides authentication as well as
        * confidentiality.
        */
        virtual bool authenticated() const { return false; }
  
        /**
        * @return the size of the authentication tag used (in bytes)
        */
        virtual size_t tag_size() const { return 0; }
  
        /**
        * @return object describing limits on key size
        */
        virtual Key_Length_Specification key_spec() const = 0;
  
        /**
        * Check whether a given key length is valid for this algorithm.
        * @param length the key length to be checked.
        * @return true if the key length is valid.
        */
        bool valid_keylength(size_t length) const
           {
           return key_spec().valid_keylength(length);
           }
  
        /**
        * Set the symmetric key of this transform
        * @param key contains the key material
        */
        template<typename Alloc>
        void set_key(const std::vector<uint8_t, Alloc>& key)
           {
           set_key(key.data(), key.size());
           }
  
        /**
        * Set the symmetric key of this transform
        * @param key contains the key material
        */
        void set_key(const SymmetricKey& key)
           {
           set_key(key.begin(), key.length());
           }
  
        /**
        * Set the symmetric key of this transform
        * @param key contains the key material
        * @param length in bytes of key param
        */
        void set_key(const uint8_t key[], size_t length)
           {
           if(!valid_keylength(length))
              throw Invalid_Key_Length(name(), length);
           key_schedule(key, length);
           }
  
        /**
        * @return provider information about this implementation. Default is "base",
        * might also return "sse2", "avx2", "openssl", or some other arbitrary string.
        */
        virtual std::string provider() const { return "base"; }
  
     private:
        virtual void key_schedule(const uint8_t key[], size_t length) = 0;
     };
  
  /**
  * The two possible directions for cipher filters, determining whether they
  * actually perform encryption or decryption.
  */
  enum Cipher_Dir { ENCRYPTION, DECRYPTION };
  
  /**
  * Get a cipher mode by name (eg "AES-128/CBC" or "Serpent/XTS")
  * @param algo_spec cipher name
  * @param direction ENCRYPTION or DECRYPTION
  */
  BOTAN_DLL Cipher_Mode* get_cipher_mode(const std::string& algo_spec, Cipher_Dir direction);
  
  }
  
  #endif
  