From ff5381cfa9cce080471fec3e83f9f1462706f909 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Fri, 7 Dec 2018 05:06:34 +0000 Subject: [PATCH] added: AES: encoding/decoding CBC mode with PKCS7 padding added: base32 encoding/decoding git-svn-id: svn://ttmath.org/publicrep/tito/trunk@1159 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/Makefile.dep | 10 +- src/Makefile.o.dep | 2 +- src/aes.cpp | 152 +++++++++++++++++++++- src/aes.h | 21 ++- src/base32.cpp | 314 +++++++++++++++++++++++++++++++++++++++++++++ src/base32.h | 90 +++++++++++++ 6 files changed, 583 insertions(+), 6 deletions(-) create mode 100644 src/base32.cpp create mode 100644 src/base32.h diff --git a/src/Makefile.dep b/src/Makefile.dep index 27b2876..4f06d5e 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,6 +1,14 @@ # DO NOT DELETE aes.o: aes.h +base32.o: base32.h base64.o: base64.h -crypto.o: crypto.h aes.h base64.h ../../pikotools/utf8/utf8.h misc.h +crypto.o: crypto.h aes.h base64.h ../../pikotools/utf8/utf8.h +crypto.o: ../../pikotools/textstream/textstream.h +crypto.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h +crypto.o: ../../pikotools/date/date.h ../../pikotools/convert/convert.h +crypto.o: ../../pikotools/convert/inttostr.h +crypto.o: ../../pikotools/convert/strtoint.h ../../pikotools/convert/text.h +crypto.o: misc.h ../../pikotools/membuffer/membuffer.h +crypto.o: ../../pikotools/textstream/types.h misc.o: misc.h diff --git a/src/Makefile.o.dep b/src/Makefile.o.dep index f8d04cf..e98a22a 100644 --- a/src/Makefile.o.dep +++ b/src/Makefile.o.dep @@ -1 +1 @@ -o = aes.o base64.o crypto.o misc.o \ No newline at end of file +o = aes.o base32.o base64.o crypto.o misc.o \ No newline at end of file diff --git a/src/aes.cpp b/src/aes.cpp index a1b135d..ecb87d5 100644 --- a/src/aes.cpp +++ b/src/aes.cpp @@ -192,6 +192,20 @@ int x, y, index = 0; } +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) { @@ -203,6 +217,22 @@ int x, y, index = 0; } +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; @@ -782,6 +812,119 @@ 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; + + int 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) @@ -799,12 +942,16 @@ void AES::IntToBuf(AES::uint8 * buf, AES::uint32 value) } -void AES::CreateHeader(TiHeader & header, const AES::uint8 * block, size_t len, const std::string & name) +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 - header.pad1 = (6 * rand()) / RAND_MAX + 3; + 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; @@ -1018,6 +1165,7 @@ bool AES::Encode(const std::vector & block, const std::string & name } + /* */ void AES::ReadHeader(TiHeader & header, const AES::uint8 * block) diff --git a/src/aes.h b/src/aes.h index c8c8014..41518ba 100644 --- a/src/aes.h +++ b/src/aes.h @@ -63,7 +63,11 @@ typedef unsigned int uint32; // 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 @@ -77,12 +81,24 @@ typedef unsigned int uint32; void EncodeData(); void DecodeData(); - // encoding/decoding block of data + // 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 @@ -94,6 +110,7 @@ typedef unsigned int uint32; 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(); @@ -214,7 +231,7 @@ private: 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); + 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); diff --git a/src/base32.cpp b/src/base32.cpp new file mode 100644 index 0000000..5dbe910 --- /dev/null +++ b/src/base32.cpp @@ -0,0 +1,314 @@ +/* + * This file is a part of Tito - a cryptography library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2018, 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: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 OWNER 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 "base32.h" + + +namespace Tito +{ + + +// 64 characters +const char * Base32::tabbase32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + + + +Base32::Base32() +{ + padding = '='; + tabbase32_len = 32; + not_existing = 256; // first 8 bits are zero +} + + + +void Base32::SetPadding(char c) +{ + for(size_t i=0 ; i(s); + + for(size_t i=0 ; i<8 ; ++i) + tab8[i] = 32; + + if( len == 0 ) + return; + + tab8[0] = tab5[0] >> 3; + tab8[1] = (tab5[0] & 0x07) << 2; + + if( len == 1 ) + return; + + tab8[1] = tab8[1] | ((tab5[1] & 0xc0) >> 6); + tab8[2] = (tab5[1] >> 1) & 0x1f; + tab8[3] = (tab5[1] & 0x01) << 4; + + if( len == 2 ) + return; + + tab8[3] = tab8[3] | ((tab5[2] & 0xf0) >> 4); + tab8[4] = ((tab5[2] & 0x0f) << 1); + + if( len == 3 ) + return; + + tab8[4] = tab8[4] | (tab5[3] & 0x80) >> 7; + tab8[5] = (tab5[3] >> 2) & 0x1f; + tab8[6] = (tab5[3] & 0x03) << 3; + + if( len == 4 ) + return; + + tab8[6] = tab8[6] | ((tab5[4] & 0xe0) >> 5); + tab8[7] = tab5[4] & 0x1f; +} + + + +void Base32::ConvertFrom8to5Pieces(const unsigned int * tab8, unsigned int * tab5) +{ + /* + tab8[0] and tab8[1] are always different from 'not_existing' + */ + + for(size_t i=0 ; i<5 ; ++i) + tab5[i] = not_existing; + + tab5[0] = ((tab8[0] & 0x1f) << 3) | ((tab8[1] & 0x1c) >> 2); + + // in order to exist tab5[1] a tab8[2] and tab8[3] should exist + if( tab8[2] == not_existing ) + return; + + if( tab8[3] == not_existing ) + return; // IMPROVE ME this is an error, cannot be such a string as input base32 + + tab5[1] = (tab8[1] & 0x03) << 6; + tab5[1] = tab5[1] | ((tab8[2] & 0x1f) << 1); + tab5[1] = tab5[1] | ((tab8[3] & 0x10) >> 4); + + // in order to exist tab5[2] a tab8[4] should exist + if( tab8[4] == not_existing ) + return; + + tab5[2] = (tab8[3] & 0x0f) << 4; + tab5[2] = tab5[2] | ((tab8[4] & 0x1e) >> 1); + + // in order to exist tab5[3] a tab8[5] and tab8[6] should exist + if( tab8[5] == not_existing ) + return; + + if( tab8[6] == not_existing ) + return; // IMPROVE ME this is an error, cannot be such a string as input base32 + + tab5[3] = (tab8[4] & 0x01) << 7; + tab5[3] = tab5[3] | ((tab8[5] & 0x1f) << 2); + tab5[3] = tab5[3] | ((tab8[6] & 0x18) >> 3); + + if( tab8[7] == not_existing ) + return; + + tab5[4] = (tab8[6] & 0x07) << 5; + tab5[4] = tab5[4] | (tab8[7] & 0x1f); +} + + + + + +bool Base32::CharFromBase32(unsigned int from, unsigned int & to) +{ + if( from>='A' && from<='Z' ) + { + to = from-'A'; + return true; + } + else + if( from>='a' && from<='z' ) + { + to = from - 'a'; + return true; + } + else + if( from>='2' && from<='7' ) + { + to = from - '2' + 'Z'-'A' + 1; + return true; + } + + /* + such character does not exist in tabbase32 table + */ + return false; +} + + + +bool Base32::Make8pieces(const char * s, unsigned int * tab8) +{ + for(size_t i=0 ; i<8 ; ++i) + { + if( s[i] == padding ) + tab8[i] = not_existing; + else + if( !CharFromBase32(s[i], tab8[i]) ) + return false; + } + +return true; +} + + + + +void Base32::Save8PiecesToString(std::string & s, const unsigned int * tab8) +{ + for(int i=0 ; i<8 ; ++i) + { + if( tab8[i] < tabbase32_len ) + s += tabbase32[tab8[i]]; + else + s += padding; + } +} + + + +void Base32::Save5PiecesToString(std::string & s, const unsigned int * tab5) +{ + for(int i=0 ; i<5 ; ++i) + { + if( tab5[i] != not_existing ) + s += tab5[i]; + } +} + + + + +/* +*/ +void Base32::Encode(const char * in, size_t len, std::string & out) +{ +unsigned int tab8[8]; + + out.clear(); + size_t new_size = len + (size_t)((double)(len) * (5.0/8.0)) + 8; + out.reserve(new_size); + + for(size_t i=0 ; i < len ; i+=5) + { + Convert5to8Pieces(in+i, len-i, tab8); + Save8PiecesToString(out, tab8); + } +} + + +void Base32::Encode(const char * in, std::string & out) +{ + size_t len = strlen(in); + Encode(in, len, out); +} + + +void Base32::Encode(const std::string & in, std::string & out) +{ + Encode(in.c_str(), in.size(), out); +} + + + + + + +bool Base32::Decode(const char * in, size_t len, std::string & out) +{ +unsigned int tab5[5]; +unsigned int tab8[8]; + + out.clear(); + + if( len % 8 != 0 ) + return false; + + size_t new_size = len - (size_t)((double)(len) * (5.0/8.0)) + 5; + + if( new_size > 0 ) + out.reserve(new_size); + + for(size_t i=0 ; i + */ + +/* + * Copyright (c) 2018, 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: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 OWNER 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_base32 +#define headerfile_tito_base32 + +#include + + +namespace Tito +{ + + +class Base32 +{ +public: + + Base32(); + + // default '='; + void SetPadding(char c); + + void Encode(const char * in, size_t len, std::string & out); + void Encode(const char * in, std::string & out); + void Encode(const std::string & in, std::string & out); + + bool Decode(const char * in, size_t len, std::string & out); + bool Decode(const char * in, std::string & out); + bool Decode(const std::string & in, std::string & out); + + + +private: + + static const char * tabbase32; + size_t tabbase32_len; + char padding; + unsigned int not_existing; + + void Convert5to8Pieces(const char * s, size_t len, unsigned int * tab8); + void ConvertFrom8to5Pieces(const unsigned int * tab8, unsigned int * tab5); + bool CharFromBase32(unsigned int from, unsigned int & to); + bool Make8pieces(const char * s, unsigned int * tab8); + void Save8PiecesToString(std::string & s, const unsigned int * tab8); + void Save5PiecesToString(std::string & s, const unsigned int * tab5); + +}; + + + +} // namespace Tito + + + +#endif +