/***************************************************************************
* This file is part of the Lime Report project *
* Copyright (C) 2021 by Alexander Arin *
* arin_a@bk.ru *
* *
** GNU General Public License Usage **
* *
* This library is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
** GNU Lesser General Public License **
* *
* This library is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library. *
* If not, see . *
* *
* 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 General Public License for more details. *
****************************************************************************/
#include "lrsimplecrypt.h"
namespace LimeReport {
#if defined(LP64) || defined(_LP64) || defined(__LP64__)
typedef unsigned int WORD; /* Should be 32-bit = 4 bytes */
#else
typedef unsigned long int WORD; /* Should be 32-bit = 4 bytes */
#endif
const int w = 32; /* word size in bits */
const int r = 12; /* number of rounds */
const int b = 16; /* number of bytes in key */
const int c = 4; /* number words in key = ceil(8*b/w)*/
const int t = 26; /* size of table S = 2*(r+1) words */
const char* passPhrase = "HjccbzHjlbyfCkjy";
WORD P = 0xb7e15163, Q = 0x9e3779b9;
#define ROTL(x, y) (((x) << (y & (w - 1))) | ((x) >> (w - (y & (w - 1)))))
#define ROTR(x, y) (((x) >> (y & (w - 1))) | ((x) << (w - (y & (w - 1)))))
union WTB {
WORD word[2];
char bytes[8];
};
void initPt(WTB& pt, QByteArray::Iterator* it, QByteArray::Iterator end)
{
for (int i = 0; i < 8; i++) {
if (*it != end) {
pt.bytes[i] = **it;
++*it;
} else
break;
}
}
class ChipperPrivate {
friend class Chipper;
public:
ChipperPrivate(): m_prepared(false) { }
bool isPrepared() { return m_prepared; }
private:
void RC5_SETUP(const char* K);
void RC5_ENCRYPT(WORD* pt, WORD* ct);
void RC5_DECRYPT(WORD* ct, WORD* pt);
WORD S[26] = { 0 };
bool m_prepared;
};
void ChipperPrivate::RC5_SETUP(const char* K)
{
WORD i, j, k, u = w / 8, A, B, L[c];
for (i = b, L[c - 1] = 0; i != 0; i--)
L[(i - 1) / u] = (L[(i - 1) / u] << 8) + K[i - 1];
for (S[0] = P, i = 1; i < t; i++)
S[i] = S[i - 1] + Q;
for (A = B = i = j = k = 0; k < 3 * t; k++, i = (i + 1) % t, j = (j + 1) % c) { /* 3*t > 3*c */
A = S[i] = ROTL(S[i] + (A + B), 3);
B = L[j] = ROTL(L[j] + (A + B), (A + B));
}
m_prepared = true;
}
void ChipperPrivate::RC5_ENCRYPT(WORD* pt, WORD* ct)
{
WORD i, A = pt[0] + S[0], B = pt[1] + S[1];
for (i = 1; i <= r; i++) {
A = ROTL(A ^ B, B) + S[2 * i];
B = ROTL(B ^ A, A) + S[2 * i + 1];
}
ct[0] = A;
ct[1] = B;
}
void ChipperPrivate::RC5_DECRYPT(WORD* ct, WORD* pt)
{
WORD i, B = ct[1], A = ct[0];
for (i = r; i > 0; i--) {
B = ROTR(B - S[2 * i + 1], A) ^ A;
A = ROTR(A - S[2 * i], B) ^ B;
}
pt[1] = B - S[1];
pt[0] = A - S[0];
}
QByteArray Chipper::cryptString(QString value)
{
QByteArray buff;
QByteArray result;
buff += value.toUtf8();
WTB pt, ct, prior;
if (!d->isPrepared())
d->RC5_SETUP(passPhrase);
prior.word[0] = 0;
prior.word[1] = 0;
QByteArray::Iterator it = buff.begin();
while (it != buff.end()) {
pt.word[0] = 0;
pt.word[1] = 0;
initPt(pt, &it, buff.end());
pt.word[0] = pt.word[0] ^ prior.word[0];
pt.word[1] = pt.word[1] ^ prior.word[1];
d->RC5_ENCRYPT(pt.word, ct.word);
prior.word[0] = pt.word[0];
prior.word[1] = pt.word[1];
for (int i = 0; i < 8; i++) {
result += ct.bytes[i];
}
}
return result;
}
QString Chipper::decryptByteArray(QByteArray value)
{
QByteArray result;
WTB pt, ct, prior;
if (!d->isPrepared())
d->RC5_SETUP(passPhrase);
prior.word[0] = 0;
prior.word[1] = 0;
QByteArray::Iterator it = value.begin();
while (it != value.end()) {
pt.word[0] = 0;
pt.word[1] = 0;
initPt(pt, &it, value.end());
d->RC5_DECRYPT(pt.word, ct.word);
ct.word[0] = ct.word[0] ^ prior.word[0];
ct.word[1] = ct.word[1] ^ prior.word[1];
prior.word[0] = ct.word[0];
prior.word[1] = ct.word[1];
for (int i = 0; i < 8; i++) {
result += ct.bytes[i];
}
}
return QString(result);
}
Chipper::Chipper(): d(new ChipperPrivate()) { }
Chipper::Chipper(QString passphrase): d(new ChipperPrivate())
{
if (!passphrase.trimmed().isEmpty()) {
passphrase = passphrase.leftJustified(16, '#');
d->RC5_SETUP(passphrase.toLatin1().data());
}
}
Chipper::~Chipper() { delete d; }
} // namespace LimeReport