/* * 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. * */ #include #include #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 & 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> 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 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=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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & block, const std::string & name, std::vector & 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(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 & 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 & 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 & 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 & block, std::string & name, std::vector & 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