/* * This file is a part of Tito - a cryptography library * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * 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 #include #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 & 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 & content, const AES::uint8 * iv); bool DecodeCBC_PKCS7(std::vector & 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 & out); bool Encode(const std::vector & block, const std::string & name, std::vector & out); bool Decode(const uint8 * block, size_t len, std::string & name, std::vector & out); bool Decode(const std::vector & block, std::string & name, std::vector & 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 & out); void PutChecksumAfter(std::vector & out); uint32 Checksum(const uint8 * block, size_t len); void EncodePad(int & y, int & x, uint16 pad, std::vector & out); void EncodeName(int & y, int & x, const std::string & name, std::vector & out); void EncodeData(int & y, int & x, const uint8 * block, size_t len, std::vector & 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 & out); bool CheckSignatureAndChecksumAfter(const TiHeader & header, const uint8 * block, size_t len); bool CheckChecksumBefore(const TiHeader & header, std::vector & out); }; } // namespace Tito #endif