@@ -28,6 +28,7 @@
*/
#include <linux/crypto.h>
+#include <linux/scatterlist.h>
#include "ubifs.h"
/* Fake description object for the "none" compressor */
@@ -75,6 +76,53 @@ static struct ubifs_compressor zlib_compr = {
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/**
+ * aes_crypt - encrypt / decrypt data.
+ * @str: the data to crypt
+ * @len: length of the data
+ * @crypto_key: the cryptographic key to use to crypt the data
+ *
+ * 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. Returns zero in case of success and a negative
+ * error code in case of failure.
+ *
+ * WARNING: The operation is done in-place, so @str mutates!
+ */
+static int aes_crypt(void *str, int len, const void *crypto_key)
+{
+ struct crypto_blkcipher *tfm;
+ struct blkcipher_desc desc;
+ struct scatterlist sg;
+ uint8_t iv[UBIFS_CRYPTO_KEYSIZE];
+ int err;
+
+ tfm = crypto_alloc_blkcipher(UBIFS_CRYPTO_ALGORITHM, 0, 0);
+ if (IS_ERR(tfm)) {
+ err = PTR_ERR(tfm);
+ ubifs_err("failed to load transform for aes, error %d", err);
+ return err;
+ }
+
+ err = crypto_blkcipher_setkey(tfm, crypto_key, UBIFS_CRYPTO_KEYSIZE);
+ if (err) {
+ ubifs_err("cannot set the AES key, flags %#x, error %d",
+ crypto_blkcipher_get_flags(tfm), err);
+ return err;
+ }
+
+ memset(&sg, 0, sizeof(struct scatterlist));
+ sg_set_buf(&sg, str, len);
+ memset(iv, 0, UBIFS_CRYPTO_KEYSIZE);
+ desc.info = iv;
+ desc.tfm = tfm;
+ desc.flags = 0;
+ err = crypto_blkcipher_encrypt(&desc, &sg, &sg, len);
+ crypto_free_blkcipher(tfm);
+ return err;
+}
+
+/**
* ubifs_compress - compress data.
* @in_buf: data to compress
* @in_len: length of the data to compress
@@ -82,6 +130,7 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
* @out_len: output buffer length is returned here
* @compr_type: type of compression to use on enter, actually used compression
* type on exit
+ * @crypto_key: the encryption key or NULL if no encryption needed
*
* This function compresses input buffer @in_buf of length @in_len and stores
* the result in the output buffer @out_buf and the resulting length in
@@ -93,7 +142,7 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
* buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
*/
void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
- int *compr_type)
+ int *compr_type, void *crypto_key)
{
int err;
struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
@@ -125,12 +174,18 @@ 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;
+ if (crypto_key)
+ aes_crypt(out_buf, *out_len, crypto_key);
+
return;
no_compr:
memcpy(out_buf, in_buf, in_len);
*out_len = in_len;
*compr_type = UBIFS_COMPR_NONE;
+
+ if (crypto_key)
+ aes_crypt(out_buf, *out_len, crypto_key);
}
/**
@@ -140,13 +195,16 @@ no_compr:
* @out_buf: output buffer where decompressed data should
* @out_len: output length is returned here
* @compr_type: type of compression
+ * @crypto_key: the encryption key or %NULL if no encryption needed
*
* 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!
*/
-int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
- int *out_len, int compr_type)
+int ubifs_decompress(void *in_buf, int in_len, void *out_buf,
+ int *out_len, int compr_type, void *crypto_key)
{
int err;
struct ubifs_compressor *compr;
@@ -163,6 +221,9 @@ int ubifs_decompress(const void *in_buf, int in_len, void *out_buf,
return -EINVAL;
}
+ if (crypto_key)
+ aes_crypt(in_buf, in_len, crypto_key);
+
if (compr_type == UBIFS_COMPR_NONE) {
memcpy(out_buf, in_buf, in_len);
*out_len = in_len;
@@ -80,7 +80,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
out_len = UBIFS_BLOCK_SIZE;
err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
- le16_to_cpu(dn->compr_type));
+ le16_to_cpu(dn->compr_type), NULL);
if (err || len != out_len)
goto dump;
@@ -649,7 +649,8 @@ static int populate_page(struct ubifs_info *c, struct page *page,
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
out_len = UBIFS_BLOCK_SIZE;
err = ubifs_decompress(&dn->data, dlen, addr, &out_len,
- le16_to_cpu(dn->compr_type));
+ le16_to_cpu(dn->compr_type),
+ NULL);
if (err || len != out_len)
goto out_err;
@@ -730,7 +730,7 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
compr_type = ui->compr_type;
out_len = dlen - UBIFS_DATA_NODE_SZ;
- ubifs_compress(buf, len, &data->data, &out_len, &compr_type);
+ ubifs_compress(buf, len, &data->data, &out_len, &compr_type, NULL);
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
dlen = UBIFS_DATA_NODE_SZ + out_len;
@@ -1113,11 +1113,11 @@ static int recomp_data_node(struct ubifs_data_node *dn, int *new_len)
len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
compr_type = le16_to_cpu(dn->compr_type);
- err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type);
+ err = ubifs_decompress(&dn->data, len, buf, &out_len, compr_type, NULL);
if (err)
goto out;
- ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type);
+ ubifs_compress(buf, *new_len, &dn->data, &out_len, &compr_type, NULL);
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
dn->compr_type = cpu_to_le16(compr_type);
dn->size = cpu_to_le32(*new_len);
@@ -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.
*/
@@ -1772,9 +1777,9 @@ long ubifs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int __init ubifs_compressors_init(void);
void ubifs_compressors_exit(void);
void ubifs_compress(const void *in_buf, int in_len, void *out_buf, int *out_len,
- int *compr_type);
-int ubifs_decompress(const void *buf, int len, void *out, int *out_len,
- int compr_type);
+ int *compr_type, void *crypto_key);
+int ubifs_decompress(void *buf, int len, void *out, int *out_len,
+ int compr_type, void *crypto_key);
#include "debug.h"
#include "misc.h"