1
/******************************************************
2
Copyright (c) 2011 Percona Ireland Ltd.
4
The xbcrypt utility: decrypt files in the XBCRYPT format.
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; version 2 of the License.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*******************************************************/
22
#include <my_getopt.h>
27
GCRY_THREAD_OPTION_PTHREAD_IMPL;
29
#define XBCRYPT_VERSION "1.0"
37
const char *xbcrypt_encrypt_algo_names[] =
38
{ "NONE", "AES128", "AES192", "AES256", NullS};
39
TYPELIB xbcrypt_encrypt_algo_typelib=
40
{array_elements(xbcrypt_encrypt_algo_names)-1,"",
41
xbcrypt_encrypt_algo_names, NULL};
43
static run_mode_t opt_run_mode = RUN_MODE_ENCRYPT;
44
static char *opt_input_file = NULL;
45
static char *opt_output_file = NULL;
46
static ulong opt_encrypt_algo;
47
static char *opt_encrypt_key_file = NULL;
48
static void *opt_encrypt_key = NULL;
49
static ulonglong opt_encrypt_chunk_size = 0;
50
static my_bool opt_verbose = FALSE;
52
static uint encrypt_algos[] = { GCRY_CIPHER_NONE,
56
static int encrypt_algo = 0;
57
static int encrypt_mode = GCRY_CIPHER_MODE_CTR;
58
static uint encrypt_key_len = 0;
59
static const unsigned char encrypt_iv[] =
60
"Percona Xtrabackup is Awesome!!!";
61
static size_t encrypt_iv_len = 0;
63
static struct my_option my_long_options[] =
65
{"help", '?', "Display this help and exit.",
66
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
68
{"decrypt", 'd', "Decrypt data input to output.",
70
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
72
{"input", 'i', "Optional input file. If not specified, input"
73
" will be read from standard input.",
74
&opt_input_file, &opt_input_file, 0,
75
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
77
{"output", 'o', "Optional output file. If not specified, output"
78
" will be written to standard output.",
79
&opt_output_file, &opt_output_file, 0,
80
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
82
{"encrypt-algo", 'a', "Encryption algorithm.",
83
&opt_encrypt_algo, &opt_encrypt_algo, &xbcrypt_encrypt_algo_typelib,
84
GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86
{"encrypt-key", 'k', "Encryption key.",
87
&opt_encrypt_key, &opt_encrypt_key, 0,
88
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
90
{"encrypt-key-file", 'f', "File which contains encryption key.",
91
&opt_encrypt_key_file, &opt_encrypt_key_file, 0,
92
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
94
{"encrypt-chunk-size", 's', "Size of working buffer for encryption in"
95
" bytes. The default value is 64K.",
96
&opt_encrypt_chunk_size, &opt_encrypt_chunk_size, 0,
97
GET_ULL, REQUIRED_ARG, (1 << 16), 1024, ULONGLONG_MAX, 0, 0, 0},
99
{"verbose", 'v', "Display verbose status output.",
100
&opt_verbose, &opt_verbose,
101
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
102
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
107
get_options(int *argc, char ***argv);
111
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
112
char *argument __attribute__((unused)));
124
mode_decrypt(File filein, File fileout);
128
mode_encrypt(File filein, File fileout);
131
main(int argc, char **argv)
133
gcry_error_t gcry_error;
139
if (get_options(&argc, &argv)) {
143
/* Acording to gcrypt docs (and my testing), setting up the threading
144
callbacks must be done first, so, lets give it a shot */
145
gcry_error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
147
msg("%s: unable to set libgcrypt thread cbs - "
148
"%s : %s\n", my_progname,
149
gcry_strsource(gcry_error),
150
gcry_strerror(gcry_error));
154
/* Version check should be the very first call because it
155
makes sure that important subsystems are intialized. */
156
if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) {
157
const char *gcrypt_version;
158
gcrypt_version = gcry_check_version(NULL);
159
/* No other library has already initialized libgcrypt. */
160
if (!gcrypt_version) {
161
msg("%s: failed to initialize libgcrypt\n",
164
} else if (opt_verbose) {
165
msg("%s: using gcrypt %s\n", my_progname,
169
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
170
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
172
/* Determine the algorithm */
173
encrypt_algo = encrypt_algos[opt_encrypt_algo];
175
/* Set up the iv length */
176
encrypt_iv_len = gcry_cipher_get_algo_blklen(encrypt_algo);
178
/* Now set up the key */
179
if (opt_encrypt_key == NULL && opt_encrypt_key_file == NULL) {
180
msg("%s: no encryption key or key file specified.\n",
183
} else if (opt_encrypt_key && opt_encrypt_key_file) {
184
msg("%s: both encryption key and key file specified.\n",
187
} else if (opt_encrypt_key_file) {
188
if (!xb_crypt_read_key_file(opt_encrypt_key_file,
191
msg("%s: unable to read encryption key file \"%s\".\n",
192
opt_encrypt_key_file, my_progname);
196
encrypt_key_len = strlen(opt_encrypt_key);
199
if (opt_input_file) {
203
msg("%s: input file \"%s\".\n", my_progname,
206
if (my_stat(opt_input_file, &mystat, MYF(MY_WME)) == NULL) {
209
if (!MY_S_ISREG(mystat.st_mode)) {
210
msg("%s: \"%s\" is not a regular file, exiting.\n",
211
my_progname, opt_input_file);
214
if ((filein = my_open(opt_input_file, O_RDONLY, MYF(MY_WME)))
216
msg("%s: failed to open \"%s\".\n", my_progname,
222
msg("%s: input from standard input.\n", my_progname);
223
filein = fileno(stdin);
226
if (opt_output_file) {
228
msg("%s: output file \"%s\".\n", my_progname,
231
if ((fileout = my_create(opt_output_file, 0,
232
O_WRONLY|O_BINARY|O_EXCL|O_NOFOLLOW,
234
msg("%s: failed to create output file \"%s\".\n",
235
my_progname, opt_output_file);
240
msg("%s: output to standard output.\n", my_progname);
241
fileout = fileno(stdout);
244
if (opt_run_mode == RUN_MODE_DECRYPT
245
&& mode_decrypt(filein, fileout)) {
247
} else if (opt_run_mode == RUN_MODE_ENCRYPT
248
&& mode_encrypt(filein, fileout)) {
252
if (opt_input_file && filein) {
253
my_close(filein, MYF(MY_WME));
255
if (opt_output_file && fileout) {
256
my_close(fileout, MYF(MY_WME));
259
my_cleanup_options(my_long_options);
265
if (opt_input_file && filein) {
266
my_close(filein, MYF(MY_WME));
268
if (opt_output_file && fileout) {
269
my_close(fileout, MYF(MY_WME));
272
my_cleanup_options(my_long_options);
283
my_xb_crypt_read_callback(void *userdata, void *buf, size_t len)
285
File* file = (File *) userdata;
286
return my_read(*file, buf, len, MYF(MY_WME));
291
mode_decrypt(File filein, File fileout)
293
xb_rcrypt_t *xbcrypt_file = NULL;
294
void *chunkbuf = NULL;
297
void *decryptbuf = NULL;
298
size_t decryptbufsize = 0;
299
ulonglong ttlchunksread = 0;
300
ulonglong ttlbytesread = 0;
301
xb_rcrypt_result_t result;
302
gcry_cipher_hd_t cipher_handle;
303
gcry_error_t gcry_error;
305
if (encrypt_algo != GCRY_CIPHER_NONE) {
306
gcry_error = gcry_cipher_open(&cipher_handle,
310
msg("%s:decrypt: unable to open libgcrypt"
311
" cipher - %s : %s\n", my_progname,
312
gcry_strsource(gcry_error),
313
gcry_strerror(gcry_error));
317
gcry_error = gcry_cipher_setkey(cipher_handle,
321
msg("%s:decrypt: unable to set libgcrypt cipher"
322
"key - %s : %s\n", my_progname,
323
gcry_strsource(gcry_error),
324
gcry_strerror(gcry_error));
329
/* Initialize the xb_crypt format reader */
330
xbcrypt_file = xb_crypt_read_open(&filein, my_xb_crypt_read_callback);
331
if (xbcrypt_file == NULL) {
332
msg("%s:decrypt: xb_crypt_read_open() failed.\n", my_progname);
336
/* Walk the encrypted chunks, decrypting them and writing out */
337
while ((result = xb_crypt_read_chunk(xbcrypt_file, &chunkbuf,
338
&originalsize, &chunksize))
339
== XB_CRYPT_READ_CHUNK) {
341
if (encrypt_algo != GCRY_CIPHER_NONE) {
342
gcry_error = gcry_cipher_reset(cipher_handle);
344
msg("%s:decrypt: unable to reset libgcrypt"
345
" cipher - %s : %s\n", my_progname,
346
gcry_strsource(gcry_error),
347
gcry_strerror(gcry_error));
351
gcry_error = gcry_cipher_setiv(cipher_handle,
355
msg("%s:decrypt: unable to set cipher iv - "
356
"%s : %s\n", my_progname,
357
gcry_strsource(gcry_error),
358
gcry_strerror(gcry_error));
362
if (decryptbufsize < originalsize) {
363
if (decryptbufsize) {
364
decryptbuf = my_realloc(decryptbuf,
367
decryptbufsize = originalsize;
369
decryptbuf = my_malloc(originalsize,
371
decryptbufsize = originalsize;
375
/* Try to decrypt it */
376
gcry_error = gcry_cipher_decrypt(cipher_handle,
382
msg("%s:decrypt: unable to decrypt chunk - "
383
"%s : %s\n", my_progname,
384
gcry_strsource(gcry_error),
385
gcry_strerror(gcry_error));
386
gcry_cipher_close(cipher_handle);
391
decryptbuf = chunkbuf;
395
if (my_write(fileout, decryptbuf, originalsize,
396
MYF(MY_WME | MY_NABP))) {
397
msg("%s:decrypt: unable to write output chunk.\n",
402
ttlbytesread += chunksize;
404
msg("%s:decrypt: %llu chunks read, %llu bytes read\n.",
405
my_progname, ttlchunksread, ttlbytesread);
408
xb_crypt_read_close(xbcrypt_file);
410
if (encrypt_algo != GCRY_CIPHER_NONE)
411
gcry_cipher_close(cipher_handle);
413
if (decryptbuf && decryptbufsize)
417
msg("\n%s:decrypt: done\n", my_progname);
422
xb_crypt_read_close(xbcrypt_file);
424
if (encrypt_algo != GCRY_CIPHER_NONE)
425
gcry_cipher_close(cipher_handle);
427
if (decryptbuf && decryptbufsize)
435
my_xb_crypt_write_callback(void *userdata, const void *buf, size_t len)
437
File* file = (File *) userdata;
439
ssize_t ret = my_write(*file, buf, len, MYF(MY_WME));
440
posix_fadvise(*file, 0, 0, POSIX_FADV_DONTNEED);
446
mode_encrypt(File filein, File fileout)
450
void *chunkbuf = NULL;
451
size_t encryptbuflen = 0;
452
size_t encryptedlen = 0;
453
void *encryptbuf = NULL;
454
ulonglong ttlchunkswritten = 0;
455
ulonglong ttlbyteswritten = 0;
456
xb_wcrypt_t *xbcrypt_file = NULL;
457
gcry_cipher_hd_t cipher_handle;
458
gcry_error_t gcry_error;
460
if (encrypt_algo != GCRY_CIPHER_NONE) {
461
gcry_error = gcry_cipher_open(&cipher_handle,
465
msg("%s:encrypt: unable to open libgcrypt cipher - "
466
"%s : %s\n", my_progname,
467
gcry_strsource(gcry_error),
468
gcry_strerror(gcry_error));
472
gcry_error = gcry_cipher_setkey(cipher_handle,
476
msg("%s:encrypt: unable to set libgcrypt cipher key - "
477
"%s : %s\n", my_progname,
478
gcry_strsource(gcry_error),
479
gcry_strerror(gcry_error));
484
posix_fadvise(filein, 0, 0, POSIX_FADV_SEQUENTIAL);
486
xbcrypt_file = xb_crypt_write_open(&fileout,
487
my_xb_crypt_write_callback);
488
if (xbcrypt_file == NULL) {
489
msg("%s:encrypt: xb_crypt_write_open() failed.\n",
494
/* now read in data in chunk size, encryptand write out */
495
chunkbuflen = opt_encrypt_chunk_size;
496
chunkbuf = my_malloc(chunkbuflen, MYF(MY_FAE));
497
while ((bytesread = my_read(filein, chunkbuf, chunkbuflen,
500
if (encrypt_algo != GCRY_CIPHER_NONE) {
501
gcry_error = gcry_cipher_reset(cipher_handle);
504
msg("%s:encrypt: unable to reset cipher - "
505
"%s : %s\n", my_progname,
506
gcry_strsource(gcry_error),
507
gcry_strerror(gcry_error));
510
gcry_error = gcry_cipher_setiv(cipher_handle,
515
msg("%s:encrypt: unable to set cipher iv - "
516
"%s : %s\n", my_progname,
517
gcry_strsource(gcry_error),
518
gcry_strerror(gcry_error));
522
if (encryptbuflen < bytesread) {
524
encryptbuf = my_realloc(encryptbuf,
527
encryptbuflen = bytesread;
529
encryptbuf = my_malloc(bytesread,
531
encryptbuflen = bytesread;
535
gcry_error = gcry_cipher_encrypt(cipher_handle,
541
encryptedlen = bytesread;
544
msg("%s:encrypt: unable to encrypt chunk - "
545
"%s : %s\n", my_progname,
546
gcry_strsource(gcry_error),
547
gcry_strerror(gcry_error));
548
gcry_cipher_close(cipher_handle);
552
encryptedlen = bytesread;
553
encryptbuf = chunkbuf;
556
if (xb_crypt_write_chunk(xbcrypt_file, encryptbuf, bytesread, encryptedlen)) {
557
msg("%s:encrypt: abcrypt_write_chunk() failed.\n",
563
ttlbyteswritten += encryptedlen;
566
msg("%s:encrypt: %llu chunks written, %llu bytes "
567
"written\n.", my_progname, ttlchunkswritten,
573
if (encryptbuf && encryptbuflen)
576
xb_crypt_write_close(xbcrypt_file);
578
if (encrypt_algo != GCRY_CIPHER_NONE)
579
gcry_cipher_close(cipher_handle);
582
msg("\n%s:encrypt: done\n", my_progname);
589
if (encryptbuf && encryptbuflen)
593
xb_crypt_write_close(xbcrypt_file);
595
if (encrypt_algo != GCRY_CIPHER_NONE)
596
gcry_cipher_close(cipher_handle);
603
get_options(int *argc, char ***argv)
607
if ((ho_error= handle_options(argc, argv, my_long_options,
617
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
618
char *argument __attribute__((unused)))
622
opt_run_mode = RUN_MODE_DECRYPT;
636
printf("%s Ver %s for %s (%s)\n", my_progname, XBCRYPT_VERSION,
637
SYSTEM_TYPE, MACHINE_TYPE);
645
puts("Copyright (C) 2011 Percona Inc.");
646
puts("This software comes with ABSOLUTELY NO WARRANTY. "
647
"This is free software,\nand you are welcome to modify and "
648
"redistribute it under the GPL license.\n");
650
puts("Encrypt or decrypt files in the XBCRYPT format.\n");
653
printf(" %s [OPTIONS...]"
654
" # read data from specified input, encrypting or decrypting "
655
" and writing the result to the specified output.\n",
658
my_print_help(my_long_options);