mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
refactor: Move SimpleCrypt to third_party/
This commit is contained in:
268
third_party/simplecrypt/simplecrypt.cpp
vendored
Normal file
268
third_party/simplecrypt/simplecrypt.cpp
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (c) 2011, Andre Somers
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the Rathenau Instituut, Andre Somers nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
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 ANDRE SOMERS 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 #######; 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 "simplecrypt.h"
|
||||
#include <QByteArray>
|
||||
#include <QtDebug>
|
||||
#include <QtGlobal>
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QRandomGenerator>
|
||||
#include <QDataStream>
|
||||
#include <limits>
|
||||
|
||||
SimpleCrypt::SimpleCrypt() : m_key(0),
|
||||
m_compressionMode(CompressionAuto),
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{}
|
||||
|
||||
SimpleCrypt::SimpleCrypt(quint64 key) : m_key(key),
|
||||
m_compressionMode(CompressionAuto),
|
||||
m_protectionMode(ProtectionChecksum),
|
||||
m_lastError(ErrorNoError)
|
||||
{
|
||||
splitKey();
|
||||
}
|
||||
|
||||
void SimpleCrypt::setKey(quint64 key)
|
||||
{
|
||||
m_key = key;
|
||||
splitKey();
|
||||
}
|
||||
|
||||
void SimpleCrypt::splitKey()
|
||||
{
|
||||
m_keyParts.clear();
|
||||
m_keyParts.resize(8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
quint64 part = m_key;
|
||||
for (int j = i; j > 0; j--)
|
||||
part = part >> 8;
|
||||
part = part & 0xff;
|
||||
m_keyParts[i] = static_cast<char>(part);
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray SimpleCrypt::encryptToByteArray(const QString &plaintext)
|
||||
{
|
||||
QByteArray plaintextArray = plaintext.toUtf8();
|
||||
return encryptToByteArray(plaintextArray);
|
||||
}
|
||||
|
||||
QByteArray SimpleCrypt::encryptToByteArray(const QByteArray &plaintext)
|
||||
{
|
||||
if (m_keyParts.isEmpty())
|
||||
{
|
||||
qWarning() << "No key set.";
|
||||
m_lastError = ErrorNoKeySet;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ba = plaintext;
|
||||
|
||||
CryptoFlags flags = CryptoFlagNone;
|
||||
if (m_compressionMode == CompressionAlways)
|
||||
{
|
||||
ba = qCompress(ba, 9); // maximum compression
|
||||
flags |= CryptoFlagCompression;
|
||||
}
|
||||
else if (m_compressionMode == CompressionAuto)
|
||||
{
|
||||
QByteArray compressed = qCompress(ba, 9);
|
||||
if (compressed.count() < ba.count())
|
||||
{
|
||||
ba = compressed;
|
||||
flags |= CryptoFlagCompression;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray integrityProtection;
|
||||
if (m_protectionMode == ProtectionChecksum)
|
||||
{
|
||||
flags |= CryptoFlagChecksum;
|
||||
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
|
||||
s << qChecksum(ba.constData(), ba.length());
|
||||
}
|
||||
else if (m_protectionMode == ProtectionHash)
|
||||
{
|
||||
flags |= CryptoFlagHash;
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(ba);
|
||||
|
||||
integrityProtection += hash.result();
|
||||
}
|
||||
|
||||
// prepend a random char to the string
|
||||
thread_local QRandomGenerator rng(QRandomGenerator::global()->generate());
|
||||
char randomChar = static_cast<char>(rng.bounded(static_cast<int>(std::numeric_limits<char>::min()), static_cast<int>(std::numeric_limits<char>::max()) + 1));
|
||||
ba = randomChar + integrityProtection + ba;
|
||||
|
||||
int pos(0);
|
||||
char lastChar(0);
|
||||
|
||||
int cnt = ba.count();
|
||||
|
||||
while (pos < cnt)
|
||||
{
|
||||
ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar;
|
||||
lastChar = ba.at(pos);
|
||||
++pos;
|
||||
}
|
||||
|
||||
QByteArray resultArray;
|
||||
resultArray.append(char(0x03)); // version for future updates to algorithm
|
||||
resultArray.append(char(flags)); // encryption flags
|
||||
resultArray.append(ba);
|
||||
|
||||
m_lastError = ErrorNoError;
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
QString SimpleCrypt::encryptToString(const QString &plaintext)
|
||||
{
|
||||
QByteArray plaintextArray = plaintext.toUtf8();
|
||||
QByteArray cypher = encryptToByteArray(plaintextArray);
|
||||
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||
return cypherString;
|
||||
}
|
||||
|
||||
QString SimpleCrypt::encryptToString(const QByteArray &plaintext)
|
||||
{
|
||||
QByteArray cypher = encryptToByteArray(plaintext);
|
||||
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||
return cypherString;
|
||||
}
|
||||
|
||||
QString SimpleCrypt::decryptToString(const QString &cyphertext)
|
||||
{
|
||||
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||
QByteArray plaintextArray = decryptToByteArray(cyphertextArray);
|
||||
QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size());
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
QString SimpleCrypt::decryptToString(const QByteArray &cypher)
|
||||
{
|
||||
QByteArray ba = decryptToByteArray(cypher);
|
||||
QString plaintext = QString::fromUtf8(ba, ba.size());
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
QByteArray SimpleCrypt::decryptToByteArray(const QString &cyphertext)
|
||||
{
|
||||
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||
QByteArray ba = decryptToByteArray(cyphertextArray);
|
||||
|
||||
return ba;
|
||||
}
|
||||
|
||||
QByteArray SimpleCrypt::decryptToByteArray(const QByteArray &cypher)
|
||||
{
|
||||
if (m_keyParts.isEmpty())
|
||||
{
|
||||
qWarning() << "No key set.";
|
||||
m_lastError = ErrorNoKeySet;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ba = cypher;
|
||||
|
||||
if (cypher.count() < 3)
|
||||
return QByteArray();
|
||||
|
||||
char version = ba.at(0);
|
||||
|
||||
if (version != 3) // we only work with version 3
|
||||
{
|
||||
m_lastError = ErrorUnknownVersion;
|
||||
qWarning() << "Invalid version or not a cyphertext.";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
CryptoFlags flags = CryptoFlags(ba.at(1));
|
||||
|
||||
ba = ba.mid(2);
|
||||
int pos(0);
|
||||
int cnt(ba.count());
|
||||
char lastChar = 0;
|
||||
|
||||
while (pos < cnt)
|
||||
{
|
||||
char currentChar = ba[pos];
|
||||
ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8);
|
||||
lastChar = currentChar;
|
||||
++pos;
|
||||
}
|
||||
|
||||
ba = ba.mid(1); // chop off the random number at the start
|
||||
|
||||
bool integrityOk(true);
|
||||
if (flags.testFlag(CryptoFlagChecksum))
|
||||
{
|
||||
if (ba.length() < 2)
|
||||
{
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
quint16 storedChecksum;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> storedChecksum;
|
||||
}
|
||||
ba = ba.mid(2);
|
||||
quint16 checksum = qChecksum(ba.constData(), ba.length());
|
||||
integrityOk = (checksum == storedChecksum);
|
||||
}
|
||||
else if (flags.testFlag(CryptoFlagHash))
|
||||
{
|
||||
if (ba.length() < 20)
|
||||
{
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray storedHash = ba.left(20);
|
||||
ba = ba.mid(20);
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(ba);
|
||||
integrityOk = (hash.result() == storedHash);
|
||||
}
|
||||
|
||||
if (!integrityOk)
|
||||
{
|
||||
m_lastError = ErrorIntegrityFailed;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
if (flags.testFlag(CryptoFlagCompression))
|
||||
ba = qUncompress(ba);
|
||||
|
||||
m_lastError = ErrorNoError;
|
||||
return ba;
|
||||
}
|
||||
Reference in New Issue
Block a user