diff mbox

UBIFS: Add cryptographic functionality when a key is passed to the compress / decompress functions

Message ID alpine.DEB.2.00.1204031228470.4560@eristoteles.iwoars.net
State New, archived
Headers show

Commit Message

Joel Reardon April 3, 2012, 10:29 a.m. UTC
This patch adds a function to perform AES encryption. The compress and
decompress routines use this function if they are called with a non-NULL
key parameter. It uses AES counter mode (where encryption and decryption
are the same function) and performs the operation in place on the data. It
uses a default IV of 0, since each key is only evey used to encrypt one
data item the IV does not matter.

The const qualifier was removed from the decompress routine for the
following reason. Encrypted data is not compressable, so compression is
first applied then the result is encrypted. In the reverse, decryption is
first applied and the result decompressed. This means that either the
input buffer for decompression is used to perform an in-place decryption
before decompression, or a third buffer is added and data is copied around.

This was tested by using a static key as the key parameter where both compress
and decompress were called. Data was written and the file system was unmounted
and the mtd dev was scanned with hexdump to make sure that no plaintext data
was available. The drive was remounted and the data successful read back. The
static key was then removed and replaced with NULL, and the same test was done
except that now the data appeared in plaintext on the raw device.

Signed-off-by: Joel Reardon <reardonj@inf.ethz.ch>
---
 fs/ubifs/compress.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++---
 fs/ubifs/ubifs.h    |    8 +++++-
 2 files changed, 78 insertions(+), 5 deletions(-)

Comments

Guillaume LECERF April 3, 2012, 10:41 a.m. UTC | #1
Hi,

2012/4/3 Joel Reardon <joel@clambassador.com>:
>  no_compr:
>        memcpy(out_buf, in_buf, in_len);
>        *out_len = in_len;
>        *compr_type = UBIFS_COMPR_NONE;
> +       goto encrypt;

This goto seems unneeded here.

> +
> +encrypt:
> +       if (crypto_key) {
> +               u8 iv[UBIFS_CRYPTO_KEYSIZE];
> +
> +               memset(iv, 0, UBIFS_CRYPTO_KEYSIZE);
> +               ubifs_aes_crypt(out_buf, *out_len, crypto_key, iv);
> +       }
diff mbox

Patch

diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
index b796b8d..e6dc77d 100644
--- a/fs/ubifs/compress.c
+++ b/fs/ubifs/compress.c
@@ -27,9 +27,12 @@ 
  * decompression.
  */

-#include <linux/crypto.h>
 #include "ubifs.h"

+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+
+
 /* Fake description object for the "none" compressor */
 static struct ubifs_compressor none_compr = {
 	.compr_type = UBIFS_COMPR_NONE,
@@ -75,6 +78,53 @@  static struct ubifs_compressor zlib_compr = {
 struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];

 /**
+ * ubifs_aes_crypt - encrypt / decrypt data.
+ * @str: data to crypt
+ * @len: length of the data
+ * @crypto_key: the cryptographic key to use to crypt the data
+ * @iv: the initialization vector to use
+ *
+ * This function applies aes encryption to the data. It is done in counter
+ * mode, which means that encryption and decryption are the same operation,
+ * i.e., it XORs the same generated bitstream, so it can be used both for
+ * encryption / decryption. The operation is done in-place, so str mutates.
+ * Both crypto_key and iv are valid pointers to a buffer of length
+ * UBIFS_CRYPTO_KEYSIZE.
+ */
+int ubifs_aes_crypt(void *str, int len, u8 *crypto_key, u8 *iv)
+{
+	struct crypto_blkcipher *tfm;
+	struct blkcipher_desc desc;
+	struct scatterlist sg;
+	int err = 0;
+
+	tfm = crypto_alloc_blkcipher(UBIFS_CRYPTO_ALGORITHM, 0, 0);
+	if (IS_ERR(tfm)) {
+		ubifs_err("failed to load transform for aes: %ld",
+			  PTR_ERR(tfm));
+		return err;
+	}
+
+	err = crypto_blkcipher_setkey(tfm, crypto_key, UBIFS_CRYPTO_KEYSIZE);
+	desc.tfm = tfm;
+	desc.flags = 0;
+	if (err) {
+		ubifs_err("crypto_blkcipher_setkey() failed  flags=%#x",
+			  crypto_blkcipher_get_flags(tfm));
+		return err;
+	}
+
+	memset(&sg, 0, sizeof(struct scatterlist));
+	sg_set_buf(&sg, str, len);
+	desc.info = iv;
+	err = crypto_blkcipher_encrypt(&desc, &sg, &sg, len);
+	crypto_free_blkcipher(tfm);
+	if (err)
+		return err;
+	return 0;
+}
+
+/**
  * ubifs_compress - compress data.
  * @in_buf: data to compress
  * @in_len: length of the data to compress
@@ -126,13 +176,21 @@  void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
 	 */
 	if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
 		goto no_compr;
-
-	return;
+	goto encrypt;

 no_compr:
 	memcpy(out_buf, in_buf, in_len);
 	*out_len = in_len;
 	*compr_type = UBIFS_COMPR_NONE;
+	goto encrypt;
+
+encrypt:
+	if (crypto_key) {
+		u8 iv[UBIFS_CRYPTO_KEYSIZE];
+
+		memset(iv, 0, UBIFS_CRYPTO_KEYSIZE);
+		ubifs_aes_crypt(out_buf, *out_len, crypto_key, iv);
+	}
 }

 /**
@@ -148,8 +206,10 @@  no_compr:
  * This function decompresses data from buffer @in_buf into buffer @out_buf.
  * The length of the uncompressed data is returned in @out_len. This functions
  * returns %0 on success or a negative error code on failure.
+ *
+ * WARNING: this function may modify the contents of in_buf when executing.
  */
-int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
+int ubifs_decompress(void *in_buf, int in_len, void *out_buf,
 		     int *out_len, int compr_type, u8 *crypto_key)
 {
 	int err;
@@ -167,6 +227,13 @@  int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
 		return -EINVAL;
 	}

+	if (crypto_key) {
+		u8 iv[UBIFS_CRYPTO_KEYSIZE];
+
+		memset(iv, 0, UBIFS_CRYPTO_KEYSIZE);
+		ubifs_aes_crypt(in_buf, in_len, crypto_key, iv);
+	}
+
 	if (compr_type == UBIFS_COMPR_NONE) {
 		memcpy(out_buf, in_buf, in_len);
 		*out_len = in_len;
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 3ed12be..84d2c49 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -160,6 +160,11 @@ 
 /* Maximum number of data nodes to bulk-read */
 #define UBIFS_MAX_BULK_READ 32

+/* 128 bit key size in bytes for UBIFS */
+#define UBIFS_CRYPTO_KEYSIZE 16
+/* AES in counter mode is the encryption algorithm. */
+#define UBIFS_CRYPTO_ALGORITHM "ctr(aes)"
+
 /*
  * Lockdep classes for UBIFS inode @ui_mutex.
  */
@@ -1771,9 +1776,10 @@  long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 /* compressor.c */
 int __init ubifs_compressors_init(void);
 void ubifs_compressors_exit(void);
+int ubifs_aes_crypt(void *str, int len, u8 *crypto_key, u8 *iv);
 void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
 		    int *compr_type, u8 *crypto_key);
-int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
+int ubifs_decompress(void *buf, int len, void *out, int *out_len,
 		     int compr_type, u8 *crypto_key);

 #include "debug.h"