/* * Copyright (C) 2017, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #include #include #include #include static int check_filetype(int fd, struct stat *sb, const char *filename) { fstat(fd, sb); /* Do not return an error in case we cannot validate the data. */ if ((sb->st_mode & S_IFMT) != S_IFREG && (sb->st_mode & S_IFMT) != S_IFLNK) { fprintf(stderr, "%s is no regular file or symlink\n", filename); return -EINVAL; } return 0; } static int crypt(struct kcapi_handle *handle, const uint8_t *iv, const char *infile, const char *outfile) { int infd = -1, outfd = -1; int ret = 0; struct stat insb, outsb; uint8_t *inmem = NULL, *outmem = NULL; size_t outsize; infd = open(infile, O_RDONLY | O_CLOEXEC); if (infd < 0) { fprintf(stderr, "Cannot open file %s: %s\n", infile, strerror(errno)); return -EIO; } outfd = open(outfile, O_RDWR | O_CLOEXEC | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); if (outfd < 0) { fprintf(stderr, "Cannot open file %s: %s\n", infile, strerror(errno)); ret = -EIO; goto out; } ret = check_filetype(infd, &insb, infile); if (ret) goto out; ret = check_filetype(outfd, &outsb, outfile); if (ret) goto out; if (insb.st_size) { inmem = mmap(NULL, insb.st_size, PROT_READ, MAP_SHARED, infd, 0); if (inmem == MAP_FAILED) { fprintf(stderr, "Use of mmap failed\n"); ret = -ENOMEM; goto out; } } outsize = ((insb.st_size + kcapi_cipher_blocksize(handle) - 1) / kcapi_cipher_blocksize(handle)) * kcapi_cipher_blocksize(handle); ret = ftruncate(outfd, outsize); if (ret) goto out; if (outsize) { outmem = mmap(NULL, outsize, PROT_WRITE, MAP_SHARED, outfd, 0); if (outmem == MAP_FAILED) { fprintf(stderr, "Use of mmap failed\n"); ret = -ENOMEM; goto out; } } #if 1 /* Send all data in one go, libkcapi will not loop */ struct iovec iniov, outiov; iniov.iov_base = inmem; iniov.iov_len = insb.st_size; outiov.iov_base = outmem; outiov.iov_len = outsize; ret = kcapi_cipher_stream_init_enc(handle, iv, NULL, 0); if (ret) goto out; ret = kcapi_cipher_stream_update(handle, &iniov, 1); if (ret) goto out; ret = kcapi_cipher_stream_op(handle, &outiov, 1); #else /* libkcapi will loop over the data and send it in chunks */ ret = kcapi_cipher_encrypt(handle, inmem, insb.st_size, iv, outmem, outsize, KCAPI_ACCESS_SENDMSG); #endif out: if (inmem && inmem != MAP_FAILED) munmap(inmem, insb.st_size); if (outmem && outmem != MAP_FAILED) munmap(outmem, outsize); if (infd >= 0) close(infd); if (outfd >= 0) close(outfd); return ret; } int main(int argc, char *argv[]) { struct kcapi_handle *handle = NULL; int ret; if (argc != 3) { fprintf(stderr, "infile, outfile required\n"); return -EINVAL; } /* with CTR mode, we can skip any padding */ ret = kcapi_cipher_init(&handle, "ctr(aes)", 0); if (ret) return ret; ret = kcapi_cipher_setkey(handle, (uint8_t *)"0123456789012345", 16); if (ret) goto out; ret = crypt(handle, (uint8_t *)"0123456789012345", argv[1], argv[2]); if (ret > 0) { fprintf(stderr, "%d bytes of ciphertext created\n", ret); ret = 0; } else { fprintf(stderr, "encryption failed with error %d\n", ret); } out: kcapi_cipher_destroy(handle); return ret; }