/* * This file is a part of Tito - a cryptography library * and is distributed under the 2-Clause 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: * * 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 "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