diff options
Diffstat (limited to 'tdewallet/backend/blowfish.cc')
-rw-r--r-- | tdewallet/backend/blowfish.cc | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/tdewallet/backend/blowfish.cc b/tdewallet/backend/blowfish.cc new file mode 100644 index 000000000..c708935de --- /dev/null +++ b/tdewallet/backend/blowfish.cc @@ -0,0 +1,259 @@ +/* This file is part of the KDE project + Copyright (C) 2001 George Staikos <staikos@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +// FIXME: should we unroll some loops? Optimization can be done here. + + +/* Implementation of 16 rounds blowfish as described in: + * _Applied_Cryptography_ (c) Bruce Schneier, 1996. + */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "blowfish.h" +#include "blowfishtables.h" + + +BlowFish::BlowFish() { + _blksz = 8; + _key = 0L; + _init = false; +} + + + +bool BlowFish::init() { + // Initialize the sboxes + for (int i = 0; i < 256; i++) { + _S[0][i] = ks0[i]; + _S[1][i] = ks1[i]; + _S[2][i] = ks2[i]; + _S[3][i] = ks3[i]; + } + + uint32_t datal = 0; + uint32_t datar = 0; + uint32_t data = 0; + int j = 0; + + + // Update the sboxes and pbox. + for (int i = 0; i < 18; i++) { + data = 0; + for (int k = 0; k < 4; ++k) { + data = (data << 8) | ((unsigned char *)_key)[j++]; + if (j >= _keylen / 8) { + j = 0; + } + } + _P[i] = P[i] ^ data; + } + + for (int i = 0; i < 18; i += 2) { + encipher(&datal, &datar); + _P[i] = datal; + _P[i+1] = datar; + } + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 256; i += 2) { + encipher(&datal, &datar); + _S[j][i] = datal; + _S[j][i+1] = datar; + } + } + + // Nice code from gpg's implementation... + // check to see if the key is weak and return error if so + for (int i = 0; i < 255; i++) { + for (int j = i + 1; j < 256; j++) { + if ((_S[0][i] == _S[0][j]) || (_S[1][i] == _S[1][j]) || + (_S[2][i] == _S[2][j]) || (_S[3][i] == _S[3][j])) { + return false; + } + } + } + + _init = true; + + return true; +} + + +BlowFish::~BlowFish() { + delete[] (unsigned char *)_key; + _key = 0L; +} + + +int BlowFish::keyLen() const { + return 448; +} + + +bool BlowFish::variableKeyLen() const { + return true; +} + + +bool BlowFish::readyToGo() const { + return _init; +} + + +bool BlowFish::setKey(void *key, int bitlength) { + if (bitlength <= 0 || bitlength > 448 || bitlength % 8 != 0) { + return false; + } + + delete[] (unsigned char *)_key; + + _key = new unsigned char[bitlength / 8]; + memcpy(_key, key, bitlength / 8); + _keylen = bitlength; + + return init(); +} + + +#ifdef WORDS_BIGENDIAN +#define shuffle(x) do { \ + uint32_t r = x; \ + x = (r & 0xff000000) >> 24; \ + x |= (r & 0x00ff0000) >> 8; \ + x |= (r & 0x0000ff00) << 8; \ + x |= (r & 0x000000ff) << 24; \ + } while (0) +#endif + +int BlowFish::encrypt(void *block, int len) { + uint32_t *d = (uint32_t *)block; + + if (!_init || len % _blksz != 0) { + return -1; + } + + for (int i = 0; i < len / _blksz; i++) { +#ifdef WORDS_BIGENDIAN + shuffle(*d); + shuffle(*(d + 1)); +#endif + encipher(d, d + 1); +#ifdef WORDS_BIGENDIAN + shuffle(*d); + shuffle(*(d + 1)); +#endif + d += 2; + } + + return len; +} + + +int BlowFish::decrypt(void *block, int len) { + uint32_t *d = (uint32_t *)block; + + if (!_init || len % _blksz != 0) { + return -1; + } + + for (int i = 0; i < len / _blksz; i++) { +#ifdef WORDS_BIGENDIAN + shuffle(*d); + shuffle(*(d + 1)); +#endif + decipher(d, d + 1); +#ifdef WORDS_BIGENDIAN + shuffle(*d); + shuffle(*(d + 1)); +#endif + d += 2; + } + + return len; +} + + +uint32_t BlowFish::F(uint32_t x) { + unsigned short a, b, c, d; + uint32_t y; + + d = x & 0x000000ff; + x >>= 8; + c = x & 0x000000ff; + x >>= 8; + b = x & 0x000000ff; + x >>= 8; + a = x & 0x000000ff; + + y = _S[0][a] + _S[1][b]; + y ^= _S[2][c]; + y += _S[3][d]; + + return y; +} + + +void BlowFish::encipher(uint32_t *xl, uint32_t *xr) { + uint32_t Xl = *xl, Xr = *xr, temp; + + for (int i = 0; i < 16; ++i) { + Xl ^= _P[i]; + Xr ^= F(Xl); + // Exchange + temp = Xl; Xl = Xr; Xr = temp; + } + + // Exchange + temp = Xl; Xl = Xr; Xr = temp; + + Xr ^= _P[16]; + Xl ^= _P[17]; + + *xl = Xl; + *xr = Xr; +} + + +void BlowFish::decipher(uint32_t *xl, uint32_t *xr) { + uint32_t Xl = *xl, Xr = *xr, temp; + + for (int i = 17; i > 1; --i) { + Xl ^= _P[i]; + Xr ^= F(Xl); + // Exchange + temp = Xl; Xl = Xr; Xr = temp; + } + + // Exchange + temp = Xl; Xl = Xr; Xr = temp; + + Xr ^= _P[1]; + Xl ^= _P[0]; + + *xl = Xl; + *xr = Xr; +} + + |