File indexing completed on 2024-06-16 03:53:03

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2001 George Staikos <staikos@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 // FIXME: should we unroll some loops?  Optimization can be done here.
0009 
0010 /* Implementation of 16 rounds blowfish as described in:
0011  * _Applied_Cryptography_ (c) Bruce Schneier, 1996.
0012  */
0013 
0014 #include "blowfish.h"
0015 
0016 #include <stdlib.h>
0017 #include <stdio.h>
0018 #include <string.h>
0019 
0020 #include "blowfishtables.h"
0021 
0022 // DO NOT INCLUDE THIS. IT BREAKS KWALLET.
0023 // We need to live with -Wundef until someone really figures out the problem.
0024 //#include <QtCore/qglobal.h> // for Q_BYTE_ORDER and friends
0025 // Workaround for -Wundef
0026 #define Q_BIG_ENDIAN 1
0027 #define Q_BYTE_ORDER Q_BIG_ENDIAN
0028 
0029 BlowFish::BlowFish()
0030 {
0031     _blksz = 8;
0032     m_key = nullptr;
0033     m_initialized = false;
0034 }
0035 
0036 bool BlowFish::init()
0037 {
0038     // Initialize the sboxes
0039     for (int i = 0; i < 256; i++) {
0040         m_S[0][i] = ks0[i];
0041         m_S[1][i] = ks1[i];
0042         m_S[2][i] = ks2[i];
0043         m_S[3][i] = ks3[i];
0044     }
0045 
0046     uint32_t datal = 0;
0047     uint32_t datar = 0;
0048     uint32_t data = 0;
0049     int j = 0;
0050 
0051     // Update the sboxes and pbox.
0052     for (int i = 0; i < 18; i++) {
0053         data = 0;
0054         for (int k = 0; k < 4; ++k) {
0055             data = (data << 8) | ((unsigned char *)m_key)[j++];
0056             if (j >= m_keylen / 8) {
0057                 j = 0;
0058             }
0059         }
0060         m_P[i] = P[i] ^ data;
0061     }
0062 
0063     for (int i = 0; i < 18; i += 2) {
0064         encipher(&datal, &datar);
0065         m_P[i] = datal;
0066         m_P[i + 1] = datar;
0067     }
0068 
0069     for (int j = 0; j < 4; j++) {
0070         for (int i = 0; i < 256; i += 2) {
0071             encipher(&datal, &datar);
0072             m_S[j][i] = datal;
0073             m_S[j][i + 1] = datar;
0074         }
0075     }
0076 
0077     // Nice code from gpg's implementation...
0078     //     check to see if the key is weak and return error if so
0079     for (int i = 0; i < 255; i++) {
0080         for (int j = i + 1; j < 256; j++) {
0081             if ((m_S[0][i] == m_S[0][j]) || (m_S[1][i] == m_S[1][j]) ||
0082                     (m_S[2][i] == m_S[2][j]) || (m_S[3][i] == m_S[3][j])) {
0083                 return false;
0084             }
0085         }
0086     }
0087 
0088     m_initialized = true;
0089 
0090     return true;
0091 }
0092 
0093 BlowFish::~BlowFish()
0094 {
0095     delete[](unsigned char *)m_key;
0096     m_key = nullptr;
0097 }
0098 
0099 int BlowFish::keyLen() const
0100 {
0101     return 448;
0102 }
0103 
0104 bool BlowFish::variableKeyLen() const
0105 {
0106     return true;
0107 }
0108 
0109 bool BlowFish::readyToGo() const
0110 {
0111     return m_initialized;
0112 }
0113 
0114 bool BlowFish::setKey(void *key, int bitlength)
0115 {
0116     if (bitlength <= 0 || bitlength > 448 || bitlength % 8 != 0) {
0117         return false;
0118     }
0119 
0120     delete[](unsigned char *)m_key;
0121 
0122     m_key = new unsigned char[bitlength / 8];
0123     memcpy(m_key, key, bitlength / 8);
0124     m_keylen = bitlength;
0125 
0126     return init();
0127 }
0128 // clang-format off
0129 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0130 #define shuffle(x) do {             \
0131         uint32_t r = x;             \
0132         x  = (r & 0xff000000) >> 24;    \
0133         x |= (r & 0x00ff0000) >>  8;    \
0134         x |= (r & 0x0000ff00) <<  8;    \
0135         x |= (r & 0x000000ff) << 24;    \
0136     } while (0)
0137 #endif
0138 // clang-format on
0139 
0140 int BlowFish::encrypt(void *block, int len)
0141 {
0142     uint32_t *d = (uint32_t *)block;
0143 
0144     if (!m_initialized || len % _blksz != 0) {
0145         return -1;
0146     }
0147 
0148     for (int i = 0; i < len / _blksz; i++) {
0149 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0150         shuffle(*d);
0151         shuffle(*(d + 1));
0152 #endif
0153         encipher(d, d + 1);
0154 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0155         shuffle(*d);
0156         shuffle(*(d + 1));
0157 #endif
0158         d += 2;
0159     }
0160 
0161     return len;
0162 }
0163 
0164 int BlowFish::decrypt(void *block, int len)
0165 {
0166     uint32_t *d = (uint32_t *)block;
0167 
0168     if (!m_initialized || len % _blksz != 0) {
0169         return -1;
0170     }
0171 
0172     for (int i = 0; i < len / _blksz; i++) {
0173 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0174         shuffle(*d);
0175         shuffle(*(d + 1));
0176 #endif
0177         decipher(d, d + 1);
0178 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
0179         shuffle(*d);
0180         shuffle(*(d + 1));
0181 #endif
0182         d += 2;
0183     }
0184 
0185     return len;
0186 }
0187 
0188 uint32_t BlowFish::F(uint32_t x)
0189 {
0190     unsigned short a;
0191     unsigned short b;
0192     unsigned short c;
0193     unsigned short d;
0194     uint32_t y;
0195 
0196     d = x & 0x000000ff;
0197     x >>= 8;
0198     c = x & 0x000000ff;
0199     x >>= 8;
0200     b = x & 0x000000ff;
0201     x >>= 8;
0202     a = x & 0x000000ff;
0203 
0204     y = m_S[0][a] + m_S[1][b];
0205     y ^= m_S[2][c];
0206     y += m_S[3][d];
0207 
0208     return y;
0209 }
0210 
0211 void BlowFish::encipher(uint32_t *xl, uint32_t *xr)
0212 {
0213     uint32_t Xl = *xl;
0214     uint32_t Xr = *xr;
0215     uint32_t temp;
0216 
0217     for (int i = 0; i < 16; ++i) {
0218         Xl ^= m_P[i];
0219         Xr ^= F(Xl);
0220         // Exchange
0221         temp = Xl; Xl = Xr; Xr = temp;
0222     }
0223 
0224     // Exchange
0225     temp = Xl; Xl = Xr; Xr = temp;
0226 
0227     Xr ^= m_P[16];
0228     Xl ^= m_P[17];
0229 
0230     *xl = Xl;
0231     *xr = Xr;
0232 }
0233 
0234 void BlowFish::decipher(uint32_t *xl, uint32_t *xr)
0235 {
0236     uint32_t Xl = *xl;
0237     uint32_t Xr = *xr;
0238     uint32_t temp;
0239 
0240     for (int i = 17; i > 1; --i) {
0241         Xl ^= m_P[i];
0242         Xr ^= F(Xl);
0243         // Exchange
0244         temp = Xl; Xl = Xr; Xr = temp;
0245     }
0246 
0247     // Exchange
0248     temp = Xl; Xl = Xr; Xr = temp;
0249 
0250     Xr ^= m_P[1];
0251     Xl ^= m_P[0];
0252 
0253     *xl = Xl;
0254     *xr = Xr;
0255 }