summaryrefslogtreecommitdiff
path: root/extra/mariabackup/xbcrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'extra/mariabackup/xbcrypt.c')
-rw-r--r--extra/mariabackup/xbcrypt.c696
1 files changed, 696 insertions, 0 deletions
diff --git a/extra/mariabackup/xbcrypt.c b/extra/mariabackup/xbcrypt.c
new file mode 100644
index 00000000000..3da70e171f7
--- /dev/null
+++ b/extra/mariabackup/xbcrypt.c
@@ -0,0 +1,696 @@
+/******************************************************
+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);
+}