Merge "Merge branch 'upstream' into tizen" into tizen
[platform/upstream/cryptsetup.git] / lib / crypto_backend / crypto_storage.c
index b0452a3..14ab7fe 100644 (file)
@@ -2,7 +2,7 @@
  * Generic wrapper for storage encryption modes and Initial Vectors
  * (reimplementation of some functions from Linux dm-crypt kernel)
  *
- * Copyright (C) 2014, Milan Broz
+ * Copyright (C) 2014-2021 Milan Broz
  *
  * This file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "crypto_backend.h"
 
 #define SECTOR_SHIFT   9
-#define SECTOR_SIZE    (1 << SECTOR_SHIFT)
 
 /*
  * Internal IV helper
  * IV documentation: https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
  */
 struct crypt_sector_iv {
-       enum { IV_NONE, IV_NULL, IV_PLAIN, IV_PLAIN64, IV_ESSIV, IV_BENBI } type;
+       enum { IV_NONE, IV_NULL, IV_PLAIN, IV_PLAIN64, IV_ESSIV, IV_BENBI, IV_PLAIN64BE, IV_EBOIV } type;
        int iv_size;
        char *iv;
-       struct crypt_cipher *essiv_cipher;
-       int benbi_shift;
+       struct crypt_cipher *cipher;
+       int shift;
 };
 
 /* Block encryption storage context */
 struct crypt_storage {
-       uint64_t sector_start;
+       size_t sector_size;
+       unsigned iv_shift;
        struct crypt_cipher *cipher;
        struct crypt_sector_iv cipher_iv;
 };
@@ -56,24 +56,32 @@ static int int_log2(unsigned int x)
 
 static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
                         const char *cipher_name, const char *mode_name,
-                        const char *iv_name, char *key, size_t key_length)
+                        const char *iv_name, const void *key, size_t key_length,
+                        size_t sector_size)
 {
+       int r;
+
        memset(ctx, 0, sizeof(*ctx));
 
-       ctx->iv_size = crypt_cipher_blocksize(cipher_name);
-       if (ctx->iv_size < 0)
+       ctx->iv_size = crypt_cipher_ivsize(cipher_name, mode_name);
+       if (ctx->iv_size < 0 || (strcmp(mode_name, "ecb") && ctx->iv_size < 8))
                return -ENOENT;
 
-       if (!iv_name ||
-           !strcmp(cipher_name, "cipher_null") ||
+       if (!strcmp(cipher_name, "cipher_null") ||
            !strcmp(mode_name, "ecb")) {
+               if (iv_name)
+                       return -EINVAL;
                ctx->type = IV_NONE;
                ctx->iv_size = 0;
                return 0;
+       } else if (!iv_name) {
+               return -EINVAL;
        } else if (!strcasecmp(iv_name, "null")) {
                ctx->type = IV_NULL;
        } else if (!strcasecmp(iv_name, "plain64")) {
                ctx->type = IV_PLAIN64;
+       } else if (!strcasecmp(iv_name, "plain64be")) {
+               ctx->type = IV_PLAIN64BE;
        } else if (!strcasecmp(iv_name, "plain")) {
                ctx->type = IV_PLAIN;
        } else if (!strncasecmp(iv_name, "essiv:", 6)) {
@@ -81,7 +89,6 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
                char *hash_name = strchr(iv_name, ':');
                int hash_size;
                char tmp[256];
-               int r;
 
                if (!hash_name)
                        return -EINVAL;
@@ -109,7 +116,7 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
                        return r;
                }
 
-               r = crypt_cipher_init(&ctx->essiv_cipher, cipher_name, "ecb",
+               r = crypt_cipher_init(&ctx->cipher, cipher_name, "ecb",
                                      tmp, hash_size);
                crypt_backend_memzero(tmp, sizeof(tmp));
                if (r)
@@ -122,7 +129,15 @@ static int crypt_sector_iv_init(struct crypt_sector_iv *ctx,
                        return -EINVAL;
 
                ctx->type = IV_BENBI;
-               ctx->benbi_shift = SECTOR_SHIFT - log;
+               ctx->shift = SECTOR_SHIFT - log;
+       } else if (!strncasecmp(iv_name, "eboiv", 5)) {
+               r = crypt_cipher_init(&ctx->cipher, cipher_name, "ecb",
+                                     key, key_length);
+               if (r)
+                       return r;
+
+               ctx->type = IV_EBOIV;
+               ctx->shift = int_log2(sector_size);
        } else
                return -ENOENT;
 
@@ -151,17 +166,27 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
                memset(ctx->iv, 0, ctx->iv_size);
                *(uint64_t *)ctx->iv = cpu_to_le64(sector);
                break;
+       case IV_PLAIN64BE:
+               memset(ctx->iv, 0, ctx->iv_size);
+               *(uint64_t *)&ctx->iv[ctx->iv_size - sizeof(uint64_t)] = cpu_to_be64(sector);
+               break;
        case IV_ESSIV:
                memset(ctx->iv, 0, ctx->iv_size);
                *(uint64_t *)ctx->iv = cpu_to_le64(sector);
-               return crypt_cipher_encrypt(ctx->essiv_cipher,
+               return crypt_cipher_encrypt(ctx->cipher,
                        ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
                break;
        case IV_BENBI:
                memset(ctx->iv, 0, ctx->iv_size);
-               val = cpu_to_be64((sector << ctx->benbi_shift) + 1);
+               val = cpu_to_be64((sector << ctx->shift) + 1);
                memcpy(ctx->iv + ctx->iv_size - sizeof(val), &val, sizeof(val));
                break;
+       case IV_EBOIV:
+               memset(ctx->iv, 0, ctx->iv_size);
+               *(uint64_t *)ctx->iv = cpu_to_le64(sector << ctx->shift);
+               return crypt_cipher_encrypt(ctx->cipher,
+                       ctx->iv, ctx->iv, ctx->iv_size, NULL, 0);
+               break;
        default:
                return -EINVAL;
        }
@@ -169,10 +194,10 @@ static int crypt_sector_iv_generate(struct crypt_sector_iv *ctx, uint64_t sector
        return 0;
 }
 
-static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
+static void crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
 {
-       if (ctx->type == IV_ESSIV)
-               crypt_cipher_destroy(ctx->essiv_cipher);
+       if (ctx->type == IV_ESSIV || ctx->type == IV_EBOIV)
+               crypt_cipher_destroy(ctx->cipher);
 
        if (ctx->iv) {
                memset(ctx->iv, 0, ctx->iv_size);
@@ -180,22 +205,27 @@ static int crypt_sector_iv_destroy(struct crypt_sector_iv *ctx)
        }
 
        memset(ctx, 0, sizeof(*ctx));
-       return 0;
 }
 
 /* Block encryption storage wrappers */
 
 int crypt_storage_init(struct crypt_storage **ctx,
-                      uint64_t sector_start,
+                      size_t sector_size,
                       const char *cipher,
                       const char *cipher_mode,
-                      char *key, size_t key_length)
+                      const void *key, size_t key_length,
+                      bool large_iv)
 {
        struct crypt_storage *s;
        char mode_name[64];
        char *cipher_iv = NULL;
        int r = -EIO;
 
+       if (sector_size < (1 << SECTOR_SHIFT) ||
+           sector_size > (1 << (SECTOR_SHIFT + 3)) ||
+           sector_size & (sector_size - 1))
+               return -EINVAL;
+
        s = malloc(sizeof(*s));
        if (!s)
                return -ENOMEM;
@@ -216,33 +246,40 @@ int crypt_storage_init(struct crypt_storage **ctx,
                return r;
        }
 
-       r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length);
+       r = crypt_sector_iv_init(&s->cipher_iv, cipher, mode_name, cipher_iv, key, key_length, sector_size);
        if (r) {
                crypt_storage_destroy(s);
                return r;
        }
 
-       s->sector_start = sector_start;
+       s->sector_size = sector_size;
+       s->iv_shift = large_iv ? int_log2(sector_size) - SECTOR_SHIFT : 0;
 
        *ctx = s;
        return 0;
 }
 
 int crypt_storage_decrypt(struct crypt_storage *ctx,
-                      uint64_t sector, size_t count,
-                      char *buffer)
+                      uint64_t iv_offset,
+                      uint64_t length, char *buffer)
 {
-       unsigned int i;
+       uint64_t i;
        int r = 0;
 
-       for (i = 0; i < count; i++) {
-               r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
+       if (length & (ctx->sector_size - 1))
+               return -EINVAL;
+
+       if (iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
+               return -EINVAL;
+
+       for (i = 0; i < length; i += ctx->sector_size) {
+               r = crypt_sector_iv_generate(&ctx->cipher_iv, (iv_offset + (i >> SECTOR_SHIFT)) >> ctx->iv_shift);
                if (r)
                        break;
                r = crypt_cipher_decrypt(ctx->cipher,
-                                        &buffer[i * SECTOR_SIZE],
-                                        &buffer[i * SECTOR_SIZE],
-                                        SECTOR_SIZE,
+                                        &buffer[i],
+                                        &buffer[i],
+                                        ctx->sector_size,
                                         ctx->cipher_iv.iv,
                                         ctx->cipher_iv.iv_size);
                if (r)
@@ -253,20 +290,26 @@ int crypt_storage_decrypt(struct crypt_storage *ctx,
 }
 
 int crypt_storage_encrypt(struct crypt_storage *ctx,
-                      uint64_t sector, size_t count,
-                      char *buffer)
+                      uint64_t iv_offset,
+                      uint64_t length, char *buffer)
 {
-       unsigned int i;
+       uint64_t i;
        int r = 0;
 
-       for (i = 0; i < count; i++) {
-               r = crypt_sector_iv_generate(&ctx->cipher_iv, sector + i);
+       if (length & (ctx->sector_size - 1))
+               return -EINVAL;
+
+       if (iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
+               return -EINVAL;
+
+       for (i = 0; i < length; i += ctx->sector_size) {
+               r = crypt_sector_iv_generate(&ctx->cipher_iv, (iv_offset + (i >> SECTOR_SHIFT)) >> ctx->iv_shift);
                if (r)
                        break;
                r = crypt_cipher_encrypt(ctx->cipher,
-                                        &buffer[i * SECTOR_SIZE],
-                                        &buffer[i * SECTOR_SIZE],
-                                        SECTOR_SIZE,
+                                        &buffer[i],
+                                        &buffer[i],
+                                        ctx->sector_size,
                                         ctx->cipher_iv.iv,
                                         ctx->cipher_iv.iv_size);
                if (r)
@@ -276,10 +319,10 @@ int crypt_storage_encrypt(struct crypt_storage *ctx,
        return r;
 }
 
-int crypt_storage_destroy(struct crypt_storage *ctx)
+void crypt_storage_destroy(struct crypt_storage *ctx)
 {
        if (!ctx)
-               return 0;
+               return;
 
        crypt_sector_iv_destroy(&ctx->cipher_iv);
 
@@ -288,6 +331,9 @@ int crypt_storage_destroy(struct crypt_storage *ctx)
 
        memset(ctx, 0, sizeof(*ctx));
        free(ctx);
+}
 
-       return 0;
+bool crypt_storage_kernel_only(struct crypt_storage *ctx)
+{
+       return crypt_cipher_kernel_only(ctx->cipher);
 }