10Duke Enterprise C++ SDK
Loading...
Searching...
No Matches
AbstractCiphers.h
1#ifndef TENDUKE_CRYPTO_ABSTRACTCIPHERS_H
2#define TENDUKE_CRYPTO_ABSTRACTCIPHERS_H
3
4#include "./Ciphers.h"
5#include "./CryptoException.h"
6#include "./kdf/PBKDF2.h"
7#include "./symmetric/aes/AESGCMCipher.h"
8#include "../utl/BinaryView.h"
9#include "../utl/DataSink.h"
10#include "../utl/SimpleBuffer.h"
11#include "../utl/StringSink.h"
12#include "../utl/random/RandomBytes.h"
13#include <cstddef>
14#include <cstdint>
15#include <memory>
16#include <string>
17
18namespace tenduke { namespace crypto {
19
28class AbstractCiphers : public virtual Ciphers
29{
30public:
31 AbstractCiphers(
32 const std::shared_ptr<::tenduke::utl::random::RandomBytes> &random,
33 const std::shared_ptr<::tenduke::crypto::PBKDF2> &keyGenerator
34 )
35 : random_(random)
36 , keyGenerator_(keyGenerator)
37 {}
38
39 std::unique_ptr<::tenduke::utl::BinaryData> decrypt(
40 const ::tenduke::utl::DataSpan &ciphertext,
41 const ::tenduke::utl::DataSpan &encryptionKey
42 ) const override
43 {
44 return decryptBytes(
45 ciphertext.data(),
46 ciphertext.size_bytes(),
47 encryptionKey.data(),
48 encryptionKey.size_bytes()
49 );
50 }
51
52 std::string decryptString(
53 const ::tenduke::utl::DataSpan &ciphertext,
54 const ::tenduke::utl::DataSpan &encryptionKey
55 ) const override
56 {
57 auto plaintext = decrypt(ciphertext, encryptionKey);
58 return std::string(reinterpret_cast<char *>(plaintext->getData()), plaintext->getLength());
59 }
60
61 std::unique_ptr<::tenduke::utl::BinaryData> encrypt(
62 const ::tenduke::utl::DataSpan &plaintext,
63 const ::tenduke::utl::DataSpan &encryptionKey
64 ) const override
65 {
66 return encryptBytes(
67 plaintext.data(),
68 plaintext.size_bytes(),
69 encryptionKey.data(),
70 encryptionKey.size_bytes()
71 );
72 }
73
74 std::unique_ptr<::tenduke::utl::BinaryData> encrypt(
75 const std::string &plaintext,
76 const ::tenduke::utl::DataSpan &encryptionKey
77 ) const override
78 {
79 return encrypt(
81 encryptionKey
82 );
83 }
84
85 std::string decryptString(
86 const ::tenduke::crypto::Cipher &cipher,
87 const ::tenduke::utl::DataSpan &ciphertext
88 ) const override
89 {
90 const auto version = readAndValidateHeader(ciphertext);
91 if (version != VERSION_2) {
92 throw ::tenduke::crypto::CryptoException(
93 "invalid_blob_version",
94 "The provided blob is not compatible with this method."
95 );
96 }
97
98 std::string result;
99 ::tenduke::utl::StringSink sink(result);
100 cipher.decryptData(
102 sink
103 );
104
105 return result;
106 }
107
109 const ::tenduke::crypto::Cipher &cipher,
110 const ::tenduke::utl::DataSpan &plaintext,
111 ::tenduke::utl::DataSink &ciphertext
112 ) const override
113 {
114 writeHeader(ciphertext, VERSION_2);
115 cipher.encryptData(plaintext, ciphertext);
116 }
117
118
119protected:
121 static constexpr std::uint32_t BLOB_MAGIC = 0x44554B45; // "DUKE" in network byte order (big-endian)
122
124 static constexpr std::size_t BLOB_HEADER_SIZE = 6;
125
126 // Version #1 is fully automated: The key is automatically generated, the salt used in the key generation is used
127 // as IV of the encryption. AES GCM 256 is used to encrypt the data.
128 static constexpr std::uint16_t VERSION_1 = 0x0001;
129
130 // Version #2 uses user-provided cipher. The caller must take care of password generation and salt storage.
131 // Version #2 is used with dedicated methods (the methods taking the cipher as a parameter).
132 static constexpr std::uint16_t VERSION_2 = 0x0002;
133
135 static constexpr int PBKDF2_ITERATIONS = 100000;
136
137 virtual std::unique_ptr<::tenduke::utl::BinaryData> encryptBytes(
138 const unsigned char *plaintext,
139 std::size_t plaintextLength,
140 const unsigned char *encryptionKey,
141 std::size_t encryptionKeyLength
142 ) const
143 {
144 std::uint8_t saltBytes[::tenduke::crypto::aes::GCM_NONCE_SIZE];
145 random_->generate(saltBytes, sizeof(saltBytes));
146 const auto salt = ::tenduke::utl::make_view(saltBytes);
147
148 const auto key = keyGenerator_->deriveAES256Key(
149 ::tenduke::utl::make_view(encryptionKey, encryptionKeyLength),
150 salt,
152 );
153
154 std::unique_ptr<::tenduke::utl::SimpleBuffer> ciphertext(new ::tenduke::utl::SimpleBuffer());
155 writeHeader(*ciphertext, VERSION_1);
156
157 key->gcmCipher()->encryptData(
158 salt,
159 ::tenduke::utl::make_view(plaintext, plaintextLength),
160 *ciphertext
161 );
162
163 return ciphertext;
164 }
165
166 virtual std::unique_ptr<::tenduke::utl::BinaryData> decryptBytes(
167 const unsigned char *ciphertext,
168 std::size_t ciphertextLength,
169 const unsigned char *encryptionKey,
170 std::size_t encryptionKeyLength
171 ) const
172 {
173 const std::uint16_t version = readAndValidateHeader(ciphertext, ciphertextLength);
174 if (version != VERSION_1) {
175 throw ::tenduke::crypto::CryptoException(
176 "cipher_unsupported_version",
177 "Unsupported blob version"
178 );
179 }
180
181 if (ciphertextLength < BLOB_HEADER_SIZE + ::tenduke::crypto::aes::GCM_NONCE_SIZE + ::tenduke::crypto::aes::GCM_MAC_SIZE) {
182 throw ::tenduke::crypto::CryptoException(
183 "cipher_invalid_ciphertext",
184 "Ciphertext too short to contain header, nonce and authentication tag"
185 );
186 }
187
188 const auto key = keyGenerator_->deriveAES256Key(
189 ::tenduke::utl::make_view(encryptionKey, encryptionKeyLength),
190 ::tenduke::utl::make_view(ciphertext + BLOB_HEADER_SIZE, ::tenduke::crypto::aes::GCM_NONCE_SIZE),
192 );
193
194 std::unique_ptr<::tenduke::utl::SimpleBuffer> plaintext(new ::tenduke::utl::SimpleBuffer());
195 key->gcmCipher()->decryptData(
196 ::tenduke::utl::make_view(ciphertext + BLOB_HEADER_SIZE, ciphertextLength - BLOB_HEADER_SIZE),
197 *plaintext
198 );
199
200 return plaintext;
201 }
202
203 virtual void writeHeader(unsigned char *buffer, const std::uint16_t version) const
204 {
205 buffer[0] = static_cast<unsigned char>((BLOB_MAGIC >> 24) & 0xFF);
206 buffer[1] = static_cast<unsigned char>((BLOB_MAGIC >> 16) & 0xFF);
207 buffer[2] = static_cast<unsigned char>((BLOB_MAGIC >> 8) & 0xFF);
208 buffer[3] = static_cast<unsigned char>(BLOB_MAGIC & 0xFF);
209 buffer[4] = static_cast<unsigned char>((version >> 8) & 0xFF);
210 buffer[5] = static_cast<unsigned char>(version & 0xFF);
211 }
212
213 virtual void writeHeader(::tenduke::utl::DataSink &output, const std::uint16_t version) const
214 {
215 output.append(static_cast<std::uint8_t>((BLOB_MAGIC >> 24) & 0xFF));
216 output.append(static_cast<std::uint8_t>((BLOB_MAGIC >> 16) & 0xFF));
217 output.append(static_cast<std::uint8_t>((BLOB_MAGIC >> 8) & 0xFF));
218 output.append(static_cast<std::uint8_t>(BLOB_MAGIC & 0xFF));
219 output.append(static_cast<std::uint8_t>((version >> 8) & 0xFF));
220 output.append(static_cast<std::uint8_t>(version & 0xFF));
221 }
222
223 virtual std::uint16_t readAndValidateHeader(
224 const unsigned char *buffer,
225 std::size_t bufferLength
226 ) const
227 {
228 if (bufferLength < BLOB_HEADER_SIZE) {
229 throw ::tenduke::crypto::CryptoException(
230 "cipher_invalid_ciphertext",
231 "Ciphertext too short to contain header"
232 );
233 }
234
235 const std::uint32_t magic =
236 (static_cast<std::uint32_t>(buffer[0]) << 24) |
237 (static_cast<std::uint32_t>(buffer[1]) << 16) |
238 (static_cast<std::uint32_t>(buffer[2]) << 8) |
239 static_cast<std::uint32_t>(buffer[3]);
240
241 if (magic != BLOB_MAGIC) {
242 throw ::tenduke::crypto::CryptoException(
243 "cipher_invalid_ciphertext",
244 "Invalid blob magic value"
245 );
246 }
247
248 return (static_cast<std::uint16_t>(buffer[4]) << 8) |
249 static_cast<std::uint16_t>(buffer[5]);
250 }
251
252 virtual std::uint16_t readAndValidateHeader(const ::tenduke::utl::DataSpan &buffer) const
253 {
254 return readAndValidateHeader(buffer.data(), buffer.size_bytes());
255 }
256
257private:
258 const std::shared_ptr<::tenduke::utl::random::RandomBytes> random_;
259 const std::shared_ptr<::tenduke::crypto::PBKDF2> keyGenerator_;
260};
261
262}}
263
264#endif //TENDUKE_CRYPTO_ABSTRACTCIPHERS_H
static constexpr std::uint32_t BLOB_MAGIC
Magic value for encrypted blob header.
Definition AbstractCiphers.h:121
std::string decryptString(const ::tenduke::utl::DataSpan &ciphertext, const ::tenduke::utl::DataSpan &encryptionKey) const override
Decrypts given data using the system default cipher (AES256 GCM) to a string.
Definition AbstractCiphers.h:52
std::unique_ptr<::tenduke::utl::BinaryData > encrypt(const std::string &plaintext, const ::tenduke::utl::DataSpan &encryptionKey) const override
Encrypts given data using the system default cipher (AES256 GCM).
Definition AbstractCiphers.h:74
static constexpr int PBKDF2_ITERATIONS
Number of PBKDF2 iterations for VERSION_1 key derivation.
Definition AbstractCiphers.h:135
std::string decryptString(const ::tenduke::crypto::Cipher &cipher, const ::tenduke::utl::DataSpan &ciphertext) const override
Decrypts given data using the given cipher to a string.
Definition AbstractCiphers.h:85
std::unique_ptr<::tenduke::utl::BinaryData > decrypt(const ::tenduke::utl::DataSpan &ciphertext, const ::tenduke::utl::DataSpan &encryptionKey) const override
Decrypts given data using the system default cipher (AES256 GCM).
Definition AbstractCiphers.h:39
std::unique_ptr<::tenduke::utl::BinaryData > encrypt(const ::tenduke::utl::DataSpan &plaintext, const ::tenduke::utl::DataSpan &encryptionKey) const override
Encrypts given data using the system default cipher (AES256 GCM).
Definition AbstractCiphers.h:61
void encrypt(const ::tenduke::crypto::Cipher &cipher, const ::tenduke::utl::DataSpan &plaintext, ::tenduke::utl::DataSink &ciphertext) const override
Encrypts data with the given cipher.
Definition AbstractCiphers.h:108
static constexpr std::size_t BLOB_HEADER_SIZE
Header size: magic (4 bytes) + version (2 bytes).
Definition AbstractCiphers.h:124
A "service locator" for cipher-related operations.
Definition Ciphers.h:20
A sink to which binary data can be appended.
Definition DataSink.h:14
virtual void append(const std::uint8_t *data, std::size_t size)=0
Appends binary data to the sink.
A tenduke::utl::DataSink, which appends binary data to a std::string.
Definition StringSink.h:16
Cryptography services.
Definition AbstractCiphers.h:18
BinaryView make_view(const unsigned char *data, const std::size_t size)
A helper function to create a tenduke::utl::BinaryView from a const pointer.
Definition BinaryView.h:93
Root for classes, functions and globals of 10Duke C++ Client.
Definition APIRequest.h:4