#ifndef CRYPTOGRAPHY_H__
#define CRYPTOGRAPHY_H__

#include "maxon/cryptography_key.h"
#include "maxon/streamconversion.h"


namespace maxon
{

/// @addtogroup Cryptography
/// @{

/// Block cipher modes. See documentation of the encryption method for details.
enum class BLOCK_CIPHER_MODE : UInt64
{
	ECB									= 0, ///< Electronic codebook.
	CBC									= 1, ///< Cipher-block chaining.
	PCBC								= 2, ///< Propagating cipher-block chaining.
	CFB									= 3, ///< Cipher feedback.
	OFB									= 4, ///< Output feedback.
	CTR									= 5, ///< Counter.
	KEEP_STATE					= 0x80000000, ///< for CBC, PCBC, CFB, OFB: Store the current state in the instance. Otherwise the next Encrypt call will use the original initialization vector.
} MAXON_ENUM_FLAGS(BLOCK_CIPHER_MODE);

//----------------------------------------------------------------------------------------
/// CryptographyStreamConversionInterface class for encrypting and decrypting.
/// To allocate an instance of a CryptographyStreamConversionRef call StreamConversions::<<encoder/decoder>>.Create(cryptoSettings).
/// Encoder and decoder can be of AesEncoder, AesDecoder, BlowfishEncoder, BlowfishDecoder etc.
/// Currently supported cryptography methods are:
///
/// AES
///		Use StreamConversions::AesEncoder.Create(cryptoSettings) as name to allocate a new instance.
///		Block size and key size must be 128, 192 or 256 bit.
///		The encryption and decryption are hardware accelerated if the hardware has AES instructions.
///		key1 is the key that is used for encryption and decryption. The following modes are supported:
///		ECB: keySize2 must be 0, key2 must be nullptr, otherwise Init will return IllegalArgumentError.
///		CBC, PCBC, CFB, OFB: keySize2 must be blockSize, key2 must not be nullptr, otherwise Init will return IllegalArgumentError. This is the initialization vector for the chiffre.
///		CTR: keySize2 must be 0, key2 must be nullptr, callback must be the address of an BLOCK_CIPHER_CTR_CALLBACK function, otherwise Init will return IllegalArgumentError.
///		userData of the Encrypt and Decrypt functions are not used except for CTR mode.
///
/// Blowfish
///		Use StreamConversions::BlowfishEncoder.Create(cryptoSettings) to allocate a class instance. Blowfish is a keyed, symmetric block cipher. @see https://en.wikipedia.org/wiki/Blowfish_(cipher)
///		The Block size must be 64 or 2048 bit. Valid key lengths are 32 to 448 bit (must be divisible by 8).
///		The Init() flag bit 1 enables the streaming mode which causes that identical blocks are encrypted different and so it's harder to find patterns.
///
///		Use BlowfishLegacyEncoder/BlowfishLegacyDecoder as the name to allocate the class which is compatible to CINEMA 4D R5 - R14 blowfish.
///		The Block size must be 64 or 2048 bit. Valid key lengths are 32 to 448 bit (must be divisible by 8).
///		The Init() flag bit 1 enables the streaming mode which causes that identical blocks are encrypted different and so it's harder to find patterns.
///		In this mode it's possible to call Encrypt() even if the datasize is not % blocksize. If the blocksize is 2048 bit the rest is encoded with 64 bit.
///		the rest is unencrypted! It's exactly the behavior that cinema 4d had. It's not recommended to use that for new code anymore!
//----------------------------------------------------------------------------------------
class CryptographyStreamConversionInterface : MAXON_INTERFACE_BASES(StreamConversionInterface)
{
	MAXON_INTERFACE(CryptographyStreamConversionInterface, MAXON_REFERENCE_NORMAL, "net.maxon.interface.cryptographystreamconversion");

public:
	//----------------------------------------------------------------------------------------
	/// Checks if the algorithm is a chaining chiffre (i.e. a value that was calculated in the current block is used in the next block).
	/// For example, CBC is a chaining chiffre, whereas ECB is not a chaining chiffre.
	/// @return												True, if it is a chaining chiffre.
	//----------------------------------------------------------------------------------------
	MAXON_METHOD Bool IsChainingChiffre() const;
};


// include autogenerated headerfile here
#include "cryptography1.hxx"

namespace StreamConversions
{
	///
	MAXON_DECLARATION(StreamConversionFactory, AesEncoder, "net.maxon.streamconversion.aes.encoder");
	MAXON_DECLARATION(StreamConversionFactory, AesDecoder, "net.maxon.streamconversion.aes.decoder");

	///
	MAXON_DECLARATION(StreamConversionFactory, BlowfishEncoder, "net.maxon.streamconversion.blowfish.encoder");
	MAXON_DECLARATION(StreamConversionFactory, BlowfishDecoder, "net.maxon.streamconversion.blowfish.decoder");

	/// old c4d encryption
	MAXON_DECLARATION(StreamConversionFactory, BlowfishLegacyEncoder, "net.maxon.streamconversion.blowfishlegacy.encoder");
	MAXON_DECLARATION(StreamConversionFactory, BlowfishLegacyDecoder, "net.maxon.streamconversion.blowfishlegacy.decoder");
	/// old c4d encryption/decrytion within one class, use encoder.Set(BLOWFISHLEGACYENDECODER_OPTIONS::ENCRYPT, true/false)
	MAXON_DECLARATION(StreamConversionFactory, BlowfishLegacyEnDecoder, "net.maxon.streamconversion.blowfishlegacyen.decoder");
}

namespace BLOWFISHLEGACYENDECODER_OPTIONS
{
	/// Set to true to encrypt, otherwise decrypt
	MAXON_ATTRIBUTE(Bool, ENCRYPT, "net.maxon.streamconversion.blowfishlegacy.encrypt");
}


// include autogenerated headerfile here
#include "cryptography2.hxx"


/// @}

} // namespace maxon



#endif // CRYPTOGRAPHY_H__
