tito/src/aes.cpp

1557 lines
31 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.
*
*/
#include <cstdio>
#include <cstdlib>
#include "aes.h"
namespace Tito
{
AES::uint8 AES::sbox[16][16] = {
{ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 },
{ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 },
{ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 },
{ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 },
{ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 },
{ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf },
{ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 },
{ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 },
{ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 },
{ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb },
{ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 },
{ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 },
{ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a },
{ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e },
{ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf },
{ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }};
AES::uint8 AES::invsbox[16][16] = {
{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb },
{ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb },
{ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e },
{ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 },
{ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 },
{ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 },
{ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 },
{ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b },
{ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 },
{ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e },
{ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b },
{ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 },
{ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f },
{ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef },
{ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 },
{ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }};
int AES::mixcolumntab[4][4] = {
{2, 3, 1, 1},
{1, 2, 3, 1},
{1, 1, 2, 3},
{3, 1, 1, 2}};
int AES::invmixcolumntab[4][4] = {
{14, 11, 13, 9},
{9, 14, 11, 13},
{13, 9, 14, 11},
{11, 13, 9, 14}};
AES::uint8 AES::Rcon[10] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
AES::uint8 AES::gf_mul9[16][16] = {
{ 0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77 },
{ 0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7 },
{ 0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c },
{ 0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc },
{ 0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01 },
{ 0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91 },
{ 0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a },
{ 0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa },
{ 0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b },
{ 0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b },
{ 0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0 },
{ 0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30 },
{ 0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed },
{ 0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d },
{ 0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6 },
{ 0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46 }};
AES::uint8 AES::gf_mul11[16][16] = {
{ 0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69 },
{ 0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9 },
{ 0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12 },
{ 0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2 },
{ 0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f },
{ 0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f },
{ 0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4 },
{ 0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54 },
{ 0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e },
{ 0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e },
{ 0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5 },
{ 0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55 },
{ 0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68 },
{ 0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8 },
{ 0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13 },
{ 0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3 }};
AES::uint8 AES::gf_mul13[16][16] = {
{ 0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b },
{ 0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b },
{ 0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0 },
{ 0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20 },
{ 0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26 },
{ 0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6 },
{ 0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d },
{ 0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d },
{ 0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91 },
{ 0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41 },
{ 0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a },
{ 0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa },
{ 0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc },
{ 0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c },
{ 0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47 },
{ 0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97 }};
AES::uint8 AES::gf_mul14[16][16] = {
{ 0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a },
{ 0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba },
{ 0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81 },
{ 0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61 },
{ 0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7 },
{ 0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17 },
{ 0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c },
{ 0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc },
{ 0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b },
{ 0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb },
{ 0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0 },
{ 0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20 },
{ 0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6 },
{ 0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56 },
{ 0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d },
{ 0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d }};
AES::AES()
{
plog = nullptr;
}
void AES::CopyToData(const AES::uint8 * state)
{
int x, y, index = 0;
for(x=0 ; x<4 ; ++x)
for(y=0 ; y<4 ; ++y)
data[y][x] = state[index++];
}
void AES::XorCopyToData(const AES::uint8 * state, const AES::uint8 * iv)
{
int x, y, index = 0;
for(x=0 ; x<4 ; ++x)
{
for(y=0 ; y<4 ; ++y)
{
data[y][x] = (state[index] ^ iv[index]);
index += 1;
}
}
}
void AES::CopyFromData(AES::uint8 * state)
{
int x, y, index = 0;
for(x=0 ; x<4 ; ++x)
for(y=0 ; y<4 ; ++y)
state[index++] = data[y][x];
}
void AES::XorCopyFromData(AES::uint8 * state, const AES::uint8 * iv)
{
int x, y, index = 0;
for(x=0 ; x<4 ; ++x)
{
for(y=0 ; y<4 ; ++y)
{
state[index] = (data[y][x] ^ iv[index]);
index += 1;
}
}
}
void AES::CopyFromData(std::vector<uint8> & out, bool clear)
{
int x, y;
if( clear )
out.clear();
if( out.size() + 16 > out.capacity() )
out.reserve(out.size() + 16);
for(x=0 ; x<4 ; ++x)
for(y=0 ; y<4 ; ++y)
out.push_back(data[y][x]);
}
void AES::PrintData()
{
int x, y;
char buf[20];
if( plog )
{
for(y=0 ; y<4 ; ++y)
{
for(x=0 ; x<4 ; ++x)
{
sprintf(buf, "%02x ", data[y][x]);
(*plog) << pt::Log::log4 << buf;
}
(*plog) << pt::Log::logend;
}
}
}
void AES::PrintKey(AES::uint8 * key_src, int key_length)
{
char buf[20];
if( plog )
{
(*plog) << pt::Log::log4 << "AES key, key_length: " << key_length << pt::Log::logend;
for(int i=0 ; i < key_length ; ++i)
{
sprintf(buf, "%02x", key_src[i]);
(*plog) << pt::Log::log4 << buf << " ";
}
(*plog) << pt::Log::logend;
}
}
void AES::PrintKey(int xs)
{
int x, y;
char buf[20];
if( plog )
{
for(y=0 ; y<4 ; ++y)
{
for(x=xs ; x<xs+key_col ; ++x)
{
sprintf(buf, "%02x ", key[y][x]);
(*plog) << pt::Log::log4 << buf << " ";
}
(*plog) << pt::Log::logend;
}
}
}
void AES::PrintKey2(int xs)
{
int x, y;
char buf[20];
if( plog )
{
(*plog) << pt::Log::log4 << "PrintKey2, xs=" << xs << pt::Log::logend;
for(x=xs ; x<xs+key_col ; ++x)
{
for(y=0 ; y<4 ; ++y)
{
sprintf(buf, "%02x", key[y][x]);
(*plog) << pt::Log::log4 << buf << " ";
}
(*plog) << pt::Log::logend;
}
}
}
void AES::PrintKey3(int x)
{
int y;
char buf[20];
if( plog )
{
(*plog) << pt::Log::log4 << "PrintKey3" << pt::Log::logend;
(*plog) << pt::Log::log4 << x << " ";
for(y=0 ; y<4 ; ++y)
{
sprintf(buf, "%02x", key[y][x]);
(*plog) << pt::Log::log4 << buf << " ";
}
(*plog) << pt::Log::logend;
}
}
AES::uint8 AES::SubBytes(AES::uint8 v)
{
int y = int(v) >> 4;
int x = (v & 0x0f);
return sbox[y][x];
}
void AES::SubBytes()
{
int x, y;
for(y=0 ; y<4 ; ++y)
for(x=0 ; x<4 ; ++x)
data[y][x] = SubBytes(data[y][x]);
}
void AES::ShiftRows1(AES::uint8 tab[4])
{
uint8 temp = tab[0];
tab[0] = tab[1];
tab[1] = tab[2];
tab[2] = tab[3];
tab[3] = temp;
}
void AES::ShiftRows2(AES::uint8 tab[4])
{
uint8 temp1 = tab[0];
uint8 temp2 = tab[1];
tab[0] = tab[2];
tab[1] = tab[3];
tab[2] = temp1;
tab[3] = temp2;
}
void AES::ShiftRows3(AES::uint8 tab[4])
{
uint8 temp = tab[3];
tab[3] = tab[2];
tab[2] = tab[1];
tab[1] = tab[0];
tab[0] = temp;
}
void AES::ShiftRows()
{
ShiftRows1(data[1]);
ShiftRows2(data[2]);
ShiftRows3(data[3]);
}
AES::uint8 AES::MixColumns2(AES::uint8 v)
{
bool high_bit = (v & 0x80) != 0;
v = v << 1;
if( high_bit )
v = v ^ 0x1b;
return v;
}
AES::uint8 AES::MixColumns3(AES::uint8 v)
{
bool high_bit = (v & 0x80) != 0;
AES::uint8 vold = v;
v = (v << 1) ^ vold;
if( high_bit )
v = v ^ 0x1b;
return v;
}
AES::uint8 AES::MixColumns(int type, AES::uint8 value)
{
switch(type)
{
case 2:
return MixColumns2(value);
case 3:
return MixColumns3(value);
case 1:
default:
return value;
}
}
void AES::MixColumns()
{
int x, y, i;
uint8 v;
uint8 temp[4];
for(x=0 ; x<4 ; ++x)
{
for(y=0 ; y<4 ; ++y)
{
v = 0;
for(i=0 ; i<4 ; ++i)
v ^= MixColumns(mixcolumntab[y][i], data[i][x]);
temp[y] = v;
}
for(y=0 ; y<4 ; ++y)
data[y][x] = temp[y];
}
}
bool AES::Key(AES::uint8 * key_src, int key_length)
{
int x, y, index = 0;
PrintKey(key_src, key_length);
key_len = key_length;
if( key_len == 16 )
{
key_col = 4;
round = 10;
}
else
if( key_len == 24 )
{
key_col = 6;
round = 12;
}
else
if( key_len == 32 )
{
key_col = 8;
round = 14;
}
else
{
if( plog )
{
(*plog) << pt::Log::log2 << "AES: I cannot initialize the AES key, incorrect key size: " << key_length
<< ", expected: 16, 24 or 32 " << pt::Log::logend;
}
return false;
}
for(x=0 ; x<key_col ; ++x)
for(y=0 ; y<4 ; ++y)
key[y][x] = key_src[index++];
KeyExpansion();
return true;
}
void AES::RotKey(int i)
{
uint8 temp = key[0][i];
key[0][i] = key[1][i];
key[1][i] = key[2][i];
key[2][i] = key[3][i];
key[3][i] = temp;
}
void AES::SubWordKey(int i)
{
for(int y=0 ; y<4 ; ++y)
key[y][i] = SubBytes(key[y][i]);
}
void AES::KeyExpansion()
{
int i, y;
int rcon_index = 0;
if( plog )
{
(*plog) << pt::Log::log4 << "AES key expansion" << pt::Log::logend;
}
for(i=key_col ; i < 4*(round+1) ; ++i)
{
for(y=0 ; y<4 ; ++y)
key[y][i] = key[y][i-1];
if( i % key_col == 0 )
{
RotKey(i);
SubWordKey(i);
key[0][i] ^= Rcon[rcon_index++];
}
else
if( key_col > 6 && i % key_col == 4 )
{
SubWordKey(i);
}
for(y=0 ; y<4 ; ++y)
key[y][i] ^= key[y][i-key_col];
if( plog )
{
PrintKey3(i);
if( i % key_col == 0 )
{
(*plog) << pt::Log::log4 << " ---- " << (rcon_index-1) << pt::Log::logend;
PrintKey2(i-key_col);
}
}
}
if( plog )
{
(*plog) << pt::Log::log4 << " ---- " << rcon_index << pt::Log::logend;
PrintKey2(i-key_col);
}
}
void AES::AddRoundKey(int xs)
{
int x, y;
for(y=0 ; y<4 ; ++y)
for(x=0 ; x<4 ; ++x)
data[y][x] ^= key[y][xs+x];
}
void AES::EncodeData()
{
int i;
if( plog )
{
(*plog) << pt::Log::log4 << " input data " << pt::Log::logend;
PrintData();
}
AddRoundKey(0);
if( plog )
{
(*plog) << pt::Log::log4 << " first round key " << pt::Log::logend;
PrintData();
}
for(i=0 ; i<round ; ++i)
{
SubBytes();
if( plog )
{
(*plog) << pt::Log::log4 << " after sub bytes, i= " << i+1 << pt::Log::logend;
PrintData();
}
ShiftRows();
if( plog )
{
(*plog) << pt::Log::log4 << " after shift rows, i= " << i+1 << pt::Log::logend;
PrintData();
}
if( i != round-1 )
{
MixColumns();
if( plog )
{
(*plog) << pt::Log::log4 << " after mix columns, i= " << i+1 << pt::Log::logend;
PrintData();
}
}
AddRoundKey((i+1)*4);
if( plog )
{
(*plog) << pt::Log::log4 << " after add round key, i= " << i+1 << pt::Log::logend;
PrintData();
}
}
}
/* inverse */
void AES::InvShiftRows1(AES::uint8 tab[4])
{
return ShiftRows3(tab);
}
void AES::InvShiftRows2(AES::uint8 tab[4])
{
return ShiftRows2(tab);
}
void AES::InvShiftRows3(AES::uint8 tab[4])
{
return ShiftRows1(tab);
}
void AES::InvShiftRows()
{
InvShiftRows1(data[1]);
InvShiftRows2(data[2]);
InvShiftRows3(data[3]);
}
AES::uint8 AES::InvSubBytes(AES::uint8 v)
{
int y = int(v) >> 4;
int x = (v & 0x0f);
return invsbox[y][x];
}
void AES::InvSubBytes()
{
int x, y;
for(y=0 ; y<4 ; ++y)
for(x=0 ; x<4 ; ++x)
data[y][x] = InvSubBytes(data[y][x]);
}
AES::uint8 AES::InvMixColumns(AES::uint8 gf_mul[16][16], AES::uint8 v)
{
int y = int(v) >> 4;
int x = (v & 0x0f);
return gf_mul[y][x];
}
AES::uint8 AES::InvMixColumns(int type, AES::uint8 value)
{
switch(type)
{
case 9:
return InvMixColumns(gf_mul9, value);
case 11:
return InvMixColumns(gf_mul11, value);
case 13:
return InvMixColumns(gf_mul13, value);
}
return InvMixColumns(gf_mul14, value);
}
void AES::InvMixColumns()
{
int x, y, i;
uint8 v;
uint8 temp[4];
for(x=0 ; x<4 ; ++x)
{
for(y=0 ; y<4 ; ++y)
{
v = 0;
for(i=0 ; i<4 ; ++i)
v ^= InvMixColumns(invmixcolumntab[y][i], data[i][x]);
temp[y] = v;
}
for(y=0 ; y<4 ; ++y)
data[y][x] = temp[y];
}
}
void AES::DecodeData()
{
int i;
if( plog )
{
(*plog) << pt::Log::log4 << " input data " << pt::Log::logend;
PrintData();
}
AddRoundKey(round*4);
if( plog )
{
(*plog) << pt::Log::log4 << " first round key " << pt::Log::logend;
PrintData();
}
for(i=round-1 ; i>=0 ; --i)
{
InvShiftRows();
if( plog )
{
(*plog) << pt::Log::log4 << " after invshiftrows, i= " << i << pt::Log::logend;
PrintData();
}
InvSubBytes();
if( plog )
{
(*plog) << pt::Log::log4 << " after invsubbutes, i= " << i << pt::Log::logend;
PrintData();
}
AddRoundKey(i*4);
if( plog )
{
(*plog) << pt::Log::log4 << " after add round key, i= " << i << pt::Log::logend;
PrintData();
}
if( i != 0 )
{
InvMixColumns();
if( plog )
{
(*plog) << pt::Log::log4 << " after inv mix columns, i= " << i << pt::Log::logend;
PrintData();
}
}
}
}
/*
*/
bool AES::Encode(AES::uint8 * block, size_t len)
{
if( len % 16 != 0 )
return false;
while( len > 0 )
{
CopyToData(block);
EncodeData();
CopyFromData(block);
len -= 16;
block += 16;
}
return true;
}
bool AES::Decode(AES::uint8 * block, size_t len)
{
if( len % 16 != 0 )
return false;
while( len > 0 )
{
CopyToData(block);
DecodeData();
CopyFromData(block);
len -= 16;
block += 16;
}
return true;
}
/*
*
* iv - initialization vector
*/
bool AES::EncodeCBC(AES::uint8 * block, size_t len, const AES::uint8 * iv)
{
if( len % 16 != 0 )
return false;
while( len > 0 )
{
XorCopyToData(block, iv);
EncodeData();
CopyFromData(block);
iv = block;
len -= 16;
block += 16;
}
return true;
}
bool AES::DecodeCBC(AES::uint8 * block, size_t len, const AES::uint8 * iv)
{
AES::uint8 cipher_copy[16];
AES::uint8 cipher_copy2[16];
bool use_first = true;
if( len % 16 != 0 )
return false;
while( len > 0 )
{
if( use_first )
{
for(size_t i=0 ; i < 16 ; ++i)
cipher_copy[i] = block[i];
}
else
{
for(size_t i=0 ; i < 16 ; ++i)
cipher_copy2[i] = block[i];
}
CopyToData(block);
DecodeData();
XorCopyFromData(block, iv);
if( use_first )
iv = cipher_copy;
else
iv = cipher_copy2;
len -= 16;
block += 16;
use_first = !use_first;
}
for(size_t i=0 ; i < 16 ; ++i)
{
cipher_copy[i] = 0;
cipher_copy2[i] = 0;
}
return true;
}
bool AES::EncodeCBC_PKCS7(std::vector<uint8> & content, const AES::uint8 * iv)
{
size_t remainder = content.size() % 16;
size_t pad = 16 - remainder;
size_t i = content.size();
content.resize(content.size() + pad);
for( ; i < content.size() ; ++i)
content[i] = pad;
return EncodeCBC(content.data(), content.size(), iv);
}
bool AES::DecodeCBC_PKCS7(std::vector<uint8> & content, const AES::uint8 * iv)
{
// there has to be at least one block (block from padding if the original content was empty)
if( content.empty() )
return false;
if( !DecodeCBC(content.data(), content.size(), iv) )
return false;
size_t pad = content[content.size()-1];
if( pad > 16 || content.size() < pad )
return false;
for(size_t i = content.size() - pad ; i < content.size() ; ++i)
{
if( content[i] != pad )
return false;
}
content.resize(content.size() - pad);
return true;
}
void AES::IntToBuf(AES::uint8 * buf, AES::uint16 value)
{
buf[0] = value & 0xff;
buf[1] = (value >> 8) & 0xff;
}
void AES::IntToBuf(AES::uint8 * buf, AES::uint32 value)
{
buf[0] = value & 0xff;
buf[1] = (value >> 8) & 0xff;
buf[2] = (value >> 16) & 0xff;
buf[3] = (value >> 24) & 0xff;
}
void AES::CreateHeader(TiHeader & header, const AES::uint8 * block, size_t len, const std::string & name, bool use_rand_first_padding)
{
header.signature = int('t') + (int('i') << 8);
// first padding from 3 to 9
if( use_rand_first_padding )
header.pad1 = (6 * rand()) / RAND_MAX + 3;
else
header.pad1 = 3;
header.all_len = 12 + header.pad1 + name.size() + len;
header.pad2 = 0;
if( (header.all_len % 16) != 0 )
header.pad2 = 16 - (header.all_len % 16);
header.all_len += header.pad2;
header.checksum_before = Checksum(block, len);
header.checksum_after = 0;
header.name_len = name.size();
}
void AES::PutHeader(const TiHeader & header, std::vector<AES::uint8> & out)
{
uint8 buf[16];
IntToBuf(buf, header.signature);
out.push_back(buf[0]);
out.push_back(buf[1]);
// space for checksum after encoding
out.push_back(0);
out.push_back(0);
out.push_back(0);
out.push_back(0);
IntToBuf(buf, header.pad1);
IntToBuf(buf+2, header.pad2);
IntToBuf(buf+4, header.checksum_before);
IntToBuf(buf+8, header.name_len);
for(int i=12 ; i<16 ; ++i)
buf[i] = 0;
CopyToData(buf);
}
void AES::PutChecksumAfter(std::vector<AES::uint8> & out)
{
if( out.size() < 7 )
return; // something wrong
// checksum starting from 6th byte
AES::uint32 checksum_after = Checksum(&out[6], out.size()-6);
IntToBuf(&out[2], checksum_after);
}
AES::uint32 AES::Checksum(const uint8 * block, size_t len)
{
uint32 sum = 0;
for(size_t i=0 ; i<len ; ++i)
sum += block[i];
return sum;
}
void AES::EncodePad(int & y, int & x, AES::uint16 pad, std::vector<AES::uint8> & out)
{
AES::uint16 index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for(; y<4 ; ++y)
{
if( index < pad )
{
data[y][x] = (rand() * 255) / RAND_MAX;
index += 1;
}
else
{
return;
}
}
y = 0;
}
x = 0;
EncodeData();
CopyFromData(out, false);
}
}
void AES::EncodeName(int & y, int & x, const std::string & name, std::vector<AES::uint8> & out)
{
size_t index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for(; y<4 ; ++y)
{
if( index < name.size() )
{
data[y][x] = name[index];
index += 1;
}
else
{
return;
}
}
y = 0;
}
x = 0;
EncodeData();
CopyFromData(out, false);
}
}
void AES::EncodeData(int & y, int & x, const AES::uint8 * block, size_t len, std::vector<AES::uint8> & out)
{
size_t index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for(; y<4 ; ++y)
{
if( index < len )
{
data[y][x] = block[index];
index += 1;
}
else
{
return;
}
}
y = 0;
}
x = 0;
EncodeData();
CopyFromData(out, false);
}
}
/*
(not encrypted)
2 bytes: signature "ti"
4 bytes: data checksum after encoding
---
6 bytes
(encrypted)
2 bytes: first padding length (from 3 to 9)
2 bytes: last padding length (can be zero)
4 bytes: data checksum before encoding
4 bytes: name string length (it can be a name of a file or just zero means an empty string)
---
12 bytes (18 bytes alltogether)
... bytes: first padding
... bytes: name string
... bytes: data
... bytes: last padding
*/
bool AES::Encode(const AES::uint8 * block, size_t len, const std::string & name, std::vector<AES::uint8> & out)
{
TiHeader header;
out.clear();
CreateHeader(header, block, len, name);
PutHeader(header, out);
if( out.capacity() < header.all_len )
out.reserve(header.all_len);
// skipping first 12 bytes from 'data'
int y = 0;
int x = 3;
EncodePad (y, x, header.pad1, out);
EncodeName(y, x, name, out);
EncodeData(y, x, block, len, out);
EncodePad (y, x, header.pad2, out);
PutChecksumAfter(out);
return true;
}
bool AES::Encode(const std::vector<AES::uint8> & block, const std::string & name, std::vector<AES::uint8> & out)
{
if( block.empty() )
return Encode(0, 0, name, out);
else
return Encode(&block[0], block.size(), name, out);
}
/*
*/
void AES::ReadHeader(TiHeader & header, const AES::uint8 * block)
{
header.signature = (uint16(block[1]) << 8) + uint16(block[0]);
header.checksum_after = (uint32(block[5]) << 24) + (uint32(block[4]) << 16) + (uint32(block[3]) << 8) + uint32(block[2]);
header.pad1 = (uint16(data[1][0]) << 8) + uint16(data[0][0]);
header.pad2 = (uint16(data[3][0]) << 8) + uint16(data[2][0]);
header.checksum_before = (uint32(data[3][1]) << 24) + (uint32(data[2][1]) << 16) + (uint32(data[1][1]) << 8) + uint32(data[0][1]);
header.name_len = (uint32(data[3][2]) << 24) + (uint32(data[2][2]) << 16) + (uint32(data[1][2]) << 8) + uint32(data[0][2]);
}
void AES::DecodePad(int & y, int & x, const AES::uint8 * & block, size_t & len, AES::uint16 pad)
{
AES::uint16 index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for( ; y<4 ; ++y)
{
if( index < pad )
{
index += 1;
}
else
{
return;
}
}
y = 0;
}
x = 0;
if( len > 0 )
{
CopyToData(block);
DecodeData();
block += 16;
len -= 16;
}
}
}
void AES::DecodeName(int & y, int & x, const AES::uint8 * & block, size_t & len, AES::uint32 name_len, std::string & name)
{
AES::uint32 index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for( ; y<4 ; ++y)
{
if( index < name_len )
{
index += 1;
name += static_cast<char>(data[y][x]);
}
else
{
return;
}
}
y = 0;
}
x = 0;
if( len > 0 )
{
CopyToData(block);
DecodeData();
block += 16;
len -= 16;
}
}
}
void AES::DecodeData(int & y, int & x, const AES::uint8 * & block, size_t & len, size_t data_len, std::vector<AES::uint8> & out)
{
size_t index = 0;
while( true )
{
for( ; x<4 ; ++x)
{
for( ; y<4 ; ++y)
{
if( index < data_len )
{
index += 1;
out.push_back(data[y][x]);
}
else
{
return;
}
}
y = 0;
}
x = 0;
if( len > 0 )
{
CopyToData(block);
DecodeData();
block += 16;
len -= 16;
}
}
}
bool AES::CheckSignatureAndChecksumAfter(const TiHeader & header, const AES::uint8 * block, size_t len)
{
if( ((header.signature >> 8) & 0xff) != 'i' || (header.signature & 0xff) != 't' )
return false;
AES::uint32 ch_after = Checksum(block+6, len-6);
return ch_after == header.checksum_after;
}
bool AES::CheckChecksumBefore(const TiHeader & header, std::vector<AES::uint8> & out)
{
AES::uint32 ch_before = 0;
if( !out.empty() )
ch_before = Checksum(&out[0], out.size());
return ch_before == header.checksum_before;
}
bool AES::Decode(const AES::uint8 * block, size_t len, std::string & name, std::vector<AES::uint8> & out)
{
TiHeader header;
name.clear();
out.clear();
// incorrect size
if( len < 18 || (len - 6) % 16 != 0)
return false;
CopyToData(block+6);
DecodeData();
ReadHeader(header, block);
if( !CheckSignatureAndChecksumAfter(header, block, len) )
return false;
size_t min_size = 18 + header.pad1 + header.name_len + header.pad2;
if( len < min_size )
return false;
size_t data_len = len - 18 - header.pad1 - header.name_len - header.pad2;
int y = 0;
int x = 3;
// skipping non encrypted part and first block
block += (6 + 16);
len -= (6 + 16);
DecodePad (y, x, block, len, header.pad1);
DecodeName(y, x, block, len, header.name_len, name);
DecodeData(y, x, block, len, data_len, out);
return CheckChecksumBefore(header, out);
}
bool AES::Decode(const std::vector<AES::uint8> & block, std::string & name, std::vector<AES::uint8> & out)
{
if( block.empty() )
return Decode(0, 0, name, out);
else
return Decode(&block[0], block.size(), name, out);
}
/*
algorithm description: http://www.samiam.org/galois.html
*/
AES::uint8 AES::GaloisMultiply(AES::uint8 a, AES::uint8 b)
{
int i;
uint8 p = 0;
for(i=0; i<8 ;++i)
{
if(b & 1)
p ^= a;
bool a_high_bit = (a & 0x80) != 0;
a = a << 1;
if( a_high_bit )
a ^= 0x1b;
b = b >> 1;
}
return p;
}
bool AES::CheckGFTable(int value, AES::uint8 gf_mul[16][16])
{
int x,y;
bool ok = true;
for(y=0 ; y<16 ; ++y)
{
for(x=0 ; x<16 ; ++x)
{
int v1 = gf_mul[y][x];
int v2 = GaloisMultiply(value, y*16 + x);
if( v1 != v2 )
{
if( plog )
{
(*plog) << pt::Log::log2 << "error: y: " << y << ", x: " << x << ", v1: " << v1 << ", v2: " << v2 << pt::Log::logend;
}
ok = false;
}
}
}
return ok;
}
bool AES::CheckGFTables()
{
bool ok9, ok11, ok13, ok14;
ok9 = CheckGFTable(9, gf_mul9);
ok11 = CheckGFTable(11, gf_mul11);
ok13 = CheckGFTable(13, gf_mul13);
ok14 = CheckGFTable(14, gf_mul14);
bool ok = ok9 && ok11 && ok13 && ok14;
if( ok )
{
if( plog )
{
(*plog) << pt::Log::log4 << "All GF tables are good" << pt::Log::logend;
}
}
return ok;
}
void AES::set_logger(pt::Log * plog)
{
this->plog = plog;
}
} // namespace Tito