//     ____   ______ __
//    / __ \ / ____// /
//   / /_/ // /    / /
//  / ____// /___ / /___   PixInsight Class Library
// /_/     \____//_____/   PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/Cryptography.h - Released 2022-03-12T18:59:29Z
// ----------------------------------------------------------------------------
// This file is part of the PixInsight Class Library (PCL).
// PCL is a multiplatform C++ framework for development of PixInsight modules.
//
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
//    of their contributors, may be used to endorse or promote products derived
//    from this software without specific prior written permission. For written
//    permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
//    reproduce the following acknowledgment in the end-user documentation
//    and/or other materials provided with the product:
//
//    "This product is based on software from the PixInsight project, developed
//    by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
//
//    Alternatively, if that is where third-party acknowledgments normally
//    appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------

#ifndef __PCL_Cryptography_h
#define __PCL_Cryptography_h

/// \file pcl/Cryptography.h

#include <pcl/Defs.h>
#include <pcl/Diagnostics.h>

#include <pcl/AutoPointer.h>
#include <pcl/ByteArray.h>
#include <pcl/Exception.h>
#include <pcl/String.h>

namespace pcl
{

// ----------------------------------------------------------------------------

/*!
 * \defgroup cryptography_classes Cryptographic Hashing and Encryption Classes
 */

/*!
 * \class CryptographicHash
 * \brief Abstract base class for cryptographic hashing algorithm
 * implementations
 *
 * %CryptographicHash defines a common interface for implementations of
 * cryptographic hashing algorithms such as MD-5, SHA-1 or SHA-256.
 *
 * \ingroup cryptography_classes
 * \sa MD5, SHA1, SHA224, SHA256, SHA384, SHA512, CryptographicHashFactory
 */
class PCL_CLASS CryptographicHash
{
public:

   /*!
    * Default constructor.
    */
   CryptographicHash() = default;

   /*!
    * Destroys a %CryptographicHash object.
    */
   virtual ~CryptographicHash()
   {
   }

   /*!
    * Copy constructor. This constructor is disabled because %CryptographicHash
    * objects are unique.
    */
   CryptographicHash( const CryptographicHash& ) = delete;

   /*!
    * Copy assignment. This operator is disabled because %CryptographicHash
    * objects are unique.
    */
   CryptographicHash& operator =( const CryptographicHash& ) = delete;

   /*!
    * Returns the name of this cryptographic hashing algorithm.
    */
   virtual String AlgorithmName() const = 0;

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    */
   virtual size_type HashLength() const = 0;

   /*!
    * Initializes this cryptographic hash generator.
    */
   virtual void Initialize() = 0;

   /*!
    * Updates the hash generator with a new \a data chunk of the specified
    * \a length in bytes.
    */
   virtual void Update( const void* data, size_type length ) = 0;

   /*!
    * Updates the hash generator with data from a container with contiguous
    * storage.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    */
   template <class C>
   void Update( const C& data )
   {
      Update( data.Begin(), data.Size() );
   }

   /*!
    * Terminates hash generation and returns the computed message digest
    * as a ByteArray instance.
    */
   ByteArray Finalize()
   {
      ByteArray hash( HashLength() );
      Finalize( hash.Begin() );
      return hash;
   }

   /*!
    * Returns the hash sequence (message digest) corresponding to a \a data
    * block of the specified \a length in bytes, stored in the specified
    * \a hash array. The specified array must provide room for at least
    * HashLength() bytes, that is, the length in bytes of the message digest
    * produced by this hashing algorithm.
    */
   void Hash( uint8* hash, const void* data, size_type length )
   {
      Initialize();
      Update( data, length );
      Finalize( hash );
   }

   /*!
    * Returns the hash sequence (message digest) corresponding to a \a data
    * block of the specified \a length in bytes, as a ByteArray instance.
    */
   ByteArray Hash( const void* data, size_type length )
   {
      ByteArray hash( HashLength() );
      Hash( hash.Begin(), data, length );
      return hash;
   }

   /*!
    * Returns the hash sequence (message digest) corresponding to a container
    * \a data with contiguous storage as a ByteArray instance.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    */
   template <class C>
   ByteArray Hash( const C& data )
   {
      return Hash( data.Begin(), data.Size() );
   }

protected:

   /*!
    * Terminates hash generation and returns the computed message digest
    * (hash value) stored in the specified \a hash array. The specified array
    * must provide room for at least HashLength() bytes, that is, the length in
    * bytes of the message digest produced by this hashing algorithm.
    */
   virtual void Finalize( void* hash ) = 0;

   friend class CryptographicHashFactory;
};

// ----------------------------------------------------------------------------

/*!
 * \class MD5
 * \brief Implementation of the %MD5 cryptographic hashing algorithm
 *
 * \b References
 *
 * Message Digest algorithm 5 (%MD5) was designed by Ronald Rivest in 1991.
 * %MD5 is a widely-used Internet standard published as RFC-1321 by RSA:
 *
 * http://tools.ietf.org/html/rfc1321
 *
 * An %MD5 message digest (or %MD5 hash value) is 128 bits (16 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, SHA1, SHA224, SHA256, SHA384, SHA512,
 *     CryptographicHashFactory
 */
class PCL_CLASS MD5 : public CryptographicHash
{
public:

   /*!
    * Constructs an %MD5 hash generator.
    */
   MD5() = default;

   /*!
    * Destroys an %MD5 hash generator.
    */
   virtual ~MD5();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "MD5".
    */
   String AlgorithmName() const override
   {
      return "MD5";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %MD5, this function returns 16, the length in bytes
    * of an %MD5 digest.
    */
   size_type HashLength() const override
   {
      return 16;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr;

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class SHA1
 * \brief Implementation of the SHA-1 cryptographic hashing algorithm
 *
 * \b References
 *
 * The initial Secure Hash Algorithm (SHA) was published by NIST in 1993 as the
 * Secure Hash Standard, FIPS PUB 180. The SHA-1 algorithm was defined in a
 * revised version published in 1995, FIPS PUB 180-1. The latest specification
 * has been released in FIPS PUB 180-4:
 *
 * http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
 *
 * An SHA-1 message digest (or SHA-1 hash value) is 160 bits (20 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA224, SHA256, SHA384, SHA512,
 *     CryptographicHashFactory
 */
class PCL_CLASS SHA1 : public CryptographicHash
{
public:

   /*!
    * Constructs an SHA-1 hash generator.
    */
   SHA1() = default;

   /*!
    * Destroys an SHA-1 hash generator.
    */
   virtual ~SHA1();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "SHA1".
    */
   String AlgorithmName() const override
   {
      return "SHA1";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %SHA1, this function returns 20, the length in bytes
    * of an SHA-1 digest.
    */
   size_type HashLength() const override
   {
      return 20;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr; // RFC4634

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class SHA224
 * \brief Implementation of the SHA-224 cryptographic hashing algorithm
 *
 * \b References
 *
 * The SHA-2 family of secure hash functions (SHA-256, SHA-384, and SHA-512)
 * was specified by NIST in 2002 with the publication of FIPS PUB 180-2. The
 * SHA-224 variant was released in a change notice for FIPS PUB 180-2 in 2004.
 * FIPS PUB 180-2 has been superseded by FIPS PUB 180-3 and FIPS PUB 180-4:
 *
 * http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
 *
 * An SHA-224 message digest is 224 bits (28 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA1, SHA256, SHA384, SHA512,
 *     CryptographicHashFactory
 */
class PCL_CLASS SHA224 : public CryptographicHash
{
public:

   /*!
    * Constructs an SHA-224 hash generator.
    */
   SHA224() = default;

   /*!
    * Destroys an SHA-224 hash generator.
    */
   virtual ~SHA224();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "SHA224".
    */
   String AlgorithmName() const override
   {
      return "SHA224";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %SHA224, this function returns 28, the length in
    * bytes of an SHA-224 digest.
    */
   size_type HashLength() const override
   {
      return 28;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr; // RFC4634

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class SHA256
 * \brief Implementation of the SHA-256 cryptographic hashing algorithm
 *
 * \b References
 *
 * The SHA-2 family of secure hash functions (SHA-256, SHA-384, and SHA-512)
 * was specified by NIST in 2002 with the publication of FIPS PUB 180-2. FIPS
 * PUB 180-2 has been superseded by FIPS PUB 180-3 and FIPS PUB 180-4:
 *
 * http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
 *
 * An SHA-256 message digest is 256 bits (32 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA1, SHA224, SHA384, SHA512,
 *     CryptographicHashFactory
 */
class PCL_CLASS SHA256 : public CryptographicHash
{
public:

   /*!
    * Constructs an SHA-256 hash generator.
    */
   SHA256() = default;

   /*!
    * Destroys an SHA-256 hash generator.
    */
   virtual ~SHA256();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "SHA256".
    */
   String AlgorithmName() const override
   {
      return "SHA256";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %SHA256, this function returns 32, the length in
    * bytes of an SHA-256 digest.
    */
   size_type HashLength() const override
   {
      return 32;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr; // RFC4634

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class SHA384
 * \brief Implementation of the SHA-384 cryptographic hashing algorithm
 *
 * \b References
 *
 * The SHA-2 family of secure hash functions (SHA-384, SHA-384, and SHA-512)
 * was specified by NIST in 2002 with the publication of FIPS PUB 180-2. FIPS
 * PUB 180-2 has been superseded by FIPS PUB 180-3 and FIPS PUB 180-4:
 *
 * http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
 *
 * An SHA-384 message digest is 384 bits (48 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA1, SHA224, SHA256, SHA512,
 *     CryptographicHashFactory
 */
class PCL_CLASS SHA384 : public CryptographicHash
{
public:

   /*!
    * Constructs an SHA-384 hash generator.
    */
   SHA384() = default;

   /*!
    * Destroys an SHA-384 hash generator.
    */
   virtual ~SHA384();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "SHA384".
    */
   String AlgorithmName() const override
   {
      return "SHA384";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %SHA384, this function returns 48, the length in
    * bytes of an SHA-384 digest.
    */
   size_type HashLength() const override
   {
      return 48;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr; // RFC4634

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class SHA512
 * \brief Implementation of the SHA-512 cryptographic hashing algorithm
 *
 * \b References
 *
 * The SHA-2 family of secure hash functions (SHA-384, SHA-384, and SHA-512)
 * was specified by NIST in 2002 with the publication of FIPS PUB 180-2. FIPS
 * PUB 180-2 has been superseded by FIPS PUB 180-3 and FIPS PUB 180-4:
 *
 * http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
 *
 * An SHA-512 message digest is 512 bits (64 bytes) long.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA1, SHA224, SHA256, SHA384,
 *     CryptographicHashFactory
 */
class PCL_CLASS SHA512 : public CryptographicHash
{
public:

   /*!
    * Constructs an SHA-512 hash generator.
    */
   SHA512() = default;

   /*!
    * Destroys an SHA-512 hash generator.
    */
   virtual ~SHA512();

   /*!
    * Returns the name of this cryptographic hashing algorithm: "SHA512".
    */
   String AlgorithmName() const override
   {
      return "SHA512";
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    *
    * As reimplemented in %SHA512, this function returns 64, the length in
    * bytes of an SHA-512 digest.
    */
   size_type HashLength() const override
   {
      return 64;
   }

   /*!
    */
   void Initialize() override;

   /*!
    */
   void Update( const void* data, size_type length ) override;

private:

   void* m_context = nullptr; // RFC4634

   /*!
    */
   void Finalize( void* hash ) override;
};

// ----------------------------------------------------------------------------

/*!
 * \class CryptographicHashFactory
 * \brief Selectable cryptographic hashing algorithm
 *
 * %CryptographicHashFactory implements a cryptographic hashing algorithm that
 * can be selected upon construction among all of the algorithms implemented in
 * the PixInsight/PCL platform. This currently includes MD-5, SHA-1, SHA-224,
 * SHA-256, SHA-384, and SHA-512.
 *
 * \ingroup cryptography_classes
 * \sa CryptographicHash, MD5, SHA1, SHA224, SHA256, SHA384, SHA512
 */
class PCL_CLASS CryptographicHashFactory : public CryptographicHash
{
public:

   /*!
    * Constructs a %CryptographicHashFactory object to implement the specified
    * hashing algorithm.
    *
    * \param algorithmName Name of a supported cryptographic hashing algorithm.
    *                      Currently this parameter can be one of: "md5",
    *                      "sha1", "sha224", "sha256", "sha384", and "sha512".
    *                      Comparisons are performed on trimmed strings and
    *                      case-insensitive.
    *
    * If an invalid or unsupported algorithm name is specified, this
    * constructor throws an Error exception.
    */
   CryptographicHashFactory( const IsoString& algorithmName )
   {
      switch ( algorithmName.Trimmed().CaseFolded().Hash32() )
      {
      case 0x445dd715: m_hash = new MD5; break;
      case 0x3cac24af: m_hash = new SHA1; break;
      case 0x7e50b015: m_hash = new SHA224; break;
      case 0xcbbce793: m_hash = new SHA256; break;
      case 0x858a0d3d: m_hash = new SHA384; break;
      case 0xb24dfd53: m_hash = new SHA512; break;
      default:
         throw Error( "CryptographicHashFactory: Unknown/unsupported algorithm \'" + algorithmName + '\'' );
      }
   }

   CryptographicHashFactory( const IsoString::ustring_base& algorithmName )
      : CryptographicHashFactory( IsoString( algorithmName ) )
   {
   }

   /*!
    * Destroys a %CryptographicHashFactory object.
    */
   virtual ~CryptographicHashFactory()
   {
   }

   /*!
    * Returns the name of this cryptographic hashing algorithm.
    */
   String AlgorithmName() const override
   {
      return m_hash->AlgorithmName();
   }

   /*!
    * Returns the length in bytes of a hash sequence (or message digest)
    * calculated with this cryptographic hashing algorithm.
    */
   size_type HashLength() const override
   {
      return m_hash->HashLength();
   }

   /*!
    * Initializes this cryptographic hash generator.
    */
   void Initialize() override
   {
      m_hash->Initialize();
   }

   /*!
    * Updates the hash generator with a new \a data chunk of the specified
    * \a length in bytes.
    */
   void Update( const void* data, size_type length ) override
   {
      m_hash->Update( data, length );
   }

private:

   AutoPointer<CryptographicHash> m_hash;

   void Finalize( void* hash ) override
   {
      m_hash->Finalize( hash );
   }
};

// ----------------------------------------------------------------------------

/*!
 * \class Cipher
 * \brief Abstract base class for cipher algorithm implementations
 *
 * %Cipher defines a common interface for implementations of algorithms
 * performing encryption and decryption of generic data.
 *
 * Currently we have implemented the AES-256 cipher with CBC/ECB encryption and
 * decryption on the PixInsight platform, available as the AES256 class.
 *
 * \ingroup cryptography_classes
 * \sa AES256
 */
class PCL_CLASS Cipher
{
public:

   /*!
    * Default constructor.
    */
   Cipher() = default;

   /*!
    * Copy constructor.
    */
   Cipher( const Cipher& ) = default;

   /*!
    * Copy assignment operator. Returns a reference to this object.
    */
   Cipher& operator =( const Cipher& ) = default;

   /*!
    * Destroys a %Cipher object.
    */
   virtual ~Cipher()
   {
   }

   /*!
    * Returns the name of this cipher algorithm.
    */
   virtual String AlgorithmName() const = 0;

   /*!
    * Returns the length in bytes of a key in this cipher algorithm.
    */
   virtual size_type KeyLength() const = 0;

   /*!
    * Buffer encryption.
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                encrypted data (or <em>cipher text</em>) will be stored.
    *
    * \param input   Starting address of the input buffer, where the original
    *                data (or <em>plain text</em>) is stored.
    *
    * \param length  The buffer length in bytes.
    */
   virtual void Encrypt( void* output, const void* input, size_type length ) const = 0;

   /*!
    * Buffer decryption.
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                decrypted data (or <em>plain text</em>) will be stored.
    *
    * \param input   Starting address of the input buffer, where the encrypted
    *                data (or <em>cipher text</em>) is stored.
    *
    * \param length  The buffer length in bytes.
    */
   virtual void Decrypt( void* output, const void* input, size_type length ) const = 0;

   /*!
    * Container encryption.
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                encrypted data (or <em>cipher text</em>) will be stored.
    *
    * \param input   Reference to a container where the original data (or
    *                <em>plain text</em>) is stored as a contiguous block. The
    *                input container will be treated as a contiguous sequence
    *                of bytes, ignoring the data type of the items contained.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    */
   template <class C>
   void Encrypt( void* output, const C& input ) const
   {
      Encrypt( output, input.Begin(), input.Size() );
   }

   /*!
    * Out-of-place container encryption.
    *
    * \param input   Reference to a container where the original data (or
    *                <em>plain text</em>) is stored as a contiguous block. The
    *                input container will be treated as a contiguous sequence
    *                of bytes, ignoring the data type of the items contained.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    *
    * Returns a ByteArray object with the encrypted data, or <em>cipher
    * text</em>. The returned object can be used to decrypt the data with the
    * Decrypt() member function.
    */
   template <class C>
   ByteArray Encrypt( const C& input ) const
   {
      ByteArray output( input.Size() );
      Encrypt( output.Begin(), input.Begin(), input.Size() );
      return output;
   }

   /*!
    * Container decryption.
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                decrypted data (or <em>plain text</em>) will be stored.
    *
    * \param input   Reference to a container where the encrypted data (or
    *                <em>cipher text</em>) is stored as a contiguous block. The
    *                input container will be treated as a contiguous sequence
    *                of bytes, ignoring the data type of the items contained.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    */
   template <class C>
   void Decrypt( void* output, const C& input ) const
   {
      Decrypt( output, input.Begin(), input.Size() );
   }

   /*!
    * Out-of-place container decryption.
    *
    * \param input   Reference to a container where the encrypted data (or
    *                <em>cipher text</em>) is stored as a contiguous block. The
    *                input container will be treated as a contiguous sequence
    *                of bytes, ignoring the data type of the items contained.
    *
    * The \c C template argument must be a class with PCL container semantics
    * (the Begin() and Size() member functions are required). Typically the
    * ByteArray class is used, although any array-like class with contiguous
    * storage is appropriate, including Array, String, Vector and Matrix.
    *
    * Returns a ByteArray object with the decrypted data, or <em>plain
    * text</em>), as a contiguous sequence of bytes.
    */
   template <class C>
   ByteArray Decrypt( const C& input ) const
   {
      ByteArray output( input.Size() );
      Decrypt( output.Begin(), input.Begin(), input.Size() );
      return output;
   }
};

// ----------------------------------------------------------------------------

/*!
 * \class AES256
 * \brief AES-256 cipher
 *
 * The %AES256 class is a FIPS-197 compliant implementation of the Advanced
 * Encryption Standard (AES) cipher using 256-bit keys.
 *
 * \b References
 *
 * The AES (Advanced Encryption Standard) block cipher algorithm (originally
 * called \e Rijndael) was designed by Vincent Rijmen and Joan Daemen:
 *
 * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
 * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
 *
 * \ingroup cryptography_classes
 */
class PCL_CLASS AES256 : public Cipher
{
public:

   enum { key_length = 32, block_length = 16 };

   /*!
    * Represents a 256-bit cipher key for the AES-256 algorithm.
    */
   typedef uint8  key_type[ key_length ];

   /*!
    * Represents a 16-byte ECB encryption/decription block for the AES-256
    * algorithm.
    */
   typedef uint8  block_type[ block_length ];

   /*!
    * Constructs an AES-256 cipher object.
    *
    * \param key     Starting address of a contiguous block of 32 bytes, which
    *                will be treated as the 256-bit cipher key. The first 32
    *                bytes stored at this address will be wiped out (replaced
    *                with zeros) by this constructor.
    *
    * \note For enhanced security, this constructor wipes out the specified
    * cipher \a key, filling it with 32 zero bytes. If you want to preserve the
    * key (which in general is a <em>bad idea</em> for security reasons), make
    * a safe copy before invoking this constructor.
    */
   AES256( void* key )
   {
      SetKey( key );
   }

   /*!
    * Constructs an AES-256 cipher object.
    *
    * \param key     256-bit cipher key specified as an 8-bit string. The
    *                contents of this string Will be wiped out (filled with
    *                null characters) by this constructor.
    *
    * The AES-256 cipher key will be initialized with the lowercase hexadecimal
    * representation of 20 successive MD5 checksum operations applied to the
    * specified \a key string (note that an %MD5 checksum is a sequence of 16
    * bytes, whose hexadecimal representation has 32 characters, or 256 bits).
    *
    * \note For enhanced security, this constructor wipes out the specified
    * cipher \a key string, filling it with null characters. If you want to
    * preserve the original key (which in general is a <em>bad idea</em> for
    * security reasons), make a copy and ensure it references its string data
    * uniquely before invoking this constructor.
    */
   AES256( IsoString& key )
   {
      ByteArray h = MD5().Hash( key );
      key.SecureFill();
      for ( int i = 1; i < 20; ++i )
         h = MD5().Hash( h );
      IsoString k = IsoString::ToHex( h );
      h.Fill( uint8( 0 ) );
      SetKey( k.Begin() );
   }

   /*!
    * Copy constructor.
    */
   AES256( const AES256& ) = default;

   /*!
    * Copy assignment operator. Returns a reference to this object.
    */
   AES256& operator =( const AES256& ) = default;

   /*!
    * Destroys an AES-256 cipher object.
    */
   virtual ~AES256()
   {
   }

   /*!
    * Returns "AES256", the name of this cipher algorithm.
    */
   String AlgorithmName() const override
   {
      return "AES256";
   }

   /*!
    * Returns 32, the length in bytes of a key in the AES-256 cipher algorithm.
    */
   size_type KeyLength() const override
   {
      return 32;
   }

   /*!
    * AES-256 buffer encryption (CBC mode).
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                encrypted data (or <em>cipher text</em>) will be stored.
    *
    * \param input   Starting address of the input buffer, where the original
    *                data (or <em>plain text</em>) is stored.
    *
    * \param length  The buffer length in bytes. Must be an integer multiple of
    *                16 bytes.
    *
    * If the specified \a length is not an integer multiple of 16 bytes, this
    * function throws an Error exception. If necessary, the source data must
    * be padded with zeros or spaces, as required to achieve a valid length.
    */
   void Encrypt( void* output, const void* input, size_type length ) const override;

   /*!
    * AES buffer decryption (CBC mode).
    *
    * \param[out] output  Starting address of the output buffer, where the
    *                decrypted data (or <em>plain text</em>) will be stored.
    *
    * \param input   Starting address of the input buffer, where the encrypted
    *                data (or <em>cipher text</em>) is stored.
    *
    * \param length  The buffer length in bytes. Must be an integer multiple of
    *                16 bytes.
    *
    * If the specified \a length is not an integer multiple of 16 bytes, this
    * function throws an Error exception.
    */
   void Decrypt( void* output, const void* input, size_type length ) const override;

   /*!
    * AES block encryption (ECB mode).
    *
    * \param[out] output   Starting address of the encrypted 16-byte block.
    *
    * \param input         Starting address of the input 16-byte block.
    */
   void EncryptBlock( void* output, const void* input ) const;

   /*!
    * AES block decryption (ECB mode).
    *
    * \param[out] output   Starting address of the decrypted 16-byte block.
    *
    * \param input         Starting address of the input 16-byte block.
    */
   void DecryptBlock( void* output, const void* input ) const;

private:

   uint32 m_erk[ 60 ]; // encryption round keys, 4*(Nr+1) elements
   uint32 m_drk[ 60 ]; // decryption round keys, 4*(Nr+1) elements

   /*!
    * \internal
    * Sets a new encryption/decryption key. Generates the round key tables and
    * wipes out 32 contiguous bytes starting at \a key.
    */
   void SetKey( void* key );
};

// ----------------------------------------------------------------------------

} // pcl

#endif   // __PCL_Cryptography_h

// ----------------------------------------------------------------------------
// EOF pcl/Cryptography.h - Released 2022-03-12T18:59:29Z
