dodo  0.0.1
A C++ library to create containerized Linux services
datacrypt.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of the dodo library (https://github.com/jmspit/dodo).
3  * Copyright (c) 2019 Jan-Marten Spit.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /**
19  * @file datacrypt.hpp
20  * Defines the dodo::common::DataCrypt class.
21  */
22 
23 #ifndef common_datacrypt_hpp
24 #define common_datacrypt_hpp
25 
26 #include <string>
27 #include <common/exception.hpp>
28 #include <common/bytes.hpp>
29 #include <openssl/err.h>
30 
31 namespace dodo::common {
32 
33  /**
34  * Interface to encrypt and decrypt Bytes data to/from a secure string. Intended for smaller secrets such as
35  * passwords, works for larger data volumes but with a time penalty, encryption/decryption of 10MiB on a
36  * 3.4GHz Corei7 takes 0.8s/0.7s. Ideal for deployment configuration data.
37  *
38  * The format of the encrypted string is
39  * @code
40  * ENC[cipher:{cipher},data:{encrypted data},iv:{initialization vector},tag:{tag}]
41  * @endcode
42  *
43  * for example
44  *
45  * @code
46  * ENC[cipher:EVP_aes_256_gcm,data:dOxteDqw7POETW6RnDwWGVOUHkGf5OE7S1UY157ZEDx0Fv5vc9c=,iv:/GXteCh6FEt2IZbmgBurjA==,tag:WgKBIu/JgCZivZRTtb5A9Q==]
47  * @endcode
48  *
49  * As the only external data required to decrypt is the key, and the other information required to decrypt included
50  * in the encrypted string, it is robust against change and not coupled to specific programs or programming languages.
51  * In fact, if the encryption uses DataCrypt::Cipher::Default, a simple decrypt/encrypt cycle will move to newer
52  * ciphers without changing any code.
53  *
54  * The IV and tag are not secrets. The iv needs to be random to prevent entropy loss with access to multiple
55  * encrypted strings generated with the same key. The encrypt function will take care of generating unique IV's for
56  * each call to encrypt. The tag is used to verify the decryption success, and is generated internally upon
57  * encrypt.
58  *
59  * The available DataCrypt::Cipher choices are
60  * | cipher | key size in bytes (octets) |
61  * |--------|----------------------------|
62  * |EVP_aes_128_gcm|16|
63  * |EVP_aes_192_gcm|24|
64  * |EVP_aes_256_gcm|32|
65  *
66  * If the provided key size is smaller, it is padded by repeating the specified key until filled. Use EVP_aes_256_gcm
67  * with a strong 32 byte key for maximum safety.
68  *
69  * Only the data size in the encrypted string will depend on the size of the original data. The encrypted string
70  * data will be around 1.4 times larger for an original data size of 38 bytes, and about 1.3 times for an original
71  * data size of 240 bytes.
72  *
73  */
74  class DataCrypt {
75  public:
76 
77  /**
78  * Cipher selection. GCM is the more secure block cipher, smaller key sizes ought to be faster
79  * at the expense of work required to crack.
80  */
81  enum class Cipher {
82  EVP_aes_128_gcm, /**< https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_128_gcm.html */
83  EVP_aes_192_gcm, /**< https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_192_gcm.html */
84  EVP_aes_256_gcm, /**< https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_256_gcm.html */
85  Default = EVP_aes_256_gcm,
86  Invalid
87  };
88 
89  /**
90  * Return the size of the key for the given Cipher in bits
91  * @param cipher The Cipher to get the key bit size for.
92  * @return the key size in bits;
93  */
94  static int keyOctets( Cipher cipher ) {
95  switch ( cipher ) {
96  case Cipher::EVP_aes_128_gcm : return 16;
97  case Cipher::EVP_aes_192_gcm : return 24;
98  case Cipher::EVP_aes_256_gcm : return 32;
99  case Cipher::Invalid : return 0;
100  }
101  return 0;
102  }
103 
104  /**
105  * Return the size of the IV (initialization vector) for the given Cipher in bits
106  * @param cipher The Cipher to get the iv bit size for.
107  * @return the iv size in bits;
108  */
109  static int ivOctets( Cipher cipher ) {
110  switch ( cipher ) {
111  case Cipher::EVP_aes_128_gcm : return 16;
112  case Cipher::EVP_aes_192_gcm : return 16;
113  case Cipher::EVP_aes_256_gcm : return 16;
114  case Cipher::Invalid : return 0;
115  }
116  return 0;
117  }
118 
119  /**
120  * Return the block size of the Cipher in octets.
121  * @param cipher The Cipher
122  * @return The size of the block in octets.
123  */
124  static int blockOctets( Cipher cipher ) {
125  switch ( cipher ) {
126  case Cipher::EVP_aes_128_gcm : return 16;
127  case Cipher::EVP_aes_192_gcm : return 16;
128  case Cipher::EVP_aes_256_gcm : return 16;
129  case Cipher::Invalid : return 0;
130  }
131  return 0;
132  }
133 
134  /**
135  * Return the tag length of the Cipher in octets.
136  * @param cipher The Cipher
137  * @return The length of the tag in octets.
138  */
139  static int tagLength( Cipher cipher ) {
140  switch ( cipher ) {
141  case Cipher::EVP_aes_128_gcm : return 16;
142  case Cipher::EVP_aes_192_gcm : return 16;
143  case Cipher::EVP_aes_256_gcm : return 16;
144  case Cipher::Invalid : return 0;
145  }
146  return 0;
147  }
148 
149  /**
150  * String representation of an Cipher instance.
151  * @param cipher The Cipher to get the iv bit size for.
152  * @return The string representation.
153  */
154  static std::string cipher2String( const Cipher& cipher ) {
155  switch ( cipher ) {
156  case Cipher::EVP_aes_128_gcm : return "EVP_aes_128_gcm";
157  case Cipher::EVP_aes_192_gcm : return "EVP_aes_192_gcm";
158  case Cipher::EVP_aes_256_gcm : return "EVP_aes_256_gcm";
159  case Cipher::Invalid : return "Invalid cipher";
160  }
161  return "Invalid cipher";
162  }
163 
164  /**
165  * Convert a string representation to an Cipher.
166  * @param s The string representation of an Cipher.
167  * @return The Cipher.
168  */
169  static Cipher string2Cipher( const std::string &s ) {
173  else return Cipher::Invalid;
174  }
175 
176  /**
177  * Encrypt data with a key into a string (so the encrypted data will not contain a 0/zero).
178  *
179  * @param cipher The cipher to use
180  * @param key The key to encrypt with.
181  * @param src The source data to encrypt.
182  * @param dst The encrypted string
183  */
184  static void encrypt( Cipher cipher,
185  const std::string &key,
186  const Bytes& src,
187  std::string &dst );
188 
189  /**
190  * Decrypt data with a key.
191  * @param key The key to decrypt with.
192  * @param src The source data to decrypt.
193  * @param dest The Bytes that will receive the decrypted data. The caller will become owner of the
194  * pointer in Bytes and responsible for cleaning it up with free().
195  * @return 0 if decryption ok, 1 if failure due to the format not being recognized, 2 if key was incorrect
196  * or the data corrupted.
197  */
198  static int decrypt( const std::string &key,
199  const std::string src,
200  Bytes &dest );
201 
202  private:
203  /**
204  * Calculate the size of the encrypted data from the input size.
205  * @param cipher The Cipher to calculate for.
206  * @param octets The number of octets in the data to encrypt.
207  * @return The size of the encrypted data.
208  */
209  static size_t cipherOctets( Cipher cipher, size_t octets ) {
210  return octets + blockOctets( cipher ) - ( octets % blockOctets( cipher ) );
211  }
212 
213  /**
214  * Decode an ENC[] string into its parts.
215  * @param src The source encrypt string.
216  * @param cipher The cipher string part.
217  * @param data The data string part.
218  * @param iv The iv string part.
219  * @param tag The tag string part.
220  * @return false if the decode failed / invalid src string.
221  */
222  static bool decode( const std::string &src,
223  std::string &cipher,
224  std::string &data,
225  std::string &iv,
226  std::string &tag );
227 
228  /**
229  * Pad or trim a key to match the key size for the Cipher.
230  * @param cipher The Cipher to apply.
231  * @param key The key to adjust
232  * @return The adjusted key.
233  */
234  static std::string paddedKey( Cipher cipher, const std::string key );
235 
236  };
237 
238 }
239 
240 #endif
dodo::common::DataCrypt::blockOctets
static int blockOctets(Cipher cipher)
Return the block size of the Cipher in octets.
Definition: datacrypt.hpp:124
dodo::common::DataCrypt::keyOctets
static int keyOctets(Cipher cipher)
Return the size of the key for the given Cipher in bits.
Definition: datacrypt.hpp:94
dodo::common::DataCrypt::decrypt
static int decrypt(const std::string &key, const std::string src, Bytes &dest)
Decrypt data with a key.
Definition: datacrypt.cpp:129
dodo::common::Bytes
An array of Octets with size elements.
Definition: bytes.hpp:44
dodo::common::DataCrypt::Cipher
Cipher
Cipher selection.
Definition: datacrypt.hpp:81
dodo::common::DataCrypt::string2Cipher
static Cipher string2Cipher(const std::string &s)
Convert a string representation to an Cipher.
Definition: datacrypt.hpp:169
dodo::common::DataCrypt::encrypt
static void encrypt(Cipher cipher, const std::string &key, const Bytes &src, std::string &dst)
Encrypt data with a key into a string (so the encrypted data will not contain a 0/zero).
Definition: datacrypt.cpp:33
dodo::common::DataCrypt::cipherOctets
static size_t cipherOctets(Cipher cipher, size_t octets)
Calculate the size of the encrypted data from the input size.
Definition: datacrypt.hpp:209
dodo::common::DataCrypt::ivOctets
static int ivOctets(Cipher cipher)
Return the size of the IV (initialization vector) for the given Cipher in bits.
Definition: datacrypt.hpp:109
dodo::common::DataCrypt::cipher2String
static std::string cipher2String(const Cipher &cipher)
String representation of an Cipher instance.
Definition: datacrypt.hpp:154
dodo::common
Common and utility interfaces.
Definition: application.hpp:29
dodo::common::DataCrypt::Cipher::EVP_aes_128_gcm
@ EVP_aes_128_gcm
https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_128_gcm.html
dodo::common::DataCrypt::paddedKey
static std::string paddedKey(Cipher cipher, const std::string key)
Pad or trim a key to match the key size for the Cipher.
Definition: datacrypt.cpp:201
dodo::common::DataCrypt::Cipher::EVP_aes_256_gcm
@ EVP_aes_256_gcm
https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_256_gcm.html
dodo::common::DataCrypt::decode
static bool decode(const std::string &src, std::string &cipher, std::string &data, std::string &iv, std::string &tag)
Decode an ENC[] string into its parts.
Definition: datacrypt.cpp:101
exception.hpp
dodo::common::DataCrypt
Interface to encrypt and decrypt Bytes data to/from a secure string.
Definition: datacrypt.hpp:74
dodo::common::DataCrypt::tagLength
static int tagLength(Cipher cipher)
Return the tag length of the Cipher in octets.
Definition: datacrypt.hpp:139
dodo::common::DataCrypt::Cipher::EVP_aes_192_gcm
@ EVP_aes_192_gcm
https://www.openssl.org/docs/man1.0.2/man3/EVP_aes_192_gcm.html
bytes.hpp