1/*****************************************************************************
2Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
3Copyright (c) 2015, 2017, MariaDB Corporation.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License as published by the Free Software
7Foundation; version 2 of the License.
8
9This program is distributed in the hope that it will be useful, but WITHOUT
10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License along with
14this program; if not, write to the Free Software Foundation, Inc.,
1551 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16
17*****************************************************************************/
18
19/**************************************************//**
20@file include/fil0crypt.h
21The low-level file system encryption support functions
22
23Created 04/01/2015 Jan Lindström
24*******************************************************/
25
26#ifndef fil0crypt_h
27#define fil0crypt_h
28
29#ifndef UNIV_INNOCHECKSUM
30#include "os0event.h"
31#include "my_crypt.h"
32#include "fil0fil.h"
33#endif /*! UNIV_INNOCHECKSUM */
34
35/**
36* Magic pattern in start of crypt data on page 0
37*/
38#define MAGIC_SZ 6
39
40static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = {
41 's', 0xE, 0xC, 'R', 'E', 't' };
42
43/* This key will be used if nothing else is given */
44#define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA
45
46extern os_event_t fil_crypt_threads_event;
47
48/**
49 * CRYPT_SCHEME_UNENCRYPTED
50 *
51 * Used as intermediate state when convering a space from unencrypted
52 * to encrypted
53 */
54/**
55 * CRYPT_SCHEME_1
56 *
57 * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths)
58 * L = AES_ECB(KEY, IV)
59 * CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE)
60 */
61
62#define CRYPT_SCHEME_1 1
63#define CRYPT_SCHEME_1_IV_LEN 16
64#define CRYPT_SCHEME_UNENCRYPTED 0
65
66/* Cached L or key for given key_version */
67struct key_struct
68{
69 uint key_version; /*!< Version of the key */
70 uint key_length; /*!< Key length */
71 unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key
72 (that is L in CRYPT_SCHEME_1) */
73};
74
75/** is encryption enabled */
76extern ulong srv_encrypt_tables;
77
78/** Mutex helper for crypt_data->scheme
79@param[in, out] schme encryption scheme
80@param[in] exit should we exit or enter mutex ? */
81void
82crypt_data_scheme_locker(
83 st_encryption_scheme* scheme,
84 int exit);
85
86struct fil_space_rotate_state_t
87{
88 time_t start_time; /*!< time when rotation started */
89 ulint active_threads; /*!< active threads in space */
90 ulint next_offset; /*!< next "free" offset */
91 ulint max_offset; /*!< max offset needing to be rotated */
92 uint min_key_version_found; /*!< min key version found but not
93 rotated */
94 lsn_t end_lsn; /*!< max lsn created when rotating this
95 space */
96 bool starting; /*!< initial write of IV */
97 bool flushing; /*!< space is being flushed at end of rotate */
98 struct {
99 bool is_active; /*!< is scrubbing active in this space */
100 time_t last_scrub_completed; /*!< when was last scrub
101 completed */
102 } scrubbing;
103};
104
105#ifndef UNIV_INNOCHECKSUM
106
107struct fil_space_crypt_t : st_encryption_scheme
108{
109 public:
110 /** Constructor. Does not initialize the members!
111 The object is expected to be placed in a buffer that
112 has been zero-initialized. */
113 fil_space_crypt_t(
114 uint new_type,
115 uint new_min_key_version,
116 uint new_key_id,
117 fil_encryption_t new_encryption)
118 : st_encryption_scheme(),
119 min_key_version(new_min_key_version),
120 page0_offset(0),
121 encryption(new_encryption),
122 key_found(0),
123 rotate_state()
124 {
125 key_id = new_key_id;
126 my_random_bytes(iv, sizeof(iv));
127 mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
128 locker = crypt_data_scheme_locker;
129 type = new_type;
130
131 if (new_encryption == FIL_ENCRYPTION_OFF ||
132 (!srv_encrypt_tables &&
133 new_encryption == FIL_ENCRYPTION_DEFAULT)) {
134 type = CRYPT_SCHEME_UNENCRYPTED;
135 } else {
136 type = CRYPT_SCHEME_1;
137 min_key_version = key_get_latest_version();
138 }
139
140 key_found = min_key_version;
141 }
142
143 /** Destructor */
144 ~fil_space_crypt_t()
145 {
146 mutex_free(&mutex);
147 }
148
149 /** Get latest key version from encryption plugin
150 @retval key_version or
151 @retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
152 is not found from encryption plugin. */
153 uint key_get_latest_version(void);
154
155 /** Returns true if key was found from encryption plugin
156 and false if not. */
157 bool is_key_found() const {
158 return key_found != ENCRYPTION_KEY_VERSION_INVALID;
159 }
160
161 /** Returns true if tablespace should be encrypted */
162 bool should_encrypt() const {
163 return ((encryption == FIL_ENCRYPTION_ON) ||
164 (srv_encrypt_tables &&
165 encryption == FIL_ENCRYPTION_DEFAULT));
166 }
167
168 /** Return true if tablespace is encrypted. */
169 bool is_encrypted() const {
170 return (encryption != FIL_ENCRYPTION_OFF);
171 }
172
173 /** Return true if default tablespace encryption is used, */
174 bool is_default_encryption() const {
175 return (encryption == FIL_ENCRYPTION_DEFAULT);
176 }
177
178 /** Return true if tablespace is not encrypted. */
179 bool not_encrypted() const {
180 return (encryption == FIL_ENCRYPTION_OFF);
181 }
182
183 /** Write crypt data to a page (0)
184 @param[in] space tablespace
185 @param[in,out] page0 first page of the tablespace
186 @param[in,out] mtr mini-transaction */
187 void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr);
188
189 uint min_key_version; // min key version for this space
190 ulint page0_offset; // byte offset on page 0 for crypt data
191 fil_encryption_t encryption; // Encryption setup
192
193 ib_mutex_t mutex; // mutex protecting following variables
194
195 /** Return code from encryption_key_get_latest_version.
196 If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
197 could not find the key and there is no need to call
198 get_latest_key_version again as keys are read only
199 at startup. */
200 uint key_found;
201
202 fil_space_rotate_state_t rotate_state;
203};
204
205/** Status info about encryption */
206struct fil_space_crypt_status_t {
207 ulint space; /*!< tablespace id */
208 ulint scheme; /*!< encryption scheme */
209 uint min_key_version; /*!< min key version */
210 uint current_key_version;/*!< current key version */
211 uint keyserver_requests;/*!< no of key requests to key server */
212 uint key_id; /*!< current key_id */
213 bool rotating; /*!< is key rotation ongoing */
214 bool flushing; /*!< is flush at end of rotation ongoing */
215 ulint rotate_next_page_number; /*!< next page if key rotating */
216 ulint rotate_max_page_number; /*!< max page if key rotating */
217};
218
219/** Statistics about encryption key rotation */
220struct fil_crypt_stat_t {
221 ulint pages_read_from_cache;
222 ulint pages_read_from_disk;
223 ulint pages_modified;
224 ulint pages_flushed;
225 ulint estimated_iops;
226};
227
228/** Status info about scrubbing */
229struct fil_space_scrub_status_t {
230 ulint space; /*!< tablespace id */
231 bool compressed; /*!< is space compressed */
232 time_t last_scrub_completed; /*!< when was last scrub completed */
233 bool scrubbing; /*!< is scrubbing ongoing */
234 time_t current_scrub_started; /*!< when started current scrubbing */
235 ulint current_scrub_active_threads; /*!< current scrub active threads */
236 ulint current_scrub_page_number; /*!< current scrub page no */
237 ulint current_scrub_max_page_number; /*!< current scrub max page no */
238};
239
240/*********************************************************************
241Init space crypt */
242UNIV_INTERN
243void
244fil_space_crypt_init();
245
246/*********************************************************************
247Cleanup space crypt */
248UNIV_INTERN
249void
250fil_space_crypt_cleanup();
251
252/**
253Create a fil_space_crypt_t object
254@param[in] encrypt_mode FIL_ENCRYPTION_DEFAULT or
255 FIL_ENCRYPTION_ON or
256 FIL_ENCRYPTION_OFF
257
258@param[in] key_id Encryption key id
259@return crypt object */
260UNIV_INTERN
261fil_space_crypt_t*
262fil_space_create_crypt_data(
263 fil_encryption_t encrypt_mode,
264 uint key_id)
265 MY_ATTRIBUTE((warn_unused_result));
266
267/******************************************************************
268Merge fil_space_crypt_t object
269@param[in,out] dst Destination cryp data
270@param[in] src Source crypt data */
271UNIV_INTERN
272void
273fil_space_merge_crypt_data(
274 fil_space_crypt_t* dst,
275 const fil_space_crypt_t* src);
276
277/** Initialize encryption parameters from a tablespace header page.
278@param[in] page_size page size of the tablespace
279@param[in] page first page of the tablespace
280@return crypt data from page 0
281@retval NULL if not present or not valid */
282UNIV_INTERN
283fil_space_crypt_t*
284fil_space_read_crypt_data(const page_size_t& page_size, const byte* page)
285 MY_ATTRIBUTE((nonnull, warn_unused_result));
286
287/**
288Free a crypt data object
289@param[in,out] crypt_data crypt data to be freed */
290UNIV_INTERN
291void
292fil_space_destroy_crypt_data(
293 fil_space_crypt_t **crypt_data);
294
295/******************************************************************
296Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
297@param[in] ptr Log entry start
298@param[in] end_ptr Log entry end
299@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED
300@return position on log buffer */
301UNIV_INTERN
302byte*
303fil_parse_write_crypt_data(
304 byte* ptr,
305 const byte* end_ptr,
306 dberr_t* err)
307 MY_ATTRIBUTE((warn_unused_result));
308
309/** Encrypt a buffer.
310@param[in,out] crypt_data Crypt data
311@param[in] space space_id
312@param[in] offset Page offset
313@param[in] lsn Log sequence number
314@param[in] src_frame Page to encrypt
315@param[in] page_size Page size
316@param[in,out] dst_frame Output buffer
317@return encrypted buffer or NULL */
318byte*
319fil_encrypt_buf(
320 fil_space_crypt_t* crypt_data,
321 ulint space,
322 ulint offset,
323 lsn_t lsn,
324 const byte* src_frame,
325 const page_size_t& page_size,
326 byte* dst_frame)
327 MY_ATTRIBUTE((warn_unused_result));
328
329/**
330Encrypt a page.
331
332@param[in] space Tablespace
333@param[in] offset Page offset
334@param[in] lsn Log sequence number
335@param[in] src_frame Page to encrypt
336@param[in,out] dst_frame Output buffer
337@return encrypted buffer or NULL */
338UNIV_INTERN
339byte*
340fil_space_encrypt(
341 const fil_space_t* space,
342 ulint offset,
343 lsn_t lsn,
344 byte* src_frame,
345 byte* dst_frame)
346 MY_ATTRIBUTE((warn_unused_result));
347
348/**
349Decrypt a page.
350@param[in,out] crypt_data crypt_data
351@param[in] tmp_frame Temporary buffer
352@param[in] page_size Page size
353@param[in,out] src_frame Page to decrypt
354@param[out] err DB_SUCCESS or error
355@return true if page decrypted, false if not.*/
356UNIV_INTERN
357bool
358fil_space_decrypt(
359 fil_space_crypt_t* crypt_data,
360 byte* tmp_frame,
361 const page_size_t& page_size,
362 byte* src_frame,
363 dberr_t* err);
364
365/******************************************************************
366Decrypt a page
367@param[in] space Tablespace
368@param[in] tmp_frame Temporary buffer used for decrypting
369@param[in,out] src_frame Page to decrypt
370@param[out] decrypted true if page was decrypted
371@return decrypted page, or original not encrypted page if decryption is
372not needed.*/
373UNIV_INTERN
374byte*
375fil_space_decrypt(
376 const fil_space_t* space,
377 byte* tmp_frame,
378 byte* src_frame,
379 bool* decrypted)
380 MY_ATTRIBUTE((warn_unused_result));
381
382/******************************************************************
383Calculate post encryption checksum
384@param[in] page_size page size
385@param[in] dst_frame Block where checksum is calculated
386@return page checksum or BUF_NO_CHECKSUM_MAGIC
387not needed. */
388UNIV_INTERN
389uint32_t
390fil_crypt_calculate_checksum(
391 const page_size_t& page_size,
392 const byte* dst_frame)
393 MY_ATTRIBUTE((warn_unused_result));
394
395/*********************************************************************
396Adjust thread count for key rotation
397@param[in] enw_cnt Number of threads to be used */
398UNIV_INTERN
399void
400fil_crypt_set_thread_cnt(
401 uint new_cnt);
402
403/*********************************************************************
404Adjust max key age
405@param[in] val New max key age */
406UNIV_INTERN
407void
408fil_crypt_set_rotate_key_age(
409 uint val);
410
411/*********************************************************************
412Adjust rotation iops
413@param[in] val New max roation iops */
414UNIV_INTERN
415void
416fil_crypt_set_rotation_iops(
417 uint val);
418
419/*********************************************************************
420Adjust encrypt tables
421@param[in] val New setting for innodb-encrypt-tables */
422UNIV_INTERN
423void
424fil_crypt_set_encrypt_tables(
425 uint val);
426
427/*********************************************************************
428Init threads for key rotation */
429UNIV_INTERN
430void
431fil_crypt_threads_init();
432
433/*********************************************************************
434Clean up key rotation threads resources */
435UNIV_INTERN
436void
437fil_crypt_threads_cleanup();
438
439/*********************************************************************
440Wait for crypt threads to stop accessing space
441@param[in] space Tablespace */
442UNIV_INTERN
443void
444fil_space_crypt_close_tablespace(
445 const fil_space_t* space);
446
447/*********************************************************************
448Get crypt status for a space (used by information_schema)
449@param[in] space Tablespace
450@param[out] status Crypt status
451return 0 if crypt data present */
452UNIV_INTERN
453void
454fil_space_crypt_get_status(
455 const fil_space_t* space,
456 struct fil_space_crypt_status_t* status);
457
458/*********************************************************************
459Return crypt statistics
460@param[out] stat Crypt statistics */
461UNIV_INTERN
462void
463fil_crypt_total_stat(
464 fil_crypt_stat_t *stat);
465
466/**
467Get scrub status for a space (used by information_schema)
468
469@param[in] space Tablespace
470@param[out] status Scrub status
471return 0 if data found */
472UNIV_INTERN
473void
474fil_space_get_scrub_status(
475 const fil_space_t* space,
476 fil_space_scrub_status_t* status);
477
478#include "fil0crypt.ic"
479#endif /* !UNIV_INNOCHECKSUM */
480
481/**
482Verify that post encryption checksum match calculated checksum.
483This function should be called only if tablespace contains crypt_data
484metadata (this is strong indication that tablespace is encrypted).
485Function also verifies that traditional checksum does not match
486calculated checksum as if it does page could be valid unencrypted,
487encrypted, or corrupted.
488
489@param[in,out] page page frame (checksum is temporarily modified)
490@param[in] page_size page size
491@param[in] space tablespace identifier
492@param[in] offset page number
493@return true if page is encrypted AND OK, false otherwise */
494UNIV_INTERN
495bool
496fil_space_verify_crypt_checksum(
497 byte* page,
498 const page_size_t& page_size,
499 ulint space,
500 ulint offset)
501 MY_ATTRIBUTE((warn_unused_result));
502
503#endif /* fil0crypt_h */
504