#pragma once #ifndef MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_CIPHERS_GCM_CIPHER_H_ #define MESSMER_BLOCKSTORE_IMPLEMENTATIONS_ENCRYPTED_CIPHERS_GCM_CIPHER_H_ #include #include #include #include #include "Cipher.h" namespace blockstore { namespace encrypted { template class GCM_Cipher { public: BOOST_CONCEPT_ASSERT((CipherConcept>)); using EncryptionKey = cpputils::FixedSizeData; static EncryptionKey CreateKey() { return cpputils::Random::OSRandom().getFixedSize(); } // Used in test cases for fast key creation static EncryptionKey CreatePseudoRandomKey() { return cpputils::Random::PseudoRandom().getFixedSize(); } static constexpr unsigned int ciphertextSize(unsigned int plaintextBlockSize) { return plaintextBlockSize + IV_SIZE + TAG_SIZE; } static constexpr unsigned int plaintextSize(unsigned int ciphertextBlockSize) { return ciphertextBlockSize - IV_SIZE - TAG_SIZE; } static cpputils::Data encrypt(const byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey); static boost::optional decrypt(const byte *ciphertext, unsigned int ciphertextSize, const EncryptionKey &encKey); private: static constexpr unsigned int IV_SIZE = BlockCipher::BLOCKSIZE; static constexpr unsigned int TAG_SIZE = 16; }; template cpputils::Data GCM_Cipher::encrypt(const byte *plaintext, unsigned int plaintextSize, const EncryptionKey &encKey) { cpputils::FixedSizeData iv = cpputils::Random::PseudoRandom().getFixedSize(); typename CryptoPP::GCM::Encryption encryption; encryption.SetKeyWithIV(encKey.data(), encKey.BINARY_LENGTH, iv.data(), IV_SIZE); cpputils::Data ciphertext(ciphertextSize(plaintextSize)); std::memcpy(ciphertext.data(), iv.data(), IV_SIZE); CryptoPP::ArraySource(plaintext, plaintextSize, true, new CryptoPP::AuthenticatedEncryptionFilter(encryption, new CryptoPP::ArraySink((byte*)ciphertext.data() + IV_SIZE, ciphertext.size() - IV_SIZE), false, TAG_SIZE ) ); return ciphertext; } template boost::optional GCM_Cipher::decrypt(const byte *ciphertext, unsigned int ciphertextSize, const EncryptionKey &encKey) { if (ciphertextSize < IV_SIZE + TAG_SIZE) { return boost::none; } const byte *ciphertextIV = ciphertext; const byte *ciphertextData = ciphertext + IV_SIZE; typename CryptoPP::GCM::Decryption decryption; decryption.SetKeyWithIV((byte*)encKey.data(), encKey.BINARY_LENGTH, ciphertextIV, IV_SIZE); cpputils::Data plaintext(plaintextSize(ciphertextSize)); try { CryptoPP::ArraySource((byte*)ciphertextData, ciphertextSize - IV_SIZE, true, new CryptoPP::AuthenticatedDecryptionFilter(decryption, new CryptoPP::ArraySink((byte*)plaintext.data(), plaintext.size()), CryptoPP::AuthenticatedDecryptionFilter::DEFAULT_FLAGS, TAG_SIZE ) ); return std::move(plaintext); } catch (const CryptoPP::HashVerificationFilter::HashVerificationFailed &e) { return boost::none; } } } } #endif