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_MAGIC2, 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(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; }
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; }
/************************************************************************ Create a datasink of the specified type */ ds_ctxt_t * ds_create(const char *root, ds_type_t type) { datasink_t *ds; ds_ctxt_t *ctxt; switch (type) { case DS_TYPE_STDOUT: ds = &datasink_stdout; break; case DS_TYPE_LOCAL: ds = &datasink_local; break; case DS_TYPE_ARCHIVE: ds = &datasink_archive; break; case DS_TYPE_XBSTREAM: ds = &datasink_xbstream; break; case DS_TYPE_COMPRESS: ds = &datasink_compress; break; case DS_TYPE_ENCRYPT: ds = &datasink_encrypt; break; case DS_TYPE_TMPFILE: ds = &datasink_tmpfile; break; case DS_TYPE_BUFFER: ds = &datasink_buffer; break; default: msg("Unknown datasink type: %d\n", type); xb_ad(0); return NULL; } ctxt = ds->init(root); if (ctxt != NULL) { ctxt->datasink = ds; } else { msg("Error: failed to initialize datasink.\n"); exit(EXIT_FAILURE); } return ctxt; }
xb_rstream_result_t xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk) { uchar tmpbuf[16]; uchar *ptr = tmpbuf; uint pathlen; size_t tlen; size_t tbytes; ulonglong ullval; ulong checksum_exp; ulong checksum;; File fd = stream->fd; xb_ad(sizeof(tmpbuf) >= CHUNK_HEADER_CONSTANT_LEN); /* This is the only place where we expect EOF, so read with my_read() rather than F_READ() */ tlen = CHUNK_HEADER_CONSTANT_LEN; while (tlen > 0) { tbytes = my_read(fd, ptr, tlen, MYF(MY_WME)); if (tbytes == 0) { break; } ptr += tbytes; tlen -= tbytes; } if (tlen == CHUNK_HEADER_CONSTANT_LEN) { return XB_STREAM_READ_EOF; } else if (tlen > 0) { msg("xb_stream_read_chunk(): unexpected end of stream at " "offset 0x%llx.\n", stream->offset); goto err; } ptr = tmpbuf; /* Chunk magic value */ if (memcmp(tmpbuf, XB_STREAM_CHUNK_MAGIC, 8)) { msg("xb_stream_read_chunk(): wrong chunk magic at offset " "0x%llx.\n", (ulonglong) stream->offset); goto err; } ptr += 8; stream->offset += 8; /* Chunk flags */ chunk->flags = *ptr++; stream->offset++; /* Chunk type, ignore unknown ones if ignorable flag is set */ chunk->type = validate_chunk_type(*ptr); if (chunk->type == XB_CHUNK_TYPE_UNKNOWN && !(chunk->flags & XB_STREAM_FLAG_IGNORABLE)) { msg("xb_stream_read_chunk(): unknown chunk type 0x%lu at " "offset 0x%llx.\n", (ulong) *ptr, (ulonglong) stream->offset); goto err; } ptr++; stream->offset++; /* Path length */ pathlen = uint4korr(ptr); if (pathlen >= FN_REFLEN) { msg("xb_stream_read_chunk(): path length (%lu) is too large at " "offset 0x%llx.\n", (ulong) pathlen, stream->offset); goto err; } chunk->pathlen = pathlen; stream->offset +=4; xb_ad((ptr + 4 - tmpbuf) == CHUNK_HEADER_CONSTANT_LEN); /* Path */ if (chunk->pathlen > 0) { F_READ((uchar *) chunk->path, pathlen); stream->offset += pathlen; } chunk->path[pathlen] = '\0'; if (chunk->type == XB_CHUNK_TYPE_EOF) { return XB_STREAM_READ_CHUNK; } /* Payload length */ F_READ(tmpbuf, 16); ullval = uint8korr(tmpbuf); if (ullval > (ulonglong) SIZE_T_MAX) { msg("xb_stream_read_chunk(): chunk length is too large at " "offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, ullval); goto err; } chunk->length = (size_t) ullval; stream->offset += 8; /* Payload offset */ ullval = uint8korr(tmpbuf + 8); if (ullval > (ulonglong) MY_OFF_T_MAX) { msg("xb_stream_read_chunk(): chunk offset is too large at " "offset 0x%llx: 0x%llx.\n", (ulonglong) stream->offset, ullval); goto err; } chunk->offset = (my_off_t) ullval; stream->offset += 8; /* Reallocate the buffer if needed */ if (chunk->length > stream->buflen) { stream->buffer = my_realloc(stream->buffer, chunk->length, MYF(MY_WME)); if (stream->buffer == NULL) { msg("xb_stream_read_chunk(): failed to increase buffer " "to %lu bytes.\n", (ulong) chunk->length); goto err; } stream->buflen = chunk->length; } /* Checksum */ F_READ(tmpbuf, 4); checksum_exp = uint4korr(tmpbuf); /* Payload */ if (chunk->length > 0) { F_READ(stream->buffer, chunk->length); stream->offset += chunk->length; } checksum = crc32(0, stream->buffer, chunk->length); if (checksum != checksum_exp) { msg("xb_stream_read_chunk(): invalid checksum at offset " "0x%llx: expected 0x%lx, read 0x%lx.\n", (ulonglong) stream->offset, checksum_exp, checksum); goto err; } stream->offset += 4; chunk->data = stream->buffer; chunk->checksum = checksum; return XB_STREAM_READ_CHUNK; err: return XB_STREAM_READ_ERROR; }