// Common, group Crypto
// Copyright Alexander Liss

	// supported types are in "cryptotype.h"

#ifndef __CRYPTOLAYER_H__
#define __CRYPTOLAYER_H__

#include "commbuf.h"

class SecretsStorage;
class CryptoLayer;


	// CryptoHash

class CryptoHashImp;

class CryptoHash
{
friend class CryptoLayer;
CryptoHash():imp(0){}
CryptoHash(const CryptoHash&);				
CryptoHash& operator=(const CryptoHash&);
public:
~CryptoHash();

// chain
int next(const CommBuffer& data, ReadControl&)const;
int get(CommBuffer& hash)const;

	// uses chain internally
int hash(CommBuffer& hash,const CommBuffer& s, ReadControl&)const;
private:
	CryptoHashImp* imp;
};


	// CryptoSymmetric
	// if blocked cbc - set iv for a channel in the beginning
	// encryption and decryption can work in parallel

class CryptoSymmetricImp;

class CryptoSymmetric
{
friend class CryptoLayer;
CryptoSymmetric():imp(0){}
CryptoSymmetric(const CryptoSymmetric&);				
CryptoSymmetric& operator=(const CryptoSymmetric&);
public:

~CryptoSymmetric();

// bytes
int block_size()const;

// one block
int encrypt_block(CommBuffer& d,const CommBuffer& s, ReadControl&)const;
int decrypt_block(CommBuffer& d,const CommBuffer& s, ReadControl&)const;

// encryption chain
int start_encrypt(const CommBuffer& iv,ReadControl&)const;
int next_encrypt(CommBuffer& d,const CommBuffer& s, ReadControl&,bool last=true)const;

// decryption chain
int start_decrypt(CommBuffer& iv,const CommBuffer& s, ReadControl&)const;
int next_decrypt(CommBuffer& d,const CommBuffer& s, ReadControl&,bool last=true)const;

private:
	CryptoSymmetricImp* imp;
};

	// CryptoPKS

class CryptoPKSImp;

class CryptoPKS
{
friend class CryptoLayer;
CryptoPKS():imp(0),storage(0){}
CryptoPKS(const CryptoPKS&);				
CryptoPKS& operator=(const CryptoPKS&);
public:

~CryptoPKS();

int encrypt_block_bits()const;
int decrypt_block_bits()const;

// public key operations, use a counterparty key
int encrypt_public(CommBuffer& d,const CommBuffer& s,ReadControl& c)const;
int decrypt_public(CommBuffer& d,const CommBuffer& s,ReadControl& c)const;

// private key operations, own pub_key is used as an index
int encrypt_private(CommBuffer& d,const CommBuffer& s,ReadControl& c)const;
int decrypt_private(CommBuffer& d,const CommBuffer& s,ReadControl& c)const;

private:
	CryptoPKSImp* imp;
	SecretsStorage* storage;
	CommBuffer pub_key;
};

	// CryptoSign
	// usually it is applied to a hash of data

class CryptoSignImp;

class CryptoSign
{
friend class CryptoLayer;
CryptoSign():imp(0),storage(0){}
CryptoSign(const CryptoSign&);				
CryptoSign& operator=(const CryptoSign&);
public:

~CryptoSign();

// "open" is without a signature
int sign(CommBuffer& closed,const CommBuffer& open,ReadControl& c)const;
int verify(CommBuffer& open,const CommBuffer& closed,ReadControl& c)const;

private:
	CryptoSignImp* imp;
	SecretsStorage* storage;
	CommBuffer pub_key;
};

	// CryptoLayerConfig

struct CryptoLayerConfig
{
	int hash,symmetric,pks,
		storage,random,
		symmetric_key,pks_key,mac_key;
};
 

	// CryptoLayer

class CryptoRandom;

class CryptoLayer
{
public:

CryptoLayer(const CryptoLayerConfig& config);
~CryptoLayer();

int seed(const CommBuffer& s,ReadControl& c);

// generate a key and store in the "internal database"
int generate_symmetric_key(unsigned int& secrets_handle,const CommBuffer& param, ReadControl& c,int key_type)const;
int generate_pks_key(CommBuffer& pub_key,const CommBuffer& param, ReadControl& c,int key_type)const;
int generate_mac_key(unsigned int& secrets_handle,const CommBuffer& param, ReadControl& c,int key_type)const;
// "external" database
int put_secret(unsigned int& secrets_handle,const CommBuffer& s,ReadControl& c, int type)const;
int get_secret(int& type, CommBuffer& d,unsigned int secrets_handle)const;
// data removal
int drop_secret(unsigned int secrets_handle)const;
int drop_secret(const CommBuffer& pub_key,ReadControl& c)const;

// random bits generator
int append_random(CommBuffer& data,int bytes)const;

CryptoHash* newCryptoHash(int type)const;
CryptoHash* newCryptoHash(int type,const CommBuffer& key,ReadControl& c)const;
CryptoHash* newCryptoHash(int& type,unsigned int key_handle)const;
CryptoSymmetric* newCryptoSymmetric(int type,const CommBuffer& key,ReadControl& c)const;
CryptoSymmetric* newCryptoSymmetric(int& type,unsigned int key_handle)const;
// for public key operations use a counterparty key
// for private key operations use own pub_key as an index
CryptoPKS* newCryptoPKS(int& type,const CommBuffer& pub_key,ReadControl& c)const;
// for verification use a counterparty key
// for signing use own pub_key as an index
CryptoSign* newCryptoSign(int& type,const CommBuffer& pub_key,ReadControl& c)const;

private:

	SecretsStorage *storage;
	CryptoRandom* crypto_random;
	CryptoLayerConfig config;

int initialize();
};

#endif