diff options
Diffstat (limited to 'extra/mariabackup/xbcrypt_read.c')
-rw-r--r-- | extra/mariabackup/xbcrypt_read.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/extra/mariabackup/xbcrypt_read.c b/extra/mariabackup/xbcrypt_read.c new file mode 100644 index 00000000000..41790c7035d --- /dev/null +++ b/extra/mariabackup/xbcrypt_read.c @@ -0,0 +1,252 @@ +/****************************************************** +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; +} + |