From 479b939b54c0c72c95c5ad16bef9ee151479c457 Mon Sep 17 00:00:00 2001 From: KingToolbox Date: Tue, 28 Jul 2020 02:05:46 +0800 Subject: [PATCH] Add a safe encryption class. --- src/Cryptographic.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++ src/Cryptographic.h | 39 +++++++++++++++++++ src/README.md | 4 ++ 3 files changed, 134 insertions(+) create mode 100644 src/Cryptographic.cpp create mode 100644 src/Cryptographic.h diff --git a/src/Cryptographic.cpp b/src/Cryptographic.cpp new file mode 100644 index 0000000..92268e3 --- /dev/null +++ b/src/Cryptographic.cpp @@ -0,0 +1,91 @@ + /* + * Copyright 2020, WindTerm. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Cryptographic.h" + +#include +#include +#include + +#include "openssl/evp.h" + +constexpr int AES_256_IV_LENGTH = 16; +constexpr int AES_256_KEY_LENGTH = 32; +constexpr int PBKDF2_LENGTH = AES_256_IV_LENGTH + AES_256_KEY_LENGTH; +constexpr int PBKDF2_ITERATION_COUNT = 100000; + +QByteArray Cryptographic::decrypt(const QByteArray &data, const QByteArray &pbkdf2) { + return doCrypt(QByteArray::fromBase64(data), Cryptographic::key(pbkdf2), Cryptographic::iv(pbkdf2), 0); +} + +QByteArray Cryptographic::doCrypt(QByteArray data, const QByteArray &key, const QByteArray &iv, int enc) { + QByteArray crypted(data.length() + EVP_MAX_BLOCK_LENGTH, '\0'); + int cryptedLength = 0; + int length; + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + EVP_CipherInit_ex( + ctx, + EVP_aes_256_cbc(), + nullptr, + reinterpret_cast(key.constData()), + reinterpret_cast(iv.constData()), + enc + ); + + EVP_CipherUpdate( + ctx, + reinterpret_cast(crypted.data()), + &length, + reinterpret_cast(data.constData()), + data.length() + ); + cryptedLength += length; + + EVP_CipherFinal_ex(ctx, reinterpret_cast(crypted.data() + cryptedLength), &length); + cryptedLength += length; + + EVP_CIPHER_CTX_free(ctx); + + crypted.resize(cryptedLength); + return crypted; +} + +QByteArray Cryptographic::encrypt(const QByteArray &data, const QByteArray &pbkdf2) { + QByteArray encrypted = doCrypt(data, Cryptographic::key(pbkdf2), Cryptographic::iv(pbkdf2), 1); + return encrypted.toBase64(); +} + +QByteArray Cryptographic::iv(const QByteArray &pbkdf2) { + Q_ASSERT(pbkdf2.length() == PBKDF2_LENGTH); + return QByteArray::fromRawData(pbkdf2.constData() + AES_256_KEY_LENGTH, AES_256_IV_LENGTH); +} + +QByteArray Cryptographic::key(const QByteArray &pbkdf2) { + Q_ASSERT(pbkdf2.length() == PBKDF2_LENGTH); + return QByteArray::fromRawData(pbkdf2.constData(), AES_256_KEY_LENGTH); +} + +QByteArray Cryptographic::pbkdf2(const QByteArray &password, const QByteArray &salt) { + return QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha3_512, password, salt, PBKDF2_ITERATION_COUNT, PBKDF2_LENGTH); +} + +QByteArray Cryptographic::salt() { + QByteArray number = QByteArray::number(QRandomGenerator::system()->generate64()); + QByteArray numberHash = QCryptographicHash::hash(number, QCryptographicHash::Sha512); + return numberHash.toBase64(); +} diff --git a/src/Cryptographic.h b/src/Cryptographic.h new file mode 100644 index 0000000..8a70fea --- /dev/null +++ b/src/Cryptographic.h @@ -0,0 +1,39 @@ + /* + * Copyright 2020, WindTerm. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CRYPTOGRAPHIC_H +#define CRYPTOGRAPHIC_H + +#pragma once + +class QByteArray; + +class Cryptographic { +public: + Cryptographic() = default; + + static QByteArray decrypt(const QByteArray &data, const QByteArray &pbkdf2); + static QByteArray encrypt(const QByteArray &data, const QByteArray &pbkdf2); + static QByteArray pbkdf2(const QByteArray &password, const QByteArray &salt); + static QByteArray salt(); + +private: + static QByteArray doCrypt(QByteArray data, const QByteArray &key, const QByteArray &iv, int enc); + static QByteArray iv(const QByteArray &pbkdf2); + static QByteArray key(const QByteArray &pbkdf2); +}; + +#endif // CRYPTOGRAPHIC_H \ No newline at end of file diff --git a/src/README.md b/src/README.md index 7b38162..9cba008 100644 --- a/src/README.md +++ b/src/README.md @@ -8,6 +8,10 @@ Below is a list of (some) WindTerm components in alphabetical order, along with A quick circular buffer template class. +## Cryptographic.h/cpp + +A very safe encryption class using the PBKDF2-algorithm as defined in RFC 8018. WindTerm uses this class together with the user's master password to protect user data, including passwords, private keys and so on. + ## Onigmo An improved version based on Onigmo 5.13.5. In particular, **the addition of iterator makes it possible to match gap buffer or nonadjacent memory blocks.** Please refer to the sample files for how to use.