add Crypto/AuthenticatedEncryption to move code from model/User into own class, add app secret to server config

This commit is contained in:
Dario 2020-06-07 21:36:17 +02:00
parent 4a93b26e9a
commit ea18b3ca0a
4 changed files with 231 additions and 1 deletions

View File

@ -0,0 +1,137 @@
#include "AuthenticatedEncryption.h"
#include "sodium.h"
#include "../ServerConfig.h"
#include <assert.h>
AuthenticatedEncryption::AuthenticatedEncryption()
: mOpsLimit(10), mMemLimit(33554432), mAlgo(2), mEncryptionKey(nullptr), mEncryptionKeyHash(0)
{
}
AuthenticatedEncryption::AuthenticatedEncryption(unsigned long long opslimit, size_t memlimit, int algo)
: mOpsLimit(opslimit), mMemLimit(memlimit), mAlgo(algo), mEncryptionKey(nullptr), mEncryptionKeyHash(0)
{
}
AuthenticatedEncryption::~AuthenticatedEncryption()
{
if (mEncryptionKey) {
MemoryManager::getInstance()->releaseMemory(mEncryptionKey);
mEncryptionKey = nullptr;
}
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::createKey(const std::string& salt_parameter, const std::string& passwd)
{
assert(crypto_hash_sha512_BYTES >= crypto_pwhash_SALTBYTES);
auto mm = MemoryManager::getInstance();
auto app_secret = ServerConfig::g_CryptoAppSecret;
std::unique_lock<std::shared_mutex> _lock(mWorkingMutex);
// use hash512 because existing data where calculated with that, but could be also changed to hash256
auto hash512_salt = mm->getFreeMemory(crypto_hash_sha512_BYTES); // need at least crypto_pwhash_SALTBYTES 16U
crypto_hash_sha512_state state;
crypto_hash_sha512_init(&state);
//crypto_hash_sha512_update
crypto_hash_sha512_update(&state, (const unsigned char*)salt_parameter.data(), salt_parameter.size());
crypto_hash_sha512_update(&state, *app_secret, app_secret->size());
crypto_hash_sha512_final(&state, *hash512_salt);
//unsigned char* key = (unsigned char *)malloc(crypto_box_SEEDBYTES); // 32U
//ObfusArray* key = new ObfusArray(crypto_box_SEEDBYTES);
auto mEncryptionKey = mm->getFreeMemory(crypto_box_SEEDBYTES);
//Bin32Bytes* key = mm->get32Bytes();
// generate encryption key, should take a bit longer to make brute force attacks hard
if (crypto_pwhash(*mEncryptionKey, mEncryptionKey->size(), passwd.data(), passwd.size(), *hash512_salt, mOpsLimit, mMemLimit, mAlgo) != 0) {
mm->releaseMemory(mEncryptionKey);
mEncryptionKey = nullptr;
return AUTH_CREATE_ENCRYPTION_KEY_FAILED;
}
// generate hash from key for compare
assert(sizeof(KeyHashed) >= crypto_shorthash_BYTES);
crypto_shorthash((unsigned char*)&mEncryptionKeyHash, *mEncryptionKey, crypto_box_SEEDBYTES, *ServerConfig::g_ServerCryptoKey);
return AUTH_ENCRYPT_OK;
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::encrypt(const MemoryBin* message, MemoryBin** encryptedMessage)
{
assert(message && encryptedMessage);
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
if (!mEncryptionKey) {
return AUTH_NO_KEY;
}
size_t message_len = message->size();
size_t ciphertext_len = crypto_secretbox_MACBYTES + message_len;
unsigned char nonce[crypto_secretbox_NONCEBYTES];
// we use a hardcoded value for nonce
// TODO: use a dynamic value, save it along with the other parameters
memset(nonce, 31, crypto_secretbox_NONCEBYTES);
auto mm = MemoryManager::getInstance();
auto ciphertext = mm->getFreeMemory(ciphertext_len);
memset(*ciphertext, 0, ciphertext_len);
if (0 != crypto_secretbox_easy(*ciphertext, *message, message_len, nonce, *mEncryptionKey)) {
mm->releaseMemory(ciphertext);
return AUTH_ENCRYPT_MESSAGE_FAILED;
}
*encryptedMessage = ciphertext;
return AUTH_ENCRYPT_OK;
}
AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const MemoryBin* encryptedMessage, MemoryBin** message)
{
assert(message && encryptedMessage);
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
if (!mEncryptionKey) {
return AUTH_NO_KEY;
}
size_t decryptSize = encryptedMessage->size() - crypto_secretbox_MACBYTES;
//unsigned char* decryptBuffer = (unsigned char*)malloc(decryptSize);
auto mm = MemoryManager::getInstance();
//ObfusArray* decryptedData = new ObfusArray(decryptSize);
auto decryptedData = mm->getFreeMemory(decryptSize);
unsigned char nonce[crypto_secretbox_NONCEBYTES];
// we use a hardcoded value for nonce
// TODO: use a dynamic value, save it along with the other parameters
memset(nonce, 31, crypto_secretbox_NONCEBYTES);
if (crypto_secretbox_open_easy(*decryptedData, *encryptedMessage, encryptedMessage->size(), nonce, *mEncryptionKey)) {
mm->releaseMemory(decryptedData);
return AUTH_DECRYPT_MESSAGE_FAILED;
}
*message = decryptedData;
return AUTH_DECRYPT_OK;
}
const char* AuthenticatedEncryption::getErrorMessage(ResultType type)
{
switch (type) {
case AUTH_ENCRYPT_OK: return "everything is ok";
//case AUTH_ENCRYPT_SHA2_TO_SMALL: return "libsodium crypto_hash_sha512_BYTES is to small to use as crypto_pwhash_SALTBYTES";
case AUTH_CREATE_ENCRYPTION_KEY_FAILED: return "error creating encryption key, maybe to much memory requested?";
case AUTH_NO_KEY: return "no encryption key generated";
case AUTH_ENCRYPT_MESSAGE_FAILED: return "message encryption failed";
case AUTH_DECRYPT_MESSAGE_FAILED: return "message decryption failed";
}
return "<unknown>";
}

View File

@ -0,0 +1,78 @@
#ifndef __GRADIDO_LOGIN_SERVER_CRYPTO_AUTHENTICATED_ENCRYPTION_H
#define __GRADIDO_LOGIN_SERVER_CRYPTO_AUTHENTICATED_ENCRYPTION_H
#include "../SingletonManager/MemoryManager.h"
#include <shared_mutex>
/*!
*
* \author: Dario Rekowski
*
* \date: 07-06-2020
*
* \brief: Wrapper Class for make using libsodium authenticated encryption easy, used for encrypt private keys for user
*
*/
typedef Poco::UInt64 KeyHashed;
class AuthenticatedEncryption
{
public:
enum ResultType {
AUTH_ENCRYPT_OK,
AUTH_DECRYPT_OK,
AUTH_CREATE_ENCRYPTION_KEY_FAILED,
AUTH_NO_KEY,
AUTH_ENCRYPT_MESSAGE_FAILED,
AUTH_DECRYPT_MESSAGE_FAILED
};
//! \brief init with default algorithms parameter
AuthenticatedEncryption();
//! \brief init with custom algorithms parameter
//!
//! details see in libsodium crypto_pwhash
AuthenticatedEncryption(unsigned long long opslimit, size_t memlimit, int algo);
~AuthenticatedEncryption();
inline KeyHashed getKeyHashed() const { std::shared_lock<std::shared_mutex> _lock(mWorkingMutex); return mEncryptionKeyHash; }
inline bool operator == (const AuthenticatedEncryption& b) const {
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
return mEncryptionKeyHash == b.getKeyHashed();
}
inline bool hasKey() const { std::shared_lock<std::shared_mutex> _lock(mWorkingMutex); return !mEncryptionKey; }
//! \brief generate encryption key, with default parameter use ca. 300 ms
//!
//! should be call from task, running in g_CryptoCPUScheduler, lock shared mutex for writing
//! \param salt_parameter for example email
//! \return AUTH_CREATE_ENCRYPTION_KEY_FAILED call strerror(errno) for more details
ResultType createKey(const std::string& salt_parameter, const std::string& passwd);
ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage);
ResultType decrypt(const MemoryBin* encryptedMessage, MemoryBin** message);
const char* getErrorMessage(ResultType type);
protected:
// algorithms parameter
unsigned long long mOpsLimit;
size_t mMemLimit;
int mAlgo;
// encryption key and hash
MemoryBin* mEncryptionKey;
KeyHashed mEncryptionKeyHash;
mutable std::shared_mutex mWorkingMutex;
};
#endif //__GRADIDO_LOGIN_SERVER_CRYPTO_AUTHENTICATED_ENCRYPTION_H

View File

@ -3,6 +3,7 @@
#include "Crypto/mnemonic_german2.h"
#include "Crypto/mnemonic_bip0039.h"
#include "Crypto/DRRandom.h"
#include "lib/DataTypeConverter.h"
#include "sodium.h"
@ -51,6 +52,7 @@ namespace ServerConfig {
bool g_disableEmail = false;
ServerSetupType g_ServerSetupType = SERVER_TYPE_PRODUCTION;
std::string g_gRPCRelayServerFullURL;
MemoryBin* g_CryptoAppSecret = nullptr;
#ifdef __linux__
#include <stdio.h>
@ -217,6 +219,14 @@ namespace ServerConfig {
auto serverSetupTypeString = cfg.getString("ServerSetupType", "");
g_ServerSetupType = getServerSetupTypeFromString(serverSetupTypeString);
// app secret for encrypt user private keys
// TODO: encrypt with server admin key
auto app_secret_string = cfg.getString("crypto.app_secret", "");
if ("" != app_secret_string) {
g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string);
}
//g_CryptoAppSecret
g_gRPCRelayServerFullURL = cfg.getString("grpc.server", "");
return true;
@ -283,6 +293,10 @@ namespace ServerConfig {
if (g_CryptoCPUScheduler) {
delete g_CryptoCPUScheduler;
}
if (g_CryptoAppSecret) {
MemoryManager::getInstance()->releaseMemory(g_CryptoAppSecret);
g_CryptoAppSecret = nullptr;
}
}
void writeToFile(std::istream& datas, std::string fileName)

View File

@ -10,7 +10,7 @@
#include "tasks/CPUSheduler.h"
#include "SingletonManager/LanguageManager.h"
#include "SingletonManager/MemoryManager.h"
#define DISABLE_EMAIL
@ -60,6 +60,7 @@ namespace ServerConfig {
extern bool g_disableEmail;
extern ServerSetupType g_ServerSetupType;
extern std::string g_gRPCRelayServerFullURL;
extern MemoryBin* g_CryptoAppSecret;
bool loadMnemonicWordLists();
bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg);