tito/src/aes.h

265 lines
7.6 KiB
C++

/*
* This file is a part of Tito - a cryptography library
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2012-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) 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 headerfile_tito_aes
#define headerfile_tito_aes
#include <vector>
#include <string>
#include "log/log.h"
namespace Tito
{
class AES
{
public:
typedef unsigned char uint8;
typedef unsigned short int uint16;
typedef unsigned int uint32;
AES();
// 'state'
// 128 bits data block (16 bytes)
// this is input/output buffer for encoding/decoding
uint8 data[4][4];
// copying 16 bytes (128bits) buffer to/from 'data' table
void CopyToData(const uint8 * state);
void XorCopyToData(const AES::uint8 * state, const AES::uint8 * iv);
void CopyFromData(uint8 * state);
void XorCopyFromData(AES::uint8 * state, const AES::uint8 * iv);
void CopyFromData(std::vector<uint8> & out, bool clear = true);
// setting a new key
// key_length should be either: 16, 24 or 32
// if the key has incorrect length the method does nothing and returns false
bool Key(AES::uint8 * key_src, int key_length);
// encoding/decoding one 128 bits block
// you can set the value for encoding/decoding either by directly
// setting 'data' table or using CopyToData method
void EncodeData();
void DecodeData();
// encoding/decoding block of data - ECB (Electronic Codebook)
// the length should be multiplication of 16 (128bits)
// the method returns false if length is incorrect
bool Encode(uint8 * block, size_t len);
bool Decode(uint8 * block, size_t len);
// encoding/decoding block of data - CBC (Cipher Block Chaining)
// the length should be multiplication of 16 (128bits)
// the method returns false if length is incorrect
bool EncodeCBC(AES::uint8 * block, size_t len, const AES::uint8 * iv);
bool DecodeCBC(AES::uint8 * block, size_t len, const AES::uint8 * iv);
bool EncodeCBC_PKCS7(std::vector<uint8> & content, const AES::uint8 * iv);
bool DecodeCBC_PKCS7(std::vector<uint8> & content, const AES::uint8 * iv);
// encoding/decoding block of data
// there is not any restrictions to the length
// we are using our own header in which we remember the length
// some control sums, how many padding bytes were used
// Encode returns always true
// Decode returns false is the control sums are different from original in the header
bool Encode(const uint8 * block, size_t len, const std::string & name, std::vector<uint8> & out);
bool Encode(const std::vector<uint8> & block, const std::string & name, std::vector<uint8> & out);
bool Decode(const uint8 * block, size_t len, std::string & name, std::vector<uint8> & out);
bool Decode(const std::vector<uint8> & block, std::string & name, std::vector<uint8> & out);
// printing 'data' tab
// for debug purposes
void PrintData();
void PrintKey(AES::uint8 * key_src, int key_length);
void PrintKey(int xs);
void PrintKey2(int xs);
void PrintKey3(int xs);
bool CheckGFTables();
/*
* pikotools logger
* default: null (no logging)
*/
void set_logger(pt::Log * plog);
private:
// key (either 128 or 192 or 256 bits)
// and a space for key expansion
uint8 key[4][60];
// key length (in bytes)
// 16 for 128 bits
// 24 for 192 bits
// 32 for 256 bits
int key_len;
// key columns
// 4 for 128 bits key
// 6 for 192 bits key
// 8 for 256 bits key
int key_col;
// how many rounds should be performed
// 10 for 128 bits key
// 12 for 192 bits key
// 14 for 256 bits key
int round;
// sbox and inverse sbox tables (256 bytes each)
static uint8 sbox[16][16];
static uint8 invsbox[16][16];
// a table for mixcolumn state
static int mixcolumntab[4][4];
static uint8 Rcon[10];
static int invmixcolumntab[4][4];
static uint8 gf_mul9[16][16];
static uint8 gf_mul11[16][16];
static uint8 gf_mul13[16][16];
static uint8 gf_mul14[16][16];
pt::Log * plog;
// returning a coresponding value from sbox table
uint8 SubBytes(AES::uint8 v);
// making the SubBytes algorithm on all items in 'data' table
void SubBytes();
// performing shift rows by 1 item
void ShiftRows1(AES::uint8 tab[4]);
// performing shift rows by 2 items
void ShiftRows2(AES::uint8 tab[4]);
// performing shift rows by 3 item
void ShiftRows3(AES::uint8 tab[4]);
// performing shift rows on 'data' table
void ShiftRows();
uint8 MixColumns2(uint8 v);
uint8 MixColumns3(uint8 v);
uint8 MixColumns(int type, uint8 value);
void MixColumns();
void RotKey(int i);
void SubWordKey(int i);
void KeyExpansion();
void AddRoundKey(int xs);
/* inverse */
void InvShiftRows1(uint8 tab[4]);
void InvShiftRows2(uint8 tab[4]);
void InvShiftRows3(uint8 tab[4]);
void InvShiftRows();
uint8 InvSubBytes(uint8 v);
void InvSubBytes();
void InvMixColumns();
uint8 InvMixColumns(uint8 gf_mul[16][16], uint8 v);
uint8 InvMixColumns(int type, uint8 value);
/* for debug */
uint8 GaloisMultiply(uint8 a, uint8 b);
bool CheckGFTable(int value, uint8 gf_mul[16][16]);
struct TiHeader
{
AES::uint16 signature;
AES::uint16 pad1;
AES::uint16 pad2;
AES::uint32 checksum_before;
AES::uint32 checksum_after;
AES::uint32 name_len;
size_t all_len;
};
void IntToBuf(uint8 * buf, uint16 value);
void IntToBuf(uint8 * buf, uint32 value);
void CreateHeader(TiHeader & header, const uint8 * block, size_t len, const std::string & name, bool use_rand_first_padding = true);
void PutHeader(const TiHeader & header, std::vector<uint8> & out);
void PutChecksumAfter(std::vector<AES::uint8> & out);
uint32 Checksum(const uint8 * block, size_t len);
void EncodePad(int & y, int & x, uint16 pad, std::vector<uint8> & out);
void EncodeName(int & y, int & x, const std::string & name, std::vector<uint8> & out);
void EncodeData(int & y, int & x, const uint8 * block, size_t len, std::vector<uint8> & out);
void ReadHeader(TiHeader & header, const uint8 * block);
void DecodePad(int & y, int & x, const uint8 * & block, size_t & len, uint16 pad);
void DecodeName(int & y, int & x, const uint8 * & block, size_t & len, uint32 name_len, std::string & name);
void DecodeData(int & y, int & x, const uint8 * & block, size_t & len, size_t data_len, std::vector<uint8> & out);
bool CheckSignatureAndChecksumAfter(const TiHeader & header, const uint8 * block, size_t len);
bool CheckChecksumBefore(const TiHeader & header, std::vector<uint8> & out);
};
} // namespace Tito
#endif