Browse Source
Merge 10.1 into 10.2
Merge 10.1 into 10.2
This will also change the minimum and maximum value of innodb_log_file_size to 1MiB and 512GiB, respectively.pull/403/merge
29 changed files with 146 additions and 3787 deletions
-
25extra/mariabackup/backup_copy.cc
-
28extra/mariabackup/backup_mysql.cc
-
665extra/mariabackup/ds_decrypt.c
-
30extra/mariabackup/ds_decrypt.h
-
446extra/mariabackup/ds_encrypt.c
-
33extra/mariabackup/ds_encrypt.h
-
1extra/mariabackup/encryption_plugin.cc
-
116extra/mariabackup/innobackupex.cc
-
13extra/mariabackup/xb0xb.h
-
696extra/mariabackup/xbcrypt.c
-
79extra/mariabackup/xbcrypt.h
-
328extra/mariabackup/xbcrypt_common.c
-
64extra/mariabackup/xbcrypt_common.h
-
252extra/mariabackup/xbcrypt_read.c
-
105extra/mariabackup/xbcrypt_write.c
-
57extra/mariabackup/xbstream.c
-
808extra/mariabackup/xtrabackup.cc
-
12extra/mariabackup/xtrabackup.h
-
18mysql-test/r/mdl_sync.result
-
8mysql-test/suite/innodb/t/log_file_size.test
-
1mysql-test/suite/mariabackup/full_backup.test
-
5mysql-test/suite/mariabackup/incremental_encrypted.test
-
1mysql-test/suite/mariabackup/xb_file_key_management.test
-
4mysql-test/suite/sys_vars/r/sysvars_innodb.result
-
24mysql-test/t/mdl_sync.test
-
3sql/sql_reload.cc
-
2storage/innobase/handler/ha_innodb.cc
-
38storage/innobase/log/log0log.cc
-
71storage/xtradb/log/log0log.cc
@ -1,665 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
#include "crc_glue.h" |
|||
|
|||
typedef struct { |
|||
pthread_t id; |
|||
uint num; |
|||
pthread_mutex_t ctrl_mutex; |
|||
pthread_cond_t ctrl_cond; |
|||
pthread_mutex_t data_mutex; |
|||
pthread_cond_t data_cond; |
|||
my_bool started; |
|||
my_bool data_avail; |
|||
my_bool cancelled; |
|||
my_bool failed; |
|||
const uchar *from; |
|||
size_t from_len; |
|||
uchar *to; |
|||
size_t to_len; |
|||
size_t to_size; |
|||
const uchar *iv; |
|||
size_t iv_len; |
|||
unsigned long long offset; |
|||
my_bool hash_appended; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
xb_rcrypt_result_t parse_result; |
|||
} crypt_thread_ctxt_t; |
|||
|
|||
typedef struct { |
|||
crypt_thread_ctxt_t *threads; |
|||
uint nthreads; |
|||
int encrypt_algo; |
|||
size_t chunk_size; |
|||
char *encrypt_key; |
|||
char *encrypt_key_file; |
|||
} ds_decrypt_ctxt_t; |
|||
|
|||
typedef struct { |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
size_t bytes_processed; |
|||
ds_file_t *dest_file; |
|||
uchar *buf; |
|||
size_t buf_len; |
|||
size_t buf_size; |
|||
} ds_decrypt_file_t; |
|||
|
|||
int ds_decrypt_encrypt_threads = 1; |
|||
|
|||
static ds_ctxt_t *decrypt_init(const char *root); |
|||
static ds_file_t *decrypt_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int decrypt_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int decrypt_close(ds_file_t *file); |
|||
static void decrypt_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_decrypt = { |
|||
&decrypt_init, |
|||
&decrypt_open, |
|||
&decrypt_write, |
|||
&decrypt_close, |
|||
&decrypt_deinit |
|||
}; |
|||
|
|||
static crypt_thread_ctxt_t *create_worker_threads(uint n); |
|||
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n); |
|||
static void *decrypt_worker_thread_func(void *arg); |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
decrypt_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_decrypt_ctxt_t *decrypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
|
|||
if (xb_crypt_init(NULL)) { |
|||
return NULL; |
|||
} |
|||
|
|||
/* Create and initialize the worker threads */ |
|||
threads = create_worker_threads(ds_decrypt_encrypt_threads); |
|||
if (threads == NULL) { |
|||
msg("decrypt: failed to create worker threads.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) + |
|||
sizeof(ds_decrypt_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
decrypt_ctxt = (ds_decrypt_ctxt_t *) (ctxt + 1); |
|||
decrypt_ctxt->threads = threads; |
|||
decrypt_ctxt->nthreads = ds_decrypt_encrypt_threads; |
|||
|
|||
ctxt->ptr = decrypt_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
decrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_ctxt_t *dest_ctxt; |
|||
|
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
ds_decrypt_file_t *crypt_file; |
|||
|
|||
char new_name[FN_REFLEN]; |
|||
ds_file_t *file; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_decrypt_file_t), |
|||
MYF(MY_FAE|MY_ZEROFILL)); |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) (file + 1); |
|||
|
|||
/* Remove the .xbcrypt extension from the filename */ |
|||
strncpy(new_name, path, FN_REFLEN); |
|||
new_name[strlen(new_name) - 8] = 0; |
|||
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat); |
|||
if (crypt_file->dest_file == NULL) { |
|||
msg("decrypt: ds_open(\"%s\") failed.\n", new_name); |
|||
goto err; |
|||
} |
|||
|
|||
crypt_file->crypt_ctxt = crypt_ctxt; |
|||
crypt_file->buf = NULL; |
|||
crypt_file->buf_size = 0; |
|||
crypt_file->buf_len = 0; |
|||
|
|||
file->ptr = crypt_file; |
|||
file->path = crypt_file->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (crypt_file->dest_file) { |
|||
ds_close(crypt_file->dest_file); |
|||
} |
|||
my_free(file); |
|||
return NULL; |
|||
} |
|||
|
|||
#define CHECK_BUF_SIZE(ptr, size, buf, len) \ |
|||
if (ptr + size - buf > (ssize_t) len) { \ |
|||
result = XB_CRYPT_READ_INCOMPLETE; \ |
|||
goto exit; \ |
|||
} |
|||
|
|||
static |
|||
xb_rcrypt_result_t |
|||
parse_xbcrypt_chunk(crypt_thread_ctxt_t *thd, const uchar *buf, size_t len, |
|||
size_t *bytes_processed) |
|||
{ |
|||
const uchar *ptr; |
|||
uint version; |
|||
ulong checksum, checksum_exp; |
|||
ulonglong tmp; |
|||
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK; |
|||
|
|||
*bytes_processed = 0; |
|||
ptr = buf; |
|||
|
|||
CHECK_BUF_SIZE(ptr, XB_CRYPT_CHUNK_MAGIC_SIZE, buf, len); |
|||
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 3; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 2; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 1; |
|||
} else { |
|||
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
|
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
thd->offset += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* reserved */ |
|||
ptr += 8; |
|||
thd->offset += 8; |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* original size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid original size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
thd->offset += 8; |
|||
thd->to_len = (size_t)tmp; |
|||
|
|||
if (thd->to_size < thd->to_len + XB_CRYPT_HASH_LEN) { |
|||
thd->to = (uchar *) my_realloc( |
|||
thd->to, |
|||
thd->to_len + XB_CRYPT_HASH_LEN, |
|||
MYF(MY_FAE | MY_ALLOW_ZERO_PTR)); |
|||
thd->to_size = thd->to_len; |
|||
} |
|||
|
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
tmp = uint8korr(ptr); /* encrypted size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
thd->offset += 8; |
|||
thd->from_len = (size_t)tmp; |
|||
|
|||
xb_a(thd->from_len <= thd->to_len + XB_CRYPT_HASH_LEN); |
|||
|
|||
CHECK_BUF_SIZE(ptr, 4, buf, len); |
|||
checksum_exp = uint4korr(ptr); /* checksum */ |
|||
ptr += 4; |
|||
thd->offset += 4; |
|||
|
|||
/* iv size */ |
|||
if (version == 1) { |
|||
thd->iv_len = 0; |
|||
thd->iv = NULL; |
|||
} else { |
|||
CHECK_BUF_SIZE(ptr, 8, buf, len); |
|||
|
|||
tmp = uint8korr(ptr); |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid iv size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, thd->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
ptr += 8; |
|||
thd->offset += 8; |
|||
thd->iv_len = (size_t)tmp; |
|||
} |
|||
|
|||
if (thd->iv_len > 0) { |
|||
CHECK_BUF_SIZE(ptr, thd->iv_len, buf, len); |
|||
thd->iv = ptr; |
|||
ptr += thd->iv_len; |
|||
} |
|||
|
|||
/* for version euqals 2 we need to read in the iv data but do not init |
|||
CTR with it */ |
|||
if (version == 2) { |
|||
thd->iv_len = 0; |
|||
thd->iv = 0; |
|||
} |
|||
|
|||
if (thd->from_len > 0) { |
|||
CHECK_BUF_SIZE(ptr, thd->from_len, buf, len); |
|||
thd->from = ptr; |
|||
ptr += thd->from_len; |
|||
} |
|||
|
|||
xb_ad(thd->from_len <= thd->to_len); |
|||
|
|||
checksum = crc32_iso3309(0, thd->from, thd->from_len); |
|||
if (checksum != checksum_exp) { |
|||
msg("%s:%s invalid checksum at offset 0x%llx, " |
|||
"expected 0x%lx, actual 0x%lx.\n", my_progname, |
|||
__FUNCTION__, thd->offset, checksum_exp, checksum); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto exit; |
|||
} |
|||
|
|||
thd->offset += thd->from_len; |
|||
|
|||
thd->hash_appended = version > 2; |
|||
|
|||
exit: |
|||
|
|||
*bytes_processed = (size_t) (ptr - buf); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
static |
|||
int |
|||
decrypt_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_decrypt_file_t *crypt_file; |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
crypt_thread_ctxt_t *thd; |
|||
uint nthreads; |
|||
uint i; |
|||
size_t bytes_processed; |
|||
xb_rcrypt_result_t parse_result = XB_CRYPT_READ_CHUNK; |
|||
my_bool err = FALSE; |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) file->ptr; |
|||
crypt_ctxt = crypt_file->crypt_ctxt; |
|||
|
|||
threads = crypt_ctxt->threads; |
|||
nthreads = crypt_ctxt->nthreads; |
|||
|
|||
if (crypt_file->buf_len > 0) { |
|||
thd = threads; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
do { |
|||
if (parse_result == XB_CRYPT_READ_INCOMPLETE) { |
|||
crypt_file->buf_size = crypt_file->buf_size * 2; |
|||
crypt_file->buf = (uchar *) my_realloc( |
|||
crypt_file->buf, |
|||
crypt_file->buf_size, |
|||
MYF(MY_FAE|MY_ALLOW_ZERO_PTR)); |
|||
} |
|||
|
|||
memcpy(crypt_file->buf + crypt_file->buf_len, |
|||
buf, MY_MIN(crypt_file->buf_size - |
|||
crypt_file->buf_len, len)); |
|||
|
|||
parse_result = parse_xbcrypt_chunk( |
|||
thd, crypt_file->buf, |
|||
crypt_file->buf_size, &bytes_processed); |
|||
|
|||
if (parse_result == XB_CRYPT_READ_ERROR) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
return 1; |
|||
} |
|||
|
|||
} while (parse_result == XB_CRYPT_READ_INCOMPLETE && |
|||
crypt_file->buf_size < len); |
|||
|
|||
if (parse_result != XB_CRYPT_READ_CHUNK) { |
|||
msg("decrypt: incomplete data.\n"); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
return 1; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= bytes_processed - crypt_file->buf_len; |
|||
buf += bytes_processed - crypt_file->buf_len; |
|||
|
|||
/* reap */ |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->failed) { |
|||
msg("decrypt: failed to decrypt chunk.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
xb_a(thd->to_len > 0); |
|||
|
|||
if (!err && |
|||
ds_write(crypt_file->dest_file, thd->to, thd->to_len)) { |
|||
msg("decrypt: write to destination failed.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += thd->from_len; |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
crypt_file->buf_len = 0; |
|||
|
|||
if (err) { |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
while (parse_result == XB_CRYPT_READ_CHUNK && len > 0) { |
|||
uint max_thread; |
|||
|
|||
for (i = 0; i < nthreads; i++) { |
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
parse_result = parse_xbcrypt_chunk( |
|||
thd, buf, len, &bytes_processed); |
|||
|
|||
if (parse_result == XB_CRYPT_READ_ERROR) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
err = TRUE; |
|||
break; |
|||
} |
|||
|
|||
thd->parse_result = parse_result; |
|||
|
|||
if (parse_result != XB_CRYPT_READ_CHUNK) { |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
break; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= bytes_processed; |
|||
buf += bytes_processed; |
|||
} |
|||
|
|||
max_thread = (i < nthreads) ? i : nthreads - 1; |
|||
|
|||
/* Reap and write decrypted data */ |
|||
for (i = 0; i <= max_thread; i++) { |
|||
thd = threads + i; |
|||
|
|||
if (thd->parse_result != XB_CRYPT_READ_CHUNK) { |
|||
break; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->failed) { |
|||
msg("decrypt: failed to decrypt chunk.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
xb_a(thd->to_len > 0); |
|||
|
|||
if (!err && ds_write(crypt_file->dest_file, thd->to, |
|||
thd->to_len)) { |
|||
msg("decrypt: write to destination failed.\n"); |
|||
err = TRUE; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += thd->from_len; |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
if (err) { |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
if (parse_result == XB_CRYPT_READ_INCOMPLETE && len > 0) { |
|||
crypt_file->buf_len = len; |
|||
if (crypt_file->buf_size < len) { |
|||
crypt_file->buf = (uchar *) my_realloc( |
|||
crypt_file->buf, |
|||
crypt_file->buf_len, |
|||
MYF(MY_FAE | MY_ALLOW_ZERO_PTR)); |
|||
crypt_file->buf_size = len; |
|||
} |
|||
memcpy(crypt_file->buf, buf, len); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
decrypt_close(ds_file_t *file) |
|||
{ |
|||
ds_decrypt_file_t *crypt_file; |
|||
ds_file_t *dest_file; |
|||
int rc = 0; |
|||
|
|||
crypt_file = (ds_decrypt_file_t *) file->ptr; |
|||
dest_file = crypt_file->dest_file; |
|||
|
|||
if (ds_close(dest_file)) { |
|||
rc = 1; |
|||
} |
|||
|
|||
my_free(crypt_file->buf); |
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
decrypt_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_decrypt_ctxt_t *crypt_ctxt; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
|
|||
crypt_ctxt = (ds_decrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads); |
|||
|
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
|||
|
|||
static |
|||
crypt_thread_ctxt_t * |
|||
create_worker_threads(uint n) |
|||
{ |
|||
crypt_thread_ctxt_t *threads; |
|||
uint i; |
|||
|
|||
threads = (crypt_thread_ctxt_t *) |
|||
my_malloc(sizeof(crypt_thread_ctxt_t) * n, |
|||
MYF(MY_FAE | MY_ZEROFILL)); |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
thd->num = i + 1; |
|||
|
|||
/* Initialize the control mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) || |
|||
pthread_cond_init(&thd->ctrl_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Initialize and data mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->data_mutex, NULL) || |
|||
pthread_cond_init(&thd->data_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
xb_crypt_cipher_open(&thd->cipher_handle); |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
if (pthread_create(&thd->id, NULL, decrypt_worker_thread_func, |
|||
thd)) { |
|||
msg("decrypt: pthread_create() failed: " |
|||
"errno = %d\n", errno); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Wait for the threads to start */ |
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
while (thd->started == FALSE) |
|||
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
return threads; |
|||
|
|||
err: |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
void |
|||
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
threads[i].cancelled = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
pthread_join(thd->id, NULL); |
|||
|
|||
pthread_cond_destroy(&thd->data_cond); |
|||
pthread_mutex_destroy(&thd->data_mutex); |
|||
pthread_cond_destroy(&thd->ctrl_cond); |
|||
pthread_mutex_destroy(&thd->ctrl_mutex); |
|||
|
|||
xb_crypt_cipher_close(thd->cipher_handle); |
|||
|
|||
my_free(thd->to); |
|||
} |
|||
|
|||
my_free(threads); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
decrypt_worker_thread_func(void *arg) |
|||
{ |
|||
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
|
|||
thd->started = TRUE; |
|||
pthread_cond_signal(&thd->ctrl_cond); |
|||
|
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
while (1) { |
|||
thd->data_avail = FALSE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
|
|||
while (!thd->data_avail && !thd->cancelled) { |
|||
pthread_cond_wait(&thd->data_cond, &thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->cancelled) |
|||
break; |
|||
|
|||
if (xb_crypt_decrypt(thd->cipher_handle, thd->from, |
|||
thd->from_len, thd->to, &thd->to_len, |
|||
thd->iv, thd->iv_len, |
|||
thd->hash_appended)) { |
|||
thd->failed = TRUE; |
|||
continue; |
|||
} |
|||
|
|||
} |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
return NULL; |
|||
} |
@ -1,30 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_DECRYPT_H |
|||
#define DS_DECRYPT_H |
|||
|
|||
#include "datasink.h" |
|||
|
|||
extern datasink_t datasink_decrypt; |
|||
|
|||
extern int ds_decrypt_encrypt_threads; |
|||
|
|||
#endif |
@ -1,446 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "datasink.h" |
|||
#include "xbcrypt_common.h" |
|||
#ifdef HAVE_GRYPT |
|||
#include "xbcrypt.h" |
|||
|
|||
#define XB_CRYPT_CHUNK_SIZE ((size_t) (ds_encrypt_encrypt_chunk_size)) |
|||
|
|||
typedef struct { |
|||
pthread_t id; |
|||
uint num; |
|||
pthread_mutex_t ctrl_mutex; |
|||
pthread_cond_t ctrl_cond; |
|||
pthread_mutex_t data_mutex; |
|||
pthread_cond_t data_cond; |
|||
my_bool started; |
|||
my_bool data_avail; |
|||
my_bool cancelled; |
|||
const uchar *from; |
|||
size_t from_len; |
|||
uchar *to; |
|||
uchar *iv; |
|||
size_t to_len; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
} crypt_thread_ctxt_t; |
|||
|
|||
typedef struct { |
|||
crypt_thread_ctxt_t *threads; |
|||
uint nthreads; |
|||
} ds_encrypt_ctxt_t; |
|||
|
|||
typedef struct { |
|||
xb_wcrypt_t *xbcrypt_file; |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
size_t bytes_processed; |
|||
ds_file_t *dest_file; |
|||
} ds_encrypt_file_t; |
|||
|
|||
/* Encryption options */ |
|||
uint ds_encrypt_encrypt_threads; |
|||
ulonglong ds_encrypt_encrypt_chunk_size; |
|||
|
|||
static ds_ctxt_t *encrypt_init(const char *root); |
|||
static ds_file_t *encrypt_open(ds_ctxt_t *ctxt, const char *path, |
|||
MY_STAT *mystat); |
|||
static int encrypt_write(ds_file_t *file, const void *buf, size_t len); |
|||
static int encrypt_close(ds_file_t *file); |
|||
static void encrypt_deinit(ds_ctxt_t *ctxt); |
|||
|
|||
datasink_t datasink_encrypt = { |
|||
&encrypt_init, |
|||
&encrypt_open, |
|||
&encrypt_write, |
|||
&encrypt_close, |
|||
&encrypt_deinit |
|||
}; |
|||
|
|||
static crypt_thread_ctxt_t *create_worker_threads(uint n); |
|||
static void destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n); |
|||
static void *encrypt_worker_thread_func(void *arg); |
|||
|
|||
static uint encrypt_iv_len = 0; |
|||
|
|||
static |
|||
ssize_t |
|||
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len) |
|||
{ |
|||
ds_encrypt_file_t *encrypt_file; |
|||
|
|||
encrypt_file = (ds_encrypt_file_t *) userdata; |
|||
|
|||
xb_ad(encrypt_file != NULL); |
|||
xb_ad(encrypt_file->dest_file != NULL); |
|||
|
|||
if (!ds_write(encrypt_file->dest_file, buf, len)) { |
|||
return len; |
|||
} |
|||
return -1; |
|||
} |
|||
|
|||
static |
|||
ds_ctxt_t * |
|||
encrypt_init(const char *root) |
|||
{ |
|||
ds_ctxt_t *ctxt; |
|||
ds_encrypt_ctxt_t *encrypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
|
|||
if (xb_crypt_init(&encrypt_iv_len)) { |
|||
return NULL; |
|||
} |
|||
|
|||
/* Create and initialize the worker threads */ |
|||
threads = create_worker_threads(ds_encrypt_encrypt_threads); |
|||
if (threads == NULL) { |
|||
msg("encrypt: failed to create worker threads.\n"); |
|||
return NULL; |
|||
} |
|||
|
|||
ctxt = (ds_ctxt_t *) my_malloc(sizeof(ds_ctxt_t) + |
|||
sizeof(ds_encrypt_ctxt_t), |
|||
MYF(MY_FAE)); |
|||
|
|||
encrypt_ctxt = (ds_encrypt_ctxt_t *) (ctxt + 1); |
|||
encrypt_ctxt->threads = threads; |
|||
encrypt_ctxt->nthreads = ds_encrypt_encrypt_threads; |
|||
|
|||
ctxt->ptr = encrypt_ctxt; |
|||
ctxt->root = my_strdup(root, MYF(MY_FAE)); |
|||
|
|||
return ctxt; |
|||
} |
|||
|
|||
static |
|||
ds_file_t * |
|||
encrypt_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) |
|||
{ |
|||
ds_ctxt_t *dest_ctxt; |
|||
|
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
ds_encrypt_file_t *crypt_file; |
|||
|
|||
char new_name[FN_REFLEN]; |
|||
ds_file_t *file; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
dest_ctxt = ctxt->pipe_ctxt; |
|||
|
|||
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
|
|||
file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + |
|||
sizeof(ds_encrypt_file_t), |
|||
MYF(MY_FAE|MY_ZEROFILL)); |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) (file + 1); |
|||
|
|||
/* Append the .xbcrypt extension to the filename */ |
|||
fn_format(new_name, path, "", ".xbcrypt", MYF(MY_APPEND_EXT)); |
|||
crypt_file->dest_file = ds_open(dest_ctxt, new_name, mystat); |
|||
if (crypt_file->dest_file == NULL) { |
|||
msg("encrypt: ds_open(\"%s\") failed.\n", new_name); |
|||
goto err; |
|||
} |
|||
|
|||
crypt_file->crypt_ctxt = crypt_ctxt; |
|||
crypt_file->xbcrypt_file = xb_crypt_write_open(crypt_file, |
|||
my_xb_crypt_write_callback); |
|||
|
|||
if (crypt_file->xbcrypt_file == NULL) { |
|||
msg("encrypt: xb_crypt_write_open() failed.\n"); |
|||
goto err; |
|||
} |
|||
|
|||
|
|||
file->ptr = crypt_file; |
|||
file->path = crypt_file->dest_file->path; |
|||
|
|||
return file; |
|||
|
|||
err: |
|||
if (crypt_file->dest_file) { |
|||
ds_close(crypt_file->dest_file); |
|||
} |
|||
my_free(file); |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
int |
|||
encrypt_write(ds_file_t *file, const void *buf, size_t len) |
|||
{ |
|||
ds_encrypt_file_t *crypt_file; |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
crypt_thread_ctxt_t *threads; |
|||
crypt_thread_ctxt_t *thd; |
|||
uint nthreads; |
|||
uint i; |
|||
const uchar *ptr; |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) file->ptr; |
|||
crypt_ctxt = crypt_file->crypt_ctxt; |
|||
|
|||
threads = crypt_ctxt->threads; |
|||
nthreads = crypt_ctxt->nthreads; |
|||
|
|||
ptr = (const uchar *) buf; |
|||
while (len > 0) { |
|||
uint max_thread; |
|||
|
|||
/* Send data to worker threads for encryption */ |
|||
for (i = 0; i < nthreads; i++) { |
|||
size_t chunk_len; |
|||
|
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
chunk_len = (len > XB_CRYPT_CHUNK_SIZE) ? |
|||
XB_CRYPT_CHUNK_SIZE : len; |
|||
thd->from = ptr; |
|||
thd->from_len = chunk_len; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
thd->data_avail = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
len -= chunk_len; |
|||
if (len == 0) { |
|||
break; |
|||
} |
|||
ptr += chunk_len; |
|||
} |
|||
|
|||
max_thread = (i < nthreads) ? i : nthreads - 1; |
|||
|
|||
/* Reap and stream the encrypted data */ |
|||
for (i = 0; i <= max_thread; i++) { |
|||
thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
while (thd->data_avail == TRUE) { |
|||
pthread_cond_wait(&thd->data_cond, |
|||
&thd->data_mutex); |
|||
} |
|||
|
|||
xb_a(threads[i].to_len > 0); |
|||
|
|||
if (xb_crypt_write_chunk(crypt_file->xbcrypt_file, |
|||
threads[i].to, |
|||
threads[i].from_len + |
|||
XB_CRYPT_HASH_LEN, |
|||
threads[i].to_len, |
|||
threads[i].iv, |
|||
encrypt_iv_len)) { |
|||
msg("encrypt: write to the destination file " |
|||
"failed.\n"); |
|||
return 1; |
|||
} |
|||
|
|||
crypt_file->bytes_processed += threads[i].from_len; |
|||
|
|||
pthread_mutex_unlock(&threads[i].data_mutex); |
|||
pthread_mutex_unlock(&threads[i].ctrl_mutex); |
|||
} |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
int |
|||
encrypt_close(ds_file_t *file) |
|||
{ |
|||
ds_encrypt_file_t *crypt_file; |
|||
ds_file_t *dest_file; |
|||
int rc = 0; |
|||
|
|||
crypt_file = (ds_encrypt_file_t *) file->ptr; |
|||
dest_file = crypt_file->dest_file; |
|||
|
|||
rc = xb_crypt_write_close(crypt_file->xbcrypt_file); |
|||
|
|||
if (ds_close(dest_file)) { |
|||
rc = 1; |
|||
} |
|||
|
|||
my_free(file); |
|||
|
|||
return rc; |
|||
} |
|||
|
|||
static |
|||
void |
|||
encrypt_deinit(ds_ctxt_t *ctxt) |
|||
{ |
|||
ds_encrypt_ctxt_t *crypt_ctxt; |
|||
|
|||
xb_ad(ctxt->pipe_ctxt != NULL); |
|||
|
|||
crypt_ctxt = (ds_encrypt_ctxt_t *) ctxt->ptr; |
|||
|
|||
destroy_worker_threads(crypt_ctxt->threads, crypt_ctxt->nthreads); |
|||
|
|||
my_free(ctxt->root); |
|||
my_free(ctxt); |
|||
} |
|||
|
|||
static |
|||
crypt_thread_ctxt_t * |
|||
create_worker_threads(uint n) |
|||
{ |
|||
crypt_thread_ctxt_t *threads; |
|||
uint i; |
|||
|
|||
threads = (crypt_thread_ctxt_t *) |
|||
my_malloc(sizeof(crypt_thread_ctxt_t) * n, MYF(MY_FAE)); |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
thd->num = i + 1; |
|||
thd->started = FALSE; |
|||
thd->cancelled = FALSE; |
|||
thd->data_avail = FALSE; |
|||
|
|||
thd->to = (uchar *) my_malloc(XB_CRYPT_CHUNK_SIZE + |
|||
XB_CRYPT_HASH_LEN, MYF(MY_FAE)); |
|||
|
|||
thd->iv = (uchar *) my_malloc(encrypt_iv_len, MYF(MY_FAE)); |
|||
|
|||
/* Initialize the control mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->ctrl_mutex, NULL) || |
|||
pthread_cond_init(&thd->ctrl_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Initialize and data mutex and condition var */ |
|||
if (pthread_mutex_init(&thd->data_mutex, NULL) || |
|||
pthread_cond_init(&thd->data_cond, NULL)) { |
|||
goto err; |
|||
} |
|||
|
|||
if (xb_crypt_cipher_open(&thd->cipher_handle)) { |
|||
goto err; |
|||
} |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
if (pthread_create(&thd->id, NULL, encrypt_worker_thread_func, |
|||
thd)) { |
|||
msg("encrypt: pthread_create() failed: " |
|||
"errno = %d\n", errno); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Wait for the threads to start */ |
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
while (thd->started == FALSE) |
|||
pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex); |
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
} |
|||
|
|||
return threads; |
|||
|
|||
err: |
|||
return NULL; |
|||
} |
|||
|
|||
static |
|||
void |
|||
destroy_worker_threads(crypt_thread_ctxt_t *threads, uint n) |
|||
{ |
|||
uint i; |
|||
|
|||
for (i = 0; i < n; i++) { |
|||
crypt_thread_ctxt_t *thd = threads + i; |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
threads[i].cancelled = TRUE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
pthread_join(thd->id, NULL); |
|||
|
|||
pthread_cond_destroy(&thd->data_cond); |
|||
pthread_mutex_destroy(&thd->data_mutex); |
|||
pthread_cond_destroy(&thd->ctrl_cond); |
|||
pthread_mutex_destroy(&thd->ctrl_mutex); |
|||
|
|||
xb_crypt_cipher_close(thd->cipher_handle); |
|||
|
|||
my_free(thd->to); |
|||
my_free(thd->iv); |
|||
} |
|||
|
|||
my_free(threads); |
|||
} |
|||
|
|||
static |
|||
void * |
|||
encrypt_worker_thread_func(void *arg) |
|||
{ |
|||
crypt_thread_ctxt_t *thd = (crypt_thread_ctxt_t *) arg; |
|||
|
|||
pthread_mutex_lock(&thd->ctrl_mutex); |
|||
|
|||
pthread_mutex_lock(&thd->data_mutex); |
|||
|
|||
thd->started = TRUE; |
|||
pthread_cond_signal(&thd->ctrl_cond); |
|||
|
|||
pthread_mutex_unlock(&thd->ctrl_mutex); |
|||
|
|||
while (1) { |
|||
thd->data_avail = FALSE; |
|||
pthread_cond_signal(&thd->data_cond); |
|||
|
|||
while (!thd->data_avail && !thd->cancelled) { |
|||
pthread_cond_wait(&thd->data_cond, &thd->data_mutex); |
|||
} |
|||
|
|||
if (thd->cancelled) |
|||
break; |
|||
|
|||
thd->to_len = thd->from_len; |
|||
|
|||
if (xb_crypt_encrypt(thd->cipher_handle, thd->from, |
|||
thd->from_len, thd->to, &thd->to_len, |
|||
thd->iv)) { |
|||
thd->to_len = 0; |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
pthread_mutex_unlock(&thd->data_mutex); |
|||
|
|||
return NULL; |
|||
} |
|||
#endif /* HAVE_GCRYPT*/ |
@ -1,33 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef DS_ENCRYPT_H |
|||
#define DS_ENCRYPT_H |
|||
|
|||
#include "datasink.h" |
|||
#ifdef HAVE_GCRYPT |
|||
extern datasink_t datasink_encrypt; |
|||
#endif |
|||
/* Encryption options */ |
|||
extern uint ds_encrypt_encrypt_threads; |
|||
extern ulonglong ds_encrypt_encrypt_chunk_size; |
|||
|
|||
|
|||
#endif |
@ -1,696 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt utility: decrypt files in the XBCRYPT format. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include <my_getopt.h> |
|||
#include "common.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
#include "crc_glue.h" |
|||
|
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
GCRY_THREAD_OPTION_PTHREAD_IMPL; |
|||
#endif |
|||
|
|||
#define XBCRYPT_VERSION "1.1" |
|||
|
|||
typedef enum { |
|||
RUN_MODE_NONE, |
|||
RUN_MODE_ENCRYPT, |
|||
RUN_MODE_DECRYPT |
|||
} run_mode_t; |
|||
|
|||
const char *xbcrypt_encrypt_algo_names[] = |
|||
{ "NONE", "AES128", "AES192", "AES256", NullS}; |
|||
TYPELIB xbcrypt_encrypt_algo_typelib= |
|||
{array_elements(xbcrypt_encrypt_algo_names)-1,"", |
|||
xbcrypt_encrypt_algo_names, NULL}; |
|||
|
|||
static run_mode_t opt_run_mode = RUN_MODE_ENCRYPT; |
|||
static char *opt_input_file = NULL; |
|||
static char *opt_output_file = NULL; |
|||
static ulong opt_encrypt_algo; |
|||
static char *opt_encrypt_key_file = NULL; |
|||
static void *opt_encrypt_key = NULL; |
|||
static ulonglong opt_encrypt_chunk_size = 0; |
|||
static my_bool opt_verbose = FALSE; |
|||
|
|||
static uint encrypt_algos[] = { GCRY_CIPHER_NONE, |
|||
GCRY_CIPHER_AES128, |
|||
GCRY_CIPHER_AES192, |
|||
GCRY_CIPHER_AES256 }; |
|||
static int encrypt_algo = 0; |
|||
static int encrypt_mode = GCRY_CIPHER_MODE_CTR; |
|||
static uint encrypt_key_len = 0; |
|||
static size_t encrypt_iv_len = 0; |
|||
|
|||
static struct my_option my_long_options[] = |
|||
{ |
|||
{"help", '?', "Display this help and exit.", |
|||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"decrypt", 'd', "Decrypt data input to output.", |
|||
0, 0, 0, |
|||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"input", 'i', "Optional input file. If not specified, input" |
|||
" will be read from standard input.", |
|||
&opt_input_file, &opt_input_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"output", 'o', "Optional output file. If not specified, output" |
|||
" will be written to standard output.", |
|||
&opt_output_file, &opt_output_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-algo", 'a', "Encryption algorithm.", |
|||
&opt_encrypt_algo, &opt_encrypt_algo, &xbcrypt_encrypt_algo_typelib, |
|||
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-key", 'k', "Encryption key.", |
|||
&opt_encrypt_key, &opt_encrypt_key, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-key-file", 'f', "File which contains encryption key.", |
|||
&opt_encrypt_key_file, &opt_encrypt_key_file, 0, |
|||
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
|||
|
|||
{"encrypt-chunk-size", 's', "Size of working buffer for encryption in" |
|||
" bytes. The default value is 64K.", |
|||
&opt_encrypt_chunk_size, &opt_encrypt_chunk_size, 0, |
|||
GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0}, |
|||
|
|||
{"verbose", 'v', "Display verbose status output.", |
|||
&opt_verbose, &opt_verbose, |
|||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, |
|||
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
|||
}; |
|||
|
|||
static |
|||
int |
|||
get_options(int *argc, char ***argv); |
|||
|
|||
static |
|||
my_bool |
|||
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
|||
char *argument __attribute__((unused))); |
|||
|
|||
static |
|||
void |
|||
print_version(void); |
|||
|
|||
static |
|||
void |
|||
usage(void); |
|||
|
|||
static |
|||
int |
|||
mode_decrypt(File filein, File fileout); |
|||
|
|||
static |
|||
int |
|||
mode_encrypt(File filein, File fileout); |
|||
|
|||
int |
|||
main(int argc, char **argv) |
|||
{ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error_t gcry_error; |
|||
#endif |
|||
File filein = 0; |
|||
File fileout = 0; |
|||
|
|||
MY_INIT(argv[0]); |
|||
|
|||
crc_init(); |
|||
|
|||
if (get_options(&argc, &argv)) { |
|||
goto err; |
|||
} |
|||
|
|||
/* Acording to gcrypt docs (and my testing), setting up the threading |
|||
callbacks must be done first, so, lets give it a shot */ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); |
|||
if (gcry_error) { |
|||
msg("%s: unable to set libgcrypt thread cbs - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
#endif |
|||
|
|||
/* Version check should be the very first call because it |
|||
makes sure that important subsystems are intialized. */ |
|||
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { |
|||
const char *gcrypt_version; |
|||
gcrypt_version = gcry_check_version(NULL); |
|||
/* No other library has already initialized libgcrypt. */ |
|||
if (!gcrypt_version) { |
|||
msg("%s: failed to initialize libgcrypt\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_verbose) { |
|||
msg("%s: using gcrypt %s\n", my_progname, |
|||
gcrypt_version); |
|||
} |
|||
} |
|||
gcry_control(GCRYCTL_DISABLE_SECMEM, 0); |
|||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); |
|||
|
|||
/* Determine the algorithm */ |
|||
encrypt_algo = encrypt_algos[opt_encrypt_algo]; |
|||
|
|||
/* Set up the iv length */ |
|||
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo); |
|||
|
|||
/* Now set up the key */ |
|||
if (opt_encrypt_key == NULL && opt_encrypt_key_file == NULL) { |
|||
msg("%s: no encryption key or key file specified.\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_encrypt_key && opt_encrypt_key_file) { |
|||
msg("%s: both encryption key and key file specified.\n", |
|||
my_progname); |
|||
return 1; |
|||
} else if (opt_encrypt_key_file) { |
|||
if (!xb_crypt_read_key_file(opt_encrypt_key_file, |
|||
&opt_encrypt_key, |
|||
&encrypt_key_len)) { |
|||
msg("%s: unable to read encryption key file \"%s\".\n", |
|||
opt_encrypt_key_file, my_progname); |
|||
return 1; |
|||
} |
|||
} else { |
|||
encrypt_key_len = strlen(opt_encrypt_key); |
|||
} |
|||
|
|||
if (opt_input_file) { |
|||
MY_STAT mystat; |
|||
|
|||
if (opt_verbose) |
|||
msg("%s: input file \"%s\".\n", my_progname, |
|||
opt_input_file); |
|||
|
|||
if (my_stat(opt_input_file, &mystat, MYF(MY_WME)) == NULL) { |
|||
goto err; |
|||
} |
|||
if (!MY_S_ISREG(mystat.st_mode)) { |
|||
msg("%s: \"%s\" is not a regular file, exiting.\n", |
|||
my_progname, opt_input_file); |
|||
goto err; |
|||
} |
|||
if ((filein = my_open(opt_input_file, O_RDONLY, MYF(MY_WME))) |
|||
< 0) { |
|||
msg("%s: failed to open \"%s\".\n", my_progname, |
|||
opt_input_file); |
|||
goto err; |
|||
} |
|||
} else { |
|||
if (opt_verbose) |
|||
msg("%s: input from standard input.\n", my_progname); |
|||
filein = fileno(stdin); |
|||
} |
|||
|
|||
if (opt_output_file) { |
|||
if (opt_verbose) |
|||
msg("%s: output file \"%s\".\n", my_progname, |
|||
opt_output_file); |
|||
|
|||
if ((fileout = my_create(opt_output_file, 0, |
|||
O_WRONLY|O_BINARY|O_EXCL|O_NOFOLLOW, |
|||
MYF(MY_WME))) < 0) { |
|||
msg("%s: failed to create output file \"%s\".\n", |
|||
my_progname, opt_output_file); |
|||
goto err; |
|||
} |
|||
} else { |
|||
if (opt_verbose) |
|||
msg("%s: output to standard output.\n", my_progname); |
|||
fileout = fileno(stdout); |
|||
} |
|||
|
|||
if (opt_run_mode == RUN_MODE_DECRYPT |
|||
&& mode_decrypt(filein, fileout)) { |
|||
goto err; |
|||
} else if (opt_run_mode == RUN_MODE_ENCRYPT |
|||
&& mode_encrypt(filein, fileout)) { |
|||
goto err; |
|||
} |
|||
|
|||
if (opt_input_file && filein) { |
|||
my_close(filein, MYF(MY_WME)); |
|||
} |
|||
if (opt_output_file && fileout) { |
|||
my_close(fileout, MYF(MY_WME)); |
|||
} |
|||
|
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
return EXIT_SUCCESS; |
|||
err: |
|||
if (opt_input_file && filein) { |
|||
my_close(filein, MYF(MY_WME)); |
|||
} |
|||
if (opt_output_file && fileout) { |
|||
my_close(fileout, MYF(MY_WME)); |
|||
} |
|||
|
|||
my_cleanup_options(my_long_options); |
|||
|
|||
my_end(0); |
|||
|
|||
exit(EXIT_FAILURE); |
|||
|
|||
} |
|||
|
|||
|
|||
static |
|||
size_t |
|||
my_xb_crypt_read_callback(void *userdata, void *buf, size_t len) |
|||
{ |
|||
File* file = (File *) userdata; |
|||
return xb_read_full(*file, buf, len); |
|||
} |
|||
|
|||
static |
|||
int |
|||
mode_decrypt(File filein, File fileout) |
|||
{ |
|||
xb_rcrypt_t *xbcrypt_file = NULL; |
|||
void *chunkbuf = NULL; |
|||
size_t chunksize; |
|||
size_t originalsize; |
|||
void *ivbuf = NULL; |
|||
size_t ivsize; |
|||
void *decryptbuf = NULL; |
|||
size_t decryptbufsize = 0; |
|||
ulonglong ttlchunksread = 0; |
|||
ulonglong ttlbytesread = 0; |
|||
xb_rcrypt_result_t result; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
gcry_error_t gcry_error; |
|||
my_bool hash_appended; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_open(&cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to open libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(cipher_handle, |
|||
opt_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to set libgcrypt cipher" |
|||
"key - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Initialize the xb_crypt format reader */ |
|||
xbcrypt_file = xb_crypt_read_open(&filein, my_xb_crypt_read_callback); |
|||
if (xbcrypt_file == NULL) { |
|||
msg("%s:decrypt: xb_crypt_read_open() failed.\n", my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
/* Walk the encrypted chunks, decrypting them and writing out */ |
|||
while ((result = xb_crypt_read_chunk(xbcrypt_file, &chunkbuf, |
|||
&originalsize, &chunksize, |
|||
&ivbuf, &ivsize, &hash_appended)) |
|||
== XB_CRYPT_READ_CHUNK) { |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to reset libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
|
|||
if (ivsize) { |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
ivbuf, |
|||
ivsize); |
|||
} |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
continue; |
|||
} |
|||
|
|||
if (decryptbufsize < originalsize) { |
|||
decryptbuf = my_realloc(decryptbuf, |
|||
originalsize, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
decryptbufsize = originalsize; |
|||
} |
|||
|
|||
/* Try to decrypt it */ |
|||
gcry_error = gcry_cipher_decrypt(cipher_handle, |
|||
decryptbuf, |
|||
originalsize, |
|||
chunkbuf, |
|||
chunksize); |
|||
if (gcry_error) { |
|||
msg("%s:decrypt: unable to decrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
goto err; |
|||
} |
|||
|
|||
} else { |
|||
decryptbuf = chunkbuf; |
|||
} |
|||
|
|||
if (hash_appended) { |
|||
uchar hash[XB_CRYPT_HASH_LEN]; |
|||
|
|||
originalsize -= XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_a(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, decryptbuf, |
|||
originalsize); |
|||
if (memcmp(hash, (char *) decryptbuf + originalsize, |
|||
XB_CRYPT_HASH_LEN) != 0) { |
|||
msg("%s:%s invalid plaintext hash. " |
|||
"Wrong encrytion key specified?\n", |
|||
my_progname, __FUNCTION__); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
/* Write it out */ |
|||
if (my_write(fileout, (const uchar *) decryptbuf, originalsize, |
|||
MYF(MY_WME | MY_NABP))) { |
|||
msg("%s:decrypt: unable to write output chunk.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
ttlchunksread++; |
|||
ttlbytesread += chunksize; |
|||
if (opt_verbose) |
|||
msg("%s:decrypt: %llu chunks read, %llu bytes read\n.", |
|||
my_progname, ttlchunksread, ttlbytesread); |
|||
} |
|||
|
|||
xb_crypt_read_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (decryptbuf && decryptbufsize) |
|||
my_free(decryptbuf); |
|||
|
|||
if (opt_verbose) |
|||
msg("\n%s:decrypt: done\n", my_progname); |
|||
|
|||
return 0; |
|||
err: |
|||
if (xbcrypt_file) |
|||
xb_crypt_read_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (decryptbuf && decryptbufsize) |
|||
my_free(decryptbuf); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
ssize_t |
|||
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len) |
|||
{ |
|||
File* file = (File *) userdata; |
|||
|
|||
ssize_t ret = my_write(*file, buf, len, MYF(MY_WME)); |
|||
posix_fadvise(*file, 0, 0, POSIX_FADV_DONTNEED); |
|||
return ret; |
|||
} |
|||
|
|||
static |
|||
int |
|||
mode_encrypt(File filein, File fileout) |
|||
{ |
|||
size_t bytesread; |
|||
size_t chunkbuflen; |
|||
uchar *chunkbuf = NULL; |
|||
void *ivbuf = NULL; |
|||
size_t encryptbuflen = 0; |
|||
size_t encryptedlen = 0; |
|||
void *encryptbuf = NULL; |
|||
ulonglong ttlchunkswritten = 0; |
|||
ulonglong ttlbyteswritten = 0; |
|||
xb_wcrypt_t *xbcrypt_file = NULL; |
|||
gcry_cipher_hd_t cipher_handle; |
|||
gcry_error_t gcry_error; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_open(&cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to open libgcrypt cipher - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return 1; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(cipher_handle, |
|||
opt_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to set libgcrypt cipher key - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
posix_fadvise(filein, 0, 0, POSIX_FADV_SEQUENTIAL); |
|||
|
|||
xbcrypt_file = xb_crypt_write_open(&fileout, |
|||
my_xb_crypt_write_callback); |
|||
if (xbcrypt_file == NULL) { |
|||
msg("%s:encrypt: xb_crypt_write_open() failed.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
ivbuf = my_malloc(encrypt_iv_len, MYF(MY_FAE)); |
|||
|
|||
/* now read in data in chunk size, encrypt and write out */ |
|||
chunkbuflen = opt_encrypt_chunk_size + XB_CRYPT_HASH_LEN; |
|||
chunkbuf = (uchar *) my_malloc(chunkbuflen, MYF(MY_FAE)); |
|||
while ((bytesread = my_read(filein, chunkbuf, opt_encrypt_chunk_size, |
|||
MYF(MY_WME))) > 0) { |
|||
|
|||
size_t origbuflen = bytesread + XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_a(XB_CRYPT_HASH_LEN == gcry_md_get_algo_dlen(XB_CRYPT_HASH)); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, chunkbuf + bytesread, |
|||
chunkbuf, bytesread); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to reset cipher - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
goto err; |
|||
} |
|||
|
|||
xb_crypt_create_iv(ivbuf, encrypt_iv_len); |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
ivbuf, |
|||
encrypt_iv_len); |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
continue; |
|||
} |
|||
|
|||
if (encryptbuflen < origbuflen) { |
|||
encryptbuf = my_realloc(encryptbuf, origbuflen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
encryptbuflen = origbuflen; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_encrypt(cipher_handle, |
|||
encryptbuf, |
|||
encryptbuflen, |
|||
chunkbuf, |
|||
origbuflen); |
|||
|
|||
encryptedlen = origbuflen; |
|||
|
|||
if (gcry_error) { |
|||
msg("%s:encrypt: unable to encrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
goto err; |
|||
} |
|||
} else { |
|||
encryptedlen = origbuflen; |
|||
encryptbuf = chunkbuf; |
|||
} |
|||
|
|||
if (xb_crypt_write_chunk(xbcrypt_file, encryptbuf, |
|||
bytesread + XB_CRYPT_HASH_LEN, |
|||
encryptedlen, ivbuf, encrypt_iv_len)) { |
|||
msg("%s:encrypt: abcrypt_write_chunk() failed.\n", |
|||
my_progname); |
|||
goto err; |
|||
} |
|||
|
|||
ttlchunkswritten++; |
|||
ttlbyteswritten += encryptedlen; |
|||
|
|||
if (opt_verbose) |
|||
msg("%s:encrypt: %llu chunks written, %llu bytes " |
|||
"written\n.", my_progname, ttlchunkswritten, |
|||
ttlbyteswritten); |
|||
} |
|||
|
|||
my_free(ivbuf); |
|||
my_free(chunkbuf); |
|||
|
|||
if (encryptbuf && encryptbuflen) |
|||
my_free(encryptbuf); |
|||
|
|||
xb_crypt_write_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
if (opt_verbose) |
|||
msg("\n%s:encrypt: done\n", my_progname); |
|||
|
|||
return 0; |
|||
err: |
|||
if (chunkbuf) |
|||
my_free(chunkbuf); |
|||
|
|||
if (encryptbuf && encryptbuflen) |
|||
my_free(encryptbuf); |
|||
|
|||
if (xbcrypt_file) |
|||
xb_crypt_write_close(xbcrypt_file); |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
|
|||
return 1; |
|||
} |
|||
|
|||
static |
|||
int |
|||
get_options(int *argc, char ***argv) |
|||
{ |
|||
int ho_error; |
|||
|
|||
if ((ho_error= handle_options(argc, argv, my_long_options, |
|||
get_one_option))) { |
|||
exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static |
|||
my_bool |
|||
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), |
|||
char *argument __attribute__((unused))) |
|||
{ |
|||
switch (optid) { |
|||
case 'd': |
|||
opt_run_mode = RUN_MODE_DECRYPT; |
|||
break; |
|||
case '?': |
|||
usage(); |
|||
exit(0); |
|||
} |
|||
|
|||
return FALSE; |
|||
} |
|||
|
|||
static |
|||
void |
|||
print_version(void) |
|||
{ |
|||
printf("%s Ver %s for %s (%s)\n", my_progname, XBCRYPT_VERSION, |
|||
SYSTEM_TYPE, MACHINE_TYPE); |
|||
} |
|||
|
|||
static |
|||
void |
|||
usage(void) |
|||
{ |
|||
print_version(); |
|||
puts("Copyright (C) 2011 Percona Inc."); |
|||
puts("This software comes with ABSOLUTELY NO WARRANTY. " |
|||
"This is free software,\nand you are welcome to modify and " |
|||
"redistribute it under the GPL license.\n"); |
|||
|
|||
puts("Encrypt or decrypt files in the XBCRYPT format.\n"); |
|||
|
|||
puts("Usage: "); |
|||
printf(" %s [OPTIONS...]" |
|||
" # read data from specified input, encrypting or decrypting " |
|||
" and writing the result to the specified output.\n", |
|||
my_progname); |
|||
puts("\nOptions:"); |
|||
my_print_help(my_long_options); |
|||
} |
@ -1,79 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2011 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#ifndef XBCRYPT_H |
|||
#define XBCRYPT_H |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
|
|||
#define XB_CRYPT_CHUNK_MAGIC1 "XBCRYP01" |
|||
#define XB_CRYPT_CHUNK_MAGIC2 "XBCRYP02" |
|||
#define XB_CRYPT_CHUNK_MAGIC3 "XBCRYP03" /* must be same size as ^^ */ |
|||
#define XB_CRYPT_CHUNK_MAGIC_CURRENT XB_CRYPT_CHUNK_MAGIC3 |
|||
#define XB_CRYPT_CHUNK_MAGIC_SIZE (sizeof(XB_CRYPT_CHUNK_MAGIC1)-1) |
|||
|
|||
#define XB_CRYPT_HASH GCRY_MD_SHA256 |
|||
#define XB_CRYPT_HASH_LEN 32 |
|||
|
|||
/****************************************************************************** |
|||
Write interface */ |
|||
typedef struct xb_wcrypt_struct xb_wcrypt_t; |
|||
|
|||
/* Callback on write for i/o, must return # of bytes written or -1 on error */ |
|||
typedef ssize_t xb_crypt_write_callback(void *userdata, |
|||
const void *buf, size_t len); |
|||
|
|||
xb_wcrypt_t *xb_crypt_write_open(void *userdata, |
|||
xb_crypt_write_callback *onwrite); |
|||
|
|||
/* Takes buffer, original length, encrypted length iv and iv length, formats |
|||
output buffer and calls write callback. |
|||
Returns 0 on success, 1 on error */ |
|||
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen, |
|||
size_t elen, const void *iv, size_t ivlen); |
|||
|
|||
/* Returns 0 on success, 1 on error */ |
|||
int xb_crypt_write_close(xb_wcrypt_t *crypt); |
|||
|
|||
/****************************************************************************** |
|||
Read interface */ |
|||
typedef struct xb_rcrypt_struct xb_rcrypt_t; |
|||
|
|||
/* Callback on read for i/o, must return # of bytes read or -1 on error */ |
|||
typedef size_t xb_crypt_read_callback(void *userdata, void *buf, size_t len); |
|||
|
|||
xb_rcrypt_t *xb_crypt_read_open(void *userdata, |
|||
xb_crypt_read_callback *onread); |
|||
|
|||
typedef enum { |
|||
XB_CRYPT_READ_CHUNK, |
|||
XB_CRYPT_READ_INCOMPLETE, |
|||
XB_CRYPT_READ_EOF, |
|||
XB_CRYPT_READ_ERROR |
|||
} xb_rcrypt_result_t; |
|||
|
|||
xb_rcrypt_result_t xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf, |
|||
size_t *olen, size_t *elen, void **iv, |
|||
size_t *ivlen, my_bool *hash_appended); |
|||
|
|||
int xb_crypt_read_close(xb_rcrypt_t *crypt); |
|||
|
|||
#endif |
@ -1,328 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013, 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption configuration file interface for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#include "common.h" |
|||
#include "xbcrypt.h" |
|||
#include "xbcrypt_common.h" |
|||
|
|||
/* Encryption options */ |
|||
char *ds_encrypt_key = NULL; |
|||
char *ds_encrypt_key_file = NULL; |
|||
ulong ds_encrypt_algo; |
|||
|
|||
static uint encrypt_key_len; |
|||
static uint encrypt_iv_len; |
|||
|
|||
static const uint encrypt_mode = GCRY_CIPHER_MODE_CTR; |
|||
|
|||
static uint encrypt_algos[] = { GCRY_CIPHER_NONE, GCRY_CIPHER_AES128, |
|||
GCRY_CIPHER_AES192, GCRY_CIPHER_AES256 }; |
|||
static uint encrypt_algo; |
|||
|
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
GCRY_THREAD_OPTION_PTHREAD_IMPL; |
|||
#endif |
|||
|
|||
|
|||
my_bool |
|||
xb_crypt_read_key_file(const char *filename, void** key, uint *keylength) |
|||
{ |
|||
FILE *fp; |
|||
|
|||
if (!(fp = my_fopen(filename, O_RDONLY, MYF(0)))) { |
|||
msg("%s:%s: unable to open config file \"%s\", errno(%d)\n", |
|||
my_progname, __FUNCTION__, filename, my_errno); |
|||
return FALSE; |
|||
} |
|||
|
|||
fseek(fp, 0 , SEEK_END); |
|||
*keylength = ftell(fp); |
|||
rewind(fp); |
|||
*key = my_malloc(*keylength, MYF(MY_FAE)); |
|||
*keylength = fread(*key, 1, *keylength, fp); |
|||
my_fclose(fp, MYF(0)); |
|||
return TRUE; |
|||
} |
|||
|
|||
void |
|||
xb_crypt_create_iv(void* ivbuf, size_t ivlen) |
|||
{ |
|||
gcry_create_nonce(ivbuf, ivlen); |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_init(uint *iv_len) |
|||
{ |
|||
gcry_error_t gcry_error; |
|||
|
|||
/* Acording to gcrypt docs (and my testing), setting up the threading |
|||
callbacks must be done first, so, lets give it a shot */ |
|||
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600) |
|||
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to set libgcrypt thread cbs - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
#endif |
|||
|
|||
/* Version check should be the very next call because it |
|||
makes sure that important subsystems are intialized. */ |
|||
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { |
|||
const char *gcrypt_version; |
|||
gcrypt_version = gcry_check_version(NULL); |
|||
/* No other library has already initialized libgcrypt. */ |
|||
if (!gcrypt_version) { |
|||
msg("encryption: failed to initialize libgcrypt\n"); |
|||
return 1; |
|||
} else { |
|||
msg("encryption: using gcrypt %s\n", gcrypt_version); |
|||
} |
|||
} |
|||
|
|||
/* Disable the gcry secure memory, not dealing with this for now */ |
|||
gcry_error = gcry_control(GCRYCTL_DISABLE_SECMEM, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to disable libgcrypt secmem - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Finalize gcry initialization. */ |
|||
gcry_error = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to finish libgcrypt initialization - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Determine the algorithm */ |
|||
encrypt_algo = encrypt_algos[ds_encrypt_algo]; |
|||
|
|||
/* Set up the iv length */ |
|||
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo); |
|||
xb_a(encrypt_iv_len > 0); |
|||
if (iv_len != NULL) { |
|||
*iv_len = encrypt_iv_len; |
|||
} |
|||
|
|||
/* Now set up the key */ |
|||
if (ds_encrypt_key == NULL && |
|||
ds_encrypt_key_file == NULL) { |
|||
msg("encryption: no encryption key or key file specified.\n"); |
|||
return gcry_error; |
|||
} else if (ds_encrypt_key && ds_encrypt_key_file) { |
|||
msg("encryption: both encryption key and key file specified.\n"); |
|||
return gcry_error; |
|||
} else if (ds_encrypt_key_file) { |
|||
if (!xb_crypt_read_key_file(ds_encrypt_key_file, |
|||
(void**)&ds_encrypt_key, |
|||
&encrypt_key_len)) { |
|||
msg("encryption: unable to read encryption key file" |
|||
" \"%s\".\n", ds_encrypt_key_file); |
|||
return gcry_error; |
|||
} |
|||
} else if (ds_encrypt_key) { |
|||
encrypt_key_len = strlen(ds_encrypt_key); |
|||
} else { |
|||
msg("encryption: no encryption key or key file specified.\n"); |
|||
return gcry_error; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle) |
|||
{ |
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
gcry_error_t gcry_error; |
|||
|
|||
gcry_error = gcry_cipher_open(cipher_handle, |
|||
encrypt_algo, |
|||
encrypt_mode, 0); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to open libgcrypt" |
|||
" cipher - %s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(*cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_setkey(*cipher_handle, |
|||
ds_encrypt_key, |
|||
encrypt_key_len); |
|||
if (gcry_error) { |
|||
msg("encryption: unable to set libgcrypt" |
|||
" cipher key - %s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(*cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
return gcry_error; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void |
|||
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle) |
|||
{ |
|||
if (encrypt_algo != GCRY_CIPHER_NONE) |
|||
gcry_cipher_close(cipher_handle); |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, |
|||
const uchar *iv, size_t iv_len, my_bool hash_appended) |
|||
{ |
|||
*to_len = from_len; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
|
|||
gcry_error_t gcry_error; |
|||
|
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to reset libgcrypt" |
|||
" cipher - %s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
if (iv_len > 0) { |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, |
|||
iv, iv_len); |
|||
} |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to set cipher iv - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
/* Try to decrypt it */ |
|||
gcry_error = gcry_cipher_decrypt(cipher_handle, to, *to_len, |
|||
from, from_len); |
|||
if (gcry_error) { |
|||
msg("%s:encryption: unable to decrypt chunk - " |
|||
"%s : %s\n", my_progname, |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
gcry_cipher_close(cipher_handle); |
|||
return gcry_error; |
|||
} |
|||
|
|||
if (hash_appended) { |
|||
uchar hash[XB_CRYPT_HASH_LEN]; |
|||
|
|||
*to_len -= XB_CRYPT_HASH_LEN; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, hash, to, |
|||
*to_len); |
|||
if (memcmp(hash, (char *) to + *to_len, |
|||
XB_CRYPT_HASH_LEN) != 0) { |
|||
msg("%s:%s invalid plaintext hash. " |
|||
"Wrong encrytion key specified?\n", |
|||
my_progname, __FUNCTION__); |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
} else { |
|||
memcpy(to, from, *to_len); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
gcry_error_t |
|||
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, uchar *iv) |
|||
{ |
|||
gcry_error_t gcry_error; |
|||
|
|||
/* ensure that XB_CRYPT_HASH_LEN is the correct length |
|||
of XB_CRYPT_HASH hashing algorithm output */ |
|||
xb_ad(gcry_md_get_algo_dlen(XB_CRYPT_HASH) == |
|||
XB_CRYPT_HASH_LEN); |
|||
|
|||
memcpy(to, from, from_len); |
|||
gcry_md_hash_buffer(XB_CRYPT_HASH, to + from_len, |
|||
from, from_len); |
|||
|
|||
*to_len = from_len; |
|||
|
|||
if (encrypt_algo != GCRY_CIPHER_NONE) { |
|||
|
|||
gcry_error = gcry_cipher_reset(cipher_handle); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to reset cipher - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
xb_crypt_create_iv(iv, encrypt_iv_len); |
|||
gcry_error = gcry_cipher_setctr(cipher_handle, iv, |
|||
encrypt_iv_len); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to set cipher ctr - " |
|||
"%s : %s\n", |
|||
gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
|
|||
gcry_error = gcry_cipher_encrypt(cipher_handle, to, |
|||
*to_len + XB_CRYPT_HASH_LEN, |
|||
to, |
|||
from_len + XB_CRYPT_HASH_LEN); |
|||
if (gcry_error) { |
|||
msg("encrypt: unable to encrypt buffer - " |
|||
"%s : %s\n", gcry_strsource(gcry_error), |
|||
gcry_strerror(gcry_error)); |
|||
return gcry_error; |
|||
} |
|||
} else { |
|||
memcpy(to, from, from_len + XB_CRYPT_HASH_LEN); |
|||
} |
|||
|
|||
*to_len += XB_CRYPT_HASH_LEN; |
|||
|
|||
return 0; |
|||
} |
|||
#endif |
@ -1,64 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2017 Percona LLC and/or its affiliates. |
|||
|
|||
Encryption datasink implementation for XtraBackup. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include <my_base.h> |
|||
#if HAVE_GCRYPT |
|||
#if GCC_VERSION >= 4002 |
|||
/* Workaround to avoid "gcry_ac_* is deprecated" warnings in gcrypt.h */ |
|||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
|||
#endif |
|||
|
|||
#include <gcrypt.h> |
|||
|
|||
extern char *ds_encrypt_key; |
|||
extern char *ds_encrypt_key_file; |
|||
extern int ds_encrypt_threads; |
|||
extern ulong ds_encrypt_algo; |
|||
|
|||
/****************************************************************************** |
|||
Utility interface */ |
|||
my_bool xb_crypt_read_key_file(const char *filename, |
|||
void** key, uint *keylength); |
|||
|
|||
void xb_crypt_create_iv(void* ivbuf, size_t ivlen); |
|||
|
|||
/* Initialize gcrypt and setup encryption key and IV lengths */ |
|||
gcry_error_t |
|||
xb_crypt_init(uint *iv_len); |
|||
|
|||
/* Setup gcrypt cipher */ |
|||
gcry_error_t |
|||
xb_crypt_cipher_open(gcry_cipher_hd_t *cipher_handle); |
|||
|
|||
/* Close gcrypt cipher */ |
|||
void |
|||
xb_crypt_cipher_close(gcry_cipher_hd_t cipher_handle); |
|||
|
|||
/* Decrypt buffer */ |
|||
gcry_error_t |
|||
xb_crypt_decrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, const uchar *iv, |
|||
size_t iv_len, my_bool hash_appended); |
|||
|
|||
/* Encrypt buffer */ |
|||
gcry_error_t |
|||
xb_crypt_encrypt(gcry_cipher_hd_t cipher_handle, const uchar *from, |
|||
size_t from_len, uchar *to, size_t *to_len, uchar *iv); |
|||
#endif |
@ -1,252 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt format reader implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include "xbcrypt.h" |
|||
#include "crc_glue.h" |
|||
|
|||
struct xb_rcrypt_struct { |
|||
void *userdata; |
|||
xb_crypt_read_callback *read; |
|||
void *buffer; |
|||
size_t bufsize; |
|||
void *ivbuffer; |
|||
size_t ivbufsize; |
|||
ulonglong offset; |
|||
}; |
|||
|
|||
xb_rcrypt_t * |
|||
xb_crypt_read_open(void *userdata, xb_crypt_read_callback *onread) |
|||
{ |
|||
xb_rcrypt_t *crypt; |
|||
|
|||
xb_ad(onread); |
|||
|
|||
crypt = (xb_rcrypt_t *) my_malloc(sizeof(xb_rcrypt_t), MYF(MY_FAE)); |
|||
|
|||
crypt->userdata = userdata; |
|||
crypt->read = onread; |
|||
crypt->buffer = NULL; |
|||
crypt->bufsize = 0; |
|||
crypt->offset = 0; |
|||
crypt->ivbuffer = NULL; |
|||
crypt->ivbufsize = 0; |
|||
return crypt; |
|||
} |
|||
|
|||
xb_rcrypt_result_t |
|||
xb_crypt_read_chunk(xb_rcrypt_t *crypt, void **buf, size_t *olen, size_t *elen, |
|||
void **iv, size_t *ivlen, my_bool *hash_appended) |
|||
|
|||
{ |
|||
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4]; |
|||
uchar *ptr; |
|||
ulonglong tmp; |
|||
ulong checksum, checksum_exp, version; |
|||
size_t bytesread; |
|||
xb_rcrypt_result_t result = XB_CRYPT_READ_CHUNK; |
|||
|
|||
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, sizeof(tmpbuf))) |
|||
!= sizeof(tmpbuf)) { |
|||
if (bytesread == 0) { |
|||
result = XB_CRYPT_READ_EOF; |
|||
goto err; |
|||
} else { |
|||
msg("%s:%s: unable to read chunk header data at " |
|||
"offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
ptr = tmpbuf; |
|||
|
|||
if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC3, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 3; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC2, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 2; |
|||
} else if (memcmp(ptr, XB_CRYPT_CHUNK_MAGIC1, |
|||
XB_CRYPT_CHUNK_MAGIC_SIZE) == 0) { |
|||
version = 1; |
|||
} else { |
|||
msg("%s:%s: wrong chunk magic at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
|
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
crypt->offset += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
tmp = uint8korr(ptr); /* reserved */ |
|||
ptr += 8; |
|||
crypt->offset += 8; |
|||
|
|||
tmp = uint8korr(ptr); /* original size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid original size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*olen = (size_t)tmp; |
|||
|
|||
tmp = uint8korr(ptr); /* encrypted size */ |
|||
ptr += 8; |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid encrypted size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*elen = (size_t)tmp; |
|||
|
|||
checksum_exp = uint4korr(ptr); /* checksum */ |
|||
ptr += 4; |
|||
crypt->offset += 4; |
|||
|
|||
/* iv size */ |
|||
if (version == 1) { |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
} else { |
|||
if ((bytesread = crypt->read(crypt->userdata, tmpbuf, 8)) |
|||
!= 8) { |
|||
if (bytesread == 0) { |
|||
result = XB_CRYPT_READ_EOF; |
|||
goto err; |
|||
} else { |
|||
msg("%s:%s: unable to read chunk iv size at " |
|||
"offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
tmp = uint8korr(tmpbuf); |
|||
if (tmp > INT_MAX) { |
|||
msg("%s:%s: invalid iv size at offset 0x%llx.\n", |
|||
my_progname, __FUNCTION__, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->offset += 8; |
|||
*ivlen = (size_t)tmp; |
|||
} |
|||
|
|||
if (*ivlen > crypt->ivbufsize) { |
|||
crypt->ivbuffer = my_realloc(crypt->ivbuffer, *ivlen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
if (crypt->ivbuffer == NULL) { |
|||
msg("%s:%s: failed to increase iv buffer to " |
|||
"%llu bytes.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*ivlen); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->ivbufsize = *ivlen; |
|||
} |
|||
|
|||
if (*ivlen > 0) { |
|||
if (crypt->read(crypt->userdata, crypt->ivbuffer, *ivlen) |
|||
!= *ivlen) { |
|||
msg("%s:%s: failed to read %lld bytes for chunk iv " |
|||
"at offset 0x%llx.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*ivlen, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
*iv = crypt->ivbuffer; |
|||
} |
|||
|
|||
/* for version euqals 2 we need to read in the iv data but do not init |
|||
CTR with it */ |
|||
if (version == 2) { |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
} |
|||
|
|||
if (*olen > crypt->bufsize) { |
|||
crypt->buffer = my_realloc(crypt->buffer, *olen, |
|||
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); |
|||
if (crypt->buffer == NULL) { |
|||
msg("%s:%s: failed to increase buffer to " |
|||
"%llu bytes.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*olen); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
crypt->bufsize = *olen; |
|||
} |
|||
|
|||
if (*elen > 0) { |
|||
if (crypt->read(crypt->userdata, crypt->buffer, *elen) |
|||
!= *elen) { |
|||
msg("%s:%s: failed to read %lld bytes for chunk payload " |
|||
"at offset 0x%llx.\n", my_progname, __FUNCTION__, |
|||
(ulonglong)*elen, crypt->offset); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
} |
|||
|
|||
checksum = crc32_iso3309(0, crypt->buffer, *elen); |
|||
if (checksum != checksum_exp) { |
|||
msg("%s:%s invalid checksum at offset 0x%llx, " |
|||
"expected 0x%lx, actual 0x%lx.\n", my_progname, __FUNCTION__, |
|||
crypt->offset, checksum_exp, checksum); |
|||
result = XB_CRYPT_READ_ERROR; |
|||
goto err; |
|||
} |
|||
|
|||
crypt->offset += *elen; |
|||
*buf = crypt->buffer; |
|||
|
|||
*hash_appended = version > 2; |
|||
|
|||
goto exit; |
|||
|
|||
err: |
|||
*buf = NULL; |
|||
*olen = 0; |
|||
*elen = 0; |
|||
*ivlen = 0; |
|||
*iv = 0; |
|||
exit: |
|||
return result; |
|||
} |
|||
|
|||
int xb_crypt_read_close(xb_rcrypt_t *crypt) |
|||
{ |
|||
if (crypt->buffer) |
|||
my_free(crypt->buffer); |
|||
if (crypt->ivbuffer) |
|||
my_free(crypt->ivbuffer); |
|||
my_free(crypt); |
|||
|
|||
return 0; |
|||
} |
|||
|
@ -1,105 +0,0 @@ |
|||
/****************************************************** |
|||
Copyright (c) 2013 Percona LLC and/or its affiliates. |
|||
|
|||
The xbcrypt format writer implementation. |
|||
|
|||
This program is free software; you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation; version 2 of the License. |
|||
|
|||
This program is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with this program; if not, write to the Free Software |
|||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|||
|
|||
*******************************************************/ |
|||
|
|||
#include "xbcrypt.h" |
|||
#include "crc_glue.h" |
|||
|
|||
struct xb_wcrypt_struct { |
|||
void *userdata; |
|||
xb_crypt_write_callback *write; |
|||
}; |
|||
|
|||
xb_wcrypt_t * |
|||
xb_crypt_write_open(void *userdata, xb_crypt_write_callback *onwrite) |
|||
{ |
|||
xb_wcrypt_t *crypt; |
|||
|
|||
xb_ad(onwrite); |
|||
|
|||
crypt = (xb_wcrypt_t *) my_malloc(sizeof(xb_wcrypt_t), MYF(MY_FAE)); |
|||
|
|||
crypt->userdata = userdata; |
|||
crypt->write = onwrite; |
|||
|
|||
return crypt; |
|||
} |
|||
|
|||
int xb_crypt_write_chunk(xb_wcrypt_t *crypt, const void *buf, size_t olen, |
|||
size_t elen, const void *iv, size_t ivlen) |
|||
{ |
|||
uchar tmpbuf[XB_CRYPT_CHUNK_MAGIC_SIZE + 8 + 8 + 8 + 4 + 8]; |
|||
uchar *ptr; |
|||
ulong checksum; |
|||
|
|||
xb_ad(olen <= INT_MAX); |
|||
if (olen > INT_MAX) |
|||
return 0; |
|||
|
|||
xb_ad(elen <= INT_MAX); |
|||
if (elen > INT_MAX) |
|||
return 0; |
|||
|
|||
xb_ad(ivlen <= INT_MAX); |
|||
if (ivlen > INT_MAX) |
|||
return 0; |
|||
|
|||
ptr = tmpbuf; |
|||
|
|||
memcpy(ptr, XB_CRYPT_CHUNK_MAGIC_CURRENT, XB_CRYPT_CHUNK_MAGIC_SIZE); |
|||
ptr += XB_CRYPT_CHUNK_MAGIC_SIZE; |
|||
|
|||
int8store(ptr, (ulonglong)0); /* reserved */ |
|||
ptr += 8; |
|||
|
|||
int8store(ptr, (ulonglong)olen); /* original size */ |
|||
ptr += 8; |
|||
|
|||
int8store(ptr, (ulonglong)elen); /* encrypted (actual) size */ |
|||
ptr += 8; |
|||
|
|||
checksum = crc32_iso3309(0, buf, elen); |
|||
int4store(ptr, checksum); /* checksum */ |
|||
ptr += 4; |
|||
|
|||
int8store(ptr, (ulonglong)ivlen); /* iv size */ |
|||
ptr += 8; |
|||
|
|||
xb_ad(ptr <= tmpbuf + sizeof(tmpbuf)); |
|||
|
|||
if (crypt->write(crypt->userdata, tmpbuf, ptr-tmpbuf) == -1) |
|||
return 1; |
|||
|
|||
if (crypt->write(crypt->userdata, iv, ivlen) == -1) |
|||
return 1; |
|||
|
|||
if (crypt->write(crypt->userdata, buf, elen) == -1) |
|||
return 1; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int xb_crypt_write_close(xb_wcrypt_t *crypt) |
|||
{ |
|||
my_free(crypt); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
808
extra/mariabackup/xtrabackup.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue