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 #include "cbc.h"
0009 #include "kwalletbackend_debug.h"
0010 #include <string.h>
0011 
0012 CipherBlockChain::CipherBlockChain(BlockCipher *cipher, bool useECBforReading) :
0013     _cipher(cipher)
0014     , _useECBforReading(useECBforReading)
0015 {
0016     _next = nullptr;
0017     _register = nullptr;
0018     _len = -1;
0019     _reader = _writer = 0L;
0020     if (cipher) {
0021         _blksz = cipher->blockSize();
0022     }
0023 }
0024 
0025 CipherBlockChain::~CipherBlockChain()
0026 {
0027     delete[](char *)_register;
0028     _register = nullptr;
0029     delete[](char *)_next;
0030     _next = nullptr;
0031 }
0032 
0033 bool CipherBlockChain::setKey(void *key, int bitlength)
0034 {
0035     if (_cipher) {
0036         return _cipher->setKey(key, bitlength);
0037     }
0038     return false;
0039 }
0040 
0041 int CipherBlockChain::keyLen() const
0042 {
0043     if (_cipher) {
0044         return _cipher->keyLen();
0045     }
0046     return -1;
0047 }
0048 
0049 bool CipherBlockChain::variableKeyLen() const
0050 {
0051     if (_cipher) {
0052         return _cipher->variableKeyLen();
0053     }
0054     return false;
0055 }
0056 
0057 bool CipherBlockChain::readyToGo() const
0058 {
0059     if (_cipher) {
0060         return _cipher->readyToGo();
0061     }
0062     return false;
0063 }
0064 
0065 void CipherBlockChain::initRegister() {
0066     if (_register == nullptr) {
0067         size_t registerLen = _cipher->blockSize();
0068         _register = new unsigned char[registerLen];
0069         _len = registerLen;
0070     }
0071     memset(_register, 0, _len);
0072 }
0073 
0074 int CipherBlockChain::encrypt(void *block, int len)
0075 {
0076     if (_cipher && !_reader) {
0077         int rc;
0078 
0079         _writer |= 1;
0080 
0081         initRegister();
0082 
0083         if ((len % _len) >0) {
0084             qCDebug(KWALLETBACKEND_LOG) << "Block length given encrypt (" << len << ") is not a multiple of " << _len;
0085             return -1;
0086         }
0087 
0088         char *elemBlock = static_cast<char*>(block);
0089         for (int b = 0; b < len/_len; b++) {
0090 
0091             // This might be optimizable
0092             char *tb = static_cast<char*>(elemBlock);
0093             for (int i = 0; i < _len; i++) {
0094                 *tb++ ^= ((char *)_register)[i];
0095             }
0096 
0097             rc = _cipher->encrypt(elemBlock, _len);
0098 
0099             if (rc != -1) {
0100                 memcpy(_register, elemBlock, _len);
0101             }
0102             elemBlock += _len;
0103         }
0104 
0105         return rc;
0106     }
0107     return -1;
0108 }
0109 
0110 // This is the old decrypt method, that was decrypting using ECB
0111 // instead of CBC
0112 int CipherBlockChain::decryptECB(void *block, int len) {
0113     if (_cipher && !_writer) {
0114         int rc;
0115 
0116         _reader |= 1;
0117 
0118         if (!_register) {
0119             _register = new unsigned char[len];
0120             _len = len;
0121             memset(_register, 0, len);
0122         } else if (len > _len) {
0123             return -1;
0124         }
0125 
0126         if (!_next) {
0127             _next = new unsigned char[_len];
0128         }
0129         memcpy(_next, block, _len);
0130 
0131         rc = _cipher->decrypt(block, len);
0132 
0133         if (rc != -1) {
0134             // This might be optimizable
0135             char *tb = (char *)block;
0136             for (int i = 0; i < len; i++) {
0137                 tb[i] ^= ((char *)_register)[i];
0138             }
0139         }
0140 
0141         void *temp;
0142         temp = _next;
0143         _next = _register;
0144         _register = temp;
0145 
0146         return rc;
0147     }
0148     return -1;
0149 }
0150 
0151 int CipherBlockChain::decrypt(void *block, int len)
0152 {
0153     if (_useECBforReading) {
0154         qCDebug(KWALLETBACKEND_LOG) << "decrypting using ECB!";
0155         return decryptECB(block, len);
0156     }
0157 
0158     if (_cipher && !_writer) {
0159         int rc = 0;
0160 
0161         _reader |= 1;
0162 
0163         initRegister();
0164 
0165         if ((len % _len) >0) {
0166             qCDebug(KWALLETBACKEND_LOG) << "Block length given for decrypt (" << len << ") is not a multiple of " << _len;
0167             return -1;
0168         }
0169 
0170         char *elemBlock = static_cast<char*>(block);
0171         for (int b = 0; b < len/_len; b++) {
0172             if (_next == nullptr) {
0173                 _next = new unsigned char[_len];
0174             }
0175             memcpy(_next, elemBlock, _len);
0176 
0177             int bytesDecrypted = _cipher->decrypt(elemBlock, _len);
0178 
0179             if (bytesDecrypted != -1) {
0180                 rc += bytesDecrypted;
0181                 // This might be optimizable
0182                 char *tb = (char *)elemBlock;
0183                 for (int i = 0; i < _len; i++) {
0184                     *tb++ ^= ((char *)_register)[i];
0185                 }
0186             }
0187 
0188             void *temp;
0189             temp = _next;
0190             _next = _register;
0191             _register = temp;
0192 
0193             elemBlock += _len;
0194         }
0195 
0196         return rc;
0197     }
0198     return -1;
0199 }
0200