From: Alain Spineux Date: Thu, 5 May 2022 08:49:00 +0000 (+0200) Subject: New Block crypto functions and types for Volume encryption X-Git-Tag: Beta-15.0.0~405 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=098b18b5027e8aa058b4c61f3ab6f7d4c134b8f5;p=thirdparty%2Fbacula.git New Block crypto functions and types for Volume encryption - encapsulate openssl API - include a unittest to show how to use and test it --- diff --git a/bacula/src/lib/crypto.c b/bacula/src/lib/crypto.c index d6c64b3ef..fd60564a0 100644 --- a/bacula/src/lib/crypto.c +++ b/bacula/src/lib/crypto.c @@ -1714,3 +1714,155 @@ const char *crypto_strerror(crypto_error_t error) { return _("Unknown error"); } } + +struct block_cipher_context +{ + int type; + int key_length; + int iv_length; + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *cipher; + unsigned char *key; + unsigned char *iv; +}; + +/* A cheap openssl handler */ +static void reportOpenSSLErrors() +{ + char buf[256]; + unsigned long e = ERR_peek_error(); + Dmsg2(1, "Block cipher error: Openssl ERROR %lu %s\n", e, ERR_error_string(e, buf)); +} + +BLOCK_CIPHER_CONTEXT *block_cipher_context_new(block_cipher_type blk_type) +{ + BLOCK_CIPHER_CONTEXT *blk_ctx; + + if (blk_type<=BLOCK_CIPHER_NONE || BLOCK_CIPHER_LAST<=blk_type) { + Dmsg1(1, "Block cipher error: invalid cipher %d\n", blk_type); + return NULL; + } + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + reportOpenSSLErrors(); + return NULL; + } + + blk_ctx = (BLOCK_CIPHER_CONTEXT *)malloc(sizeof(BLOCK_CIPHER_CONTEXT)); + memset(blk_ctx, '\0', sizeof(BLOCK_CIPHER_CONTEXT)); + blk_ctx->type = blk_type; + blk_ctx->ctx = ctx; + EVP_CIPHER_CTX_set_padding(blk_ctx->ctx, 1); // already the openssl default + switch (blk_type) { + case BLOCK_CIPHER_NULL: + blk_ctx->cipher = NULL; + blk_ctx->key_length = 16; + blk_ctx->iv_length = 16; // ATTN min size block_cipher_init_iv_header() + break; + case BLOCK_CIPHER_AES_128_XTS: + blk_ctx->cipher = EVP_aes_128_xts(); + blk_ctx->key_length = EVP_CIPHER_key_length(blk_ctx->cipher); // 32 bytes + blk_ctx->iv_length = EVP_CIPHER_iv_length(blk_ctx->cipher); // 16 bytes + break; + case BLOCK_CIPHER_AES_256_XTS: + blk_ctx->cipher = EVP_aes_256_xts(); + blk_ctx->key_length = EVP_CIPHER_key_length(blk_ctx->cipher); // 64 bytes + blk_ctx->iv_length = EVP_CIPHER_iv_length(blk_ctx->cipher); // 16 bytes + break; + default: + ASSERT2(0, "unknown block cipher"); + } + ASSERT(blk_ctx->iv_length >= 12); // (BlockNum, VolSessionId, VolSessionTime) + blk_ctx->key = (unsigned char*)malloc(blk_ctx->key_length); + blk_ctx->iv = (unsigned char*)malloc(blk_ctx->iv_length); + return blk_ctx; +} + +void block_cipher_context_free(BLOCK_CIPHER_CONTEXT *blk_ctx) +{ + EVP_CIPHER_CTX_free(blk_ctx->ctx); + free(blk_ctx->key); + free(blk_ctx->iv); + free(blk_ctx); + return; +} + +void block_cipher_init_key(BLOCK_CIPHER_CONTEXT *blk_ctx, const unsigned char *key) +{ + memcpy(blk_ctx->key, key, blk_ctx->key_length); +} + +void block_cipher_init_iv(BLOCK_CIPHER_CONTEXT *blk_ctx, const unsigned char *iv) +{ + memcpy(blk_ctx->iv, iv, blk_ctx->iv_length); +} + +void block_cipher_init_iv_header(BLOCK_CIPHER_CONTEXT *blk_ctx, uint32_t BlockNumber, uint32_t VolSessionId, uint32_t VolSessionTime) +{ + ser_declare; + ser_begin(blk_ctx->iv, 3*sizeof(uint32_t)); + ser_uint32(BlockNumber); + ser_uint32(VolSessionId); + ser_uint32(VolSessionTime); + memset(blk_ctx->iv+3*sizeof(uint32_t), '\0', blk_ctx->iv_length-3*sizeof(uint32_t)); +} + +int block_cipher_encrypt(BLOCK_CIPHER_CONTEXT *blk_ctx, int len, const char *src, char *dst) +{ + int ret; + if (blk_ctx->type == BLOCK_CIPHER_NULL) { + memcpy(dst, src, len); + return 0; + } + ret = EVP_EncryptInit_ex(blk_ctx->ctx, blk_ctx->cipher, NULL, blk_ctx->key, blk_ctx->iv); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + int outl1, outl2; + ret = EVP_EncryptUpdate(blk_ctx->ctx, (unsigned char *)dst, &outl1, (const unsigned char *)src, len); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + ret = EVP_EncryptFinal_ex(blk_ctx->ctx, (unsigned char *)dst + outl1, &outl2); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + ASSERTD(outl1+outl2==len, "unexpected encryption length"); + return 0; +} + +int block_cipher_decrypt(BLOCK_CIPHER_CONTEXT *blk_ctx, int len, const char *src, char *dst) +{ + int ret; + if (blk_ctx->type == BLOCK_CIPHER_NULL) { + memcpy(dst, src, len); + return 0; + } + ret = EVP_DecryptInit_ex(blk_ctx->ctx, blk_ctx->cipher, NULL, blk_ctx->key, blk_ctx->iv); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + int outl1, outl2; + ret = EVP_DecryptUpdate(blk_ctx->ctx, (unsigned char *)dst, &outl1, (const unsigned char *)src, len); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + ret = EVP_DecryptFinal_ex(blk_ctx->ctx, (unsigned char *)dst + outl1, &outl2); + if (ret != 1) { + reportOpenSSLErrors(); + return -1; + } + ASSERTD(outl1+outl2==len, "unexpected decryption length"); + return 0; +} + +int block_cipher_get_key_length(BLOCK_CIPHER_CONTEXT *blk_ctx) +{ + return blk_ctx->key_length; +} diff --git a/bacula/src/lib/crypto.h b/bacula/src/lib/crypto.h index efac78fd9..04b5b606e 100644 --- a/bacula/src/lib/crypto.h +++ b/bacula/src/lib/crypto.h @@ -108,6 +108,20 @@ typedef enum { #define CRYPTO_DIGEST_XXH3_64_SIZE 8 /* 64bits */ #define CRYPTO_DIGEST_XXH3_128_SIZE 16 /* 128bits */ +typedef enum +{ + BLOCK_CIPHER_NONE = 0, + BLOCK_CIPHER_NULL, + BLOCK_CIPHER_AES_128_XTS, + BLOCK_CIPHER_AES_256_XTS, + BLOCK_CIPHER_LAST +} block_cipher_type; + +#define MAX_BLOCK_CIPHER_KEY_LEN 64 /* for BLOCK_CIPHER_AES_256_XTS */ +#define MAX_MASTERKEY_ID_LEN 20 /* this is the 40 hexa fingerprint */ + +typedef struct block_cipher_context BLOCK_CIPHER_CONTEXT; + /* Maximum Message Digest Size */ #ifdef HAVE_OPENSSL diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index e70407851..c206dc579 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -229,6 +229,15 @@ const char * crypto_digest_name (DIGEST *digest); crypto_digest_t crypto_digest_stream_type (int stream); const char * crypto_strerror (crypto_error_t error); +BLOCK_CIPHER_CONTEXT *block_cipher_context_new(block_cipher_type blk_type); +void block_cipher_context_free(BLOCK_CIPHER_CONTEXT *blk_ctx); +void block_cipher_init_key(BLOCK_CIPHER_CONTEXT *blk_ctx, const unsigned char *key); +void block_cipher_init_iv(BLOCK_CIPHER_CONTEXT *blk_ctx, const unsigned char *iv); +void block_cipher_init_iv_header(BLOCK_CIPHER_CONTEXT *blk_ctx, uint32_t BlockNumber, uint32_t VolSessionId, uint32_t VolSessionTime); +int block_cipher_encrypt(BLOCK_CIPHER_CONTEXT *blk_ctx, int len, const char *src, char *dst); +int block_cipher_decrypt(BLOCK_CIPHER_CONTEXT *blk_ctx, int len, const char *src, char *dst); +int block_cipher_get_key_length(BLOCK_CIPHER_CONTEXT *blk_ctx); + /* daemon.c */ void daemon_start (); diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 1a6ce2341..aa08da4a8 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -175,6 +175,9 @@ all: Makefile libbacsd.la drivers bacula-sd @STATIC_SD@ \ @echo "===== Make of stored is good ====" @echo " " +../lib/unittests.o: ../lib/unittests.c + (cd ../lib ; make unittests.o) + bacula-sd: Makefile libbacsd.la $(SDOBJS) \ ../lib/libbaccfg$(DEFAULT_ARCHIVE_TYPE) \ ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) \ @@ -278,7 +281,6 @@ btape: Makefile $(TAPEOBJS) libbacsd.la drivers ../lib/libbac$(DEFAULT_ARCHIVE_ $(LIBTOOL_LINK) $(CXX) $(TTOOL_LDFLAGS) $(LDFLAGS) -L../lib -L../findlib -o $@ $(TAPEOBJS) \ $(SD_LIBS) $(DLIB) -lm $(LIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) - cloud_test.o: cloud_test.c @echo "Compiling $<" $(NO_ECHO)$(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) \ diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 2a0781ee8..2b618dab1 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -381,6 +381,8 @@ public: devstatmetrics_t devstatmetrics; /* these are a device metrics for every device */ bstatcollect *devstatcollector; /* a pointer to daemon's statcollector */ + BLOCK_CIPHER_CONTEXT *crypto_device_ctx; + /* Methods */ btime_t get_timer_count(); /* return the last timer interval (ms) */ diff --git a/bacula/src/tools/Makefile.in b/bacula/src/tools/Makefile.in index 71e5f135b..fcedaff19 100644 --- a/bacula/src/tools/Makefile.in +++ b/bacula/src/tools/Makefile.in @@ -131,6 +131,11 @@ bnet_test: Makefile bnet_test.o ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) ../findlib/ $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ bnet_test.o -lbacfind -lbac -lm \ $(DLIB) $(LIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) +block_crypto_test: Makefile block_crypto_test.o ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) ../lib/unittests.o + $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L../lib -o $@ block_crypto_test.o ../lib/unittests.o -lbac -lm \ + $(DLIB) $(LIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) + $(LIBTOOL_INSTALL) $(INSTALL_PROGRAM) $@ $(DESTDIR)$(sbindir)/ + tags_test: Makefile test_tags.o ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) ../lib/unittests.o $(LIBTOOL_LINK) $(CXX) $(LDFLAGS) -L../lib -o $@ test_tags.o ../lib/unittests.o -lbac \ $(DLIB) $(LIBS)