eCryptfs: Use skcipher and shash
[cascardo/linux.git] / fs / ecryptfs / keystore.c
index 6bd67e2..9893d15 100644 (file)
  * 02111-1307, USA.
  */
 
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/key.h>
 #include <linux/random.h>
-#include <linux/crypto.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include "ecryptfs_kernel.h"
@@ -601,12 +602,13 @@ struct ecryptfs_write_tag_70_packet_silly_stack {
        struct ecryptfs_auth_tok *auth_tok;
        struct scatterlist src_sg[2];
        struct scatterlist dst_sg[2];
-       struct blkcipher_desc desc;
+       struct crypto_skcipher *skcipher_tfm;
+       struct skcipher_request *skcipher_req;
        char iv[ECRYPTFS_MAX_IV_BYTES];
        char hash[ECRYPTFS_TAG_70_DIGEST_SIZE];
        char tmp_hash[ECRYPTFS_TAG_70_DIGEST_SIZE];
-       struct hash_desc hash_desc;
-       struct scatterlist hash_sg;
+       struct crypto_shash *hash_tfm;
+       struct shash_desc *hash_desc;
 };
 
 /**
@@ -629,14 +631,12 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
        struct key *auth_tok_key = NULL;
        int rc = 0;
 
-       s = kmalloc(sizeof(*s), GFP_KERNEL);
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
        if (!s) {
                printk(KERN_ERR "%s: Out of memory whilst trying to kmalloc "
                       "[%zd] bytes of kernel memory\n", __func__, sizeof(*s));
-               rc = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
-       s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
        (*packet_size) = 0;
        rc = ecryptfs_find_auth_tok_for_sig(
                &auth_tok_key,
@@ -649,7 +649,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                goto out;
        }
        rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(
-               &s->desc.tfm,
+               &s->skcipher_tfm,
                &s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name);
        if (unlikely(rc)) {
                printk(KERN_ERR "Internal error whilst attempting to get "
@@ -658,7 +658,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                goto out;
        }
        mutex_lock(s->tfm_mutex);
-       s->block_size = crypto_blkcipher_blocksize(s->desc.tfm);
+       s->block_size = crypto_skcipher_blocksize(s->skcipher_tfm);
        /* Plus one for the \0 separator between the random prefix
         * and the plaintext filename */
        s->num_rand_bytes = (ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES + 1);
@@ -691,6 +691,19 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                rc = -EINVAL;
                goto out_unlock;
        }
+
+       s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL);
+       if (!s->skcipher_req) {
+               printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
+                      "skcipher_request_alloc for %s\n", __func__,
+                      crypto_skcipher_driver_name(s->skcipher_tfm));
+               rc = -ENOMEM;
+               goto out_unlock;
+       }
+
+       skcipher_request_set_callback(s->skcipher_req,
+                                     CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+
        s->block_aligned_filename = kzalloc(s->block_aligned_filename_size,
                                            GFP_KERNEL);
        if (!s->block_aligned_filename) {
@@ -700,7 +713,6 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                rc = -ENOMEM;
                goto out_unlock;
        }
-       s->i = 0;
        dest[s->i++] = ECRYPTFS_TAG_70_PACKET_TYPE;
        rc = ecryptfs_write_packet_length(&dest[s->i],
                                          (ECRYPTFS_SIG_SIZE
@@ -738,40 +750,36 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                       "password tokens\n", __func__);
                goto out_free_unlock;
        }
-       sg_init_one(
-               &s->hash_sg,
-               (u8 *)s->auth_tok->token.password.session_key_encryption_key,
-               s->auth_tok->token.password.session_key_encryption_key_bytes);
-       s->hash_desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-       s->hash_desc.tfm = crypto_alloc_hash(ECRYPTFS_TAG_70_DIGEST, 0,
-                                            CRYPTO_ALG_ASYNC);
-       if (IS_ERR(s->hash_desc.tfm)) {
-                       rc = PTR_ERR(s->hash_desc.tfm);
+       s->hash_tfm = crypto_alloc_shash(ECRYPTFS_TAG_70_DIGEST, 0, 0);
+       if (IS_ERR(s->hash_tfm)) {
+                       rc = PTR_ERR(s->hash_tfm);
                        printk(KERN_ERR "%s: Error attempting to "
                               "allocate hash crypto context; rc = [%d]\n",
                               __func__, rc);
                        goto out_free_unlock;
        }
-       rc = crypto_hash_init(&s->hash_desc);
-       if (rc) {
-               printk(KERN_ERR
-                      "%s: Error initializing crypto hash; rc = [%d]\n",
-                      __func__, rc);
-               goto out_release_free_unlock;
-       }
-       rc = crypto_hash_update(
-               &s->hash_desc, &s->hash_sg,
-               s->auth_tok->token.password.session_key_encryption_key_bytes);
-       if (rc) {
-               printk(KERN_ERR
-                      "%s: Error updating crypto hash; rc = [%d]\n",
-                      __func__, rc);
+
+       s->hash_desc = kmalloc(sizeof(*s->hash_desc) +
+                              crypto_shash_descsize(s->hash_tfm), GFP_KERNEL);
+       if (!s->hash_desc) {
+               printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
+                      "kmalloc [%zd] bytes\n", __func__,
+                      sizeof(*s->hash_desc) +
+                      crypto_shash_descsize(s->hash_tfm));
+               rc = -ENOMEM;
                goto out_release_free_unlock;
        }
-       rc = crypto_hash_final(&s->hash_desc, s->hash);
+
+       s->hash_desc->tfm = s->hash_tfm;
+       s->hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       rc = crypto_shash_digest(s->hash_desc,
+                                (u8 *)s->auth_tok->token.password.session_key_encryption_key,
+                                s->auth_tok->token.password.session_key_encryption_key_bytes,
+                                s->hash);
        if (rc) {
                printk(KERN_ERR
-                      "%s: Error finalizing crypto hash; rc = [%d]\n",
+                      "%s: Error computing crypto hash; rc = [%d]\n",
                       __func__, rc);
                goto out_release_free_unlock;
        }
@@ -780,27 +788,12 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                        s->hash[(s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)];
                if ((s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)
                    == (ECRYPTFS_TAG_70_DIGEST_SIZE - 1)) {
-                       sg_init_one(&s->hash_sg, (u8 *)s->hash,
-                                   ECRYPTFS_TAG_70_DIGEST_SIZE);
-                       rc = crypto_hash_init(&s->hash_desc);
-                       if (rc) {
-                               printk(KERN_ERR
-                                      "%s: Error initializing crypto hash; "
-                                      "rc = [%d]\n", __func__, rc);
-                               goto out_release_free_unlock;
-                       }
-                       rc = crypto_hash_update(&s->hash_desc, &s->hash_sg,
-                                               ECRYPTFS_TAG_70_DIGEST_SIZE);
+                       rc = crypto_shash_digest(s->hash_desc, (u8 *)s->hash,
+                                               ECRYPTFS_TAG_70_DIGEST_SIZE,
+                                               s->tmp_hash);
                        if (rc) {
                                printk(KERN_ERR
-                                      "%s: Error updating crypto hash; "
-                                      "rc = [%d]\n", __func__, rc);
-                               goto out_release_free_unlock;
-                       }
-                       rc = crypto_hash_final(&s->hash_desc, s->tmp_hash);
-                       if (rc) {
-                               printk(KERN_ERR
-                                      "%s: Error finalizing crypto hash; "
+                                      "%s: Error computing crypto hash; "
                                       "rc = [%d]\n", __func__, rc);
                                goto out_release_free_unlock;
                        }
@@ -834,10 +827,8 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
         * of the IV here, so we just use 0's for the IV. Note the
         * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
         * >= ECRYPTFS_MAX_IV_BYTES. */
-       memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES);
-       s->desc.info = s->iv;
-       rc = crypto_blkcipher_setkey(
-               s->desc.tfm,
+       rc = crypto_skcipher_setkey(
+               s->skcipher_tfm,
                s->auth_tok->token.password.session_key_encryption_key,
                mount_crypt_stat->global_default_fn_cipher_key_bytes);
        if (rc < 0) {
@@ -850,8 +841,9 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
                       mount_crypt_stat->global_default_fn_cipher_key_bytes);
                goto out_release_free_unlock;
        }
-       rc = crypto_blkcipher_encrypt_iv(&s->desc, s->dst_sg, s->src_sg,
-                                        s->block_aligned_filename_size);
+       skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
+                                  s->block_aligned_filename_size, s->iv);
+       rc = crypto_skcipher_encrypt(s->skcipher_req);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to encrypt filename; "
                       "rc = [%d]\n", __func__, rc);
@@ -861,7 +853,7 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
        (*packet_size) = s->i;
        (*remaining_bytes) -= (*packet_size);
 out_release_free_unlock:
-       crypto_free_hash(s->hash_desc.tfm);
+       crypto_free_shash(s->hash_tfm);
 out_free_unlock:
        kzfree(s->block_aligned_filename);
 out_unlock:
@@ -871,6 +863,8 @@ out:
                up_write(&(auth_tok_key->sem));
                key_put(auth_tok_key);
        }
+       skcipher_request_free(s->skcipher_req);
+       kzfree(s->hash_desc);
        kfree(s);
        return rc;
 }
@@ -888,7 +882,8 @@ struct ecryptfs_parse_tag_70_packet_silly_stack {
        struct ecryptfs_auth_tok *auth_tok;
        struct scatterlist src_sg[2];
        struct scatterlist dst_sg[2];
-       struct blkcipher_desc desc;
+       struct crypto_skcipher *skcipher_tfm;
+       struct skcipher_request *skcipher_req;
        char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
        char iv[ECRYPTFS_MAX_IV_BYTES];
        char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
@@ -922,14 +917,12 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
        (*packet_size) = 0;
        (*filename_size) = 0;
        (*filename) = NULL;
-       s = kmalloc(sizeof(*s), GFP_KERNEL);
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
        if (!s) {
                printk(KERN_ERR "%s: Out of memory whilst trying to kmalloc "
                       "[%zd] bytes of kernel memory\n", __func__, sizeof(*s));
-               rc = -ENOMEM;
-               goto out;
+               return -ENOMEM;
        }
-       s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
        if (max_packet_size < ECRYPTFS_TAG_70_MIN_METADATA_SIZE) {
                printk(KERN_WARNING "%s: max_packet_size is [%zd]; it must be "
                       "at least [%d]\n", __func__, max_packet_size,
@@ -992,7 +985,7 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                       rc);
                goto out;
        }
-       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->desc.tfm,
+       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&s->skcipher_tfm,
                                                        &s->tfm_mutex,
                                                        s->cipher_string);
        if (unlikely(rc)) {
@@ -1030,12 +1023,23 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                       __func__, rc, s->block_aligned_filename_size);
                goto out_free_unlock;
        }
+
+       s->skcipher_req = skcipher_request_alloc(s->skcipher_tfm, GFP_KERNEL);
+       if (!s->skcipher_req) {
+               printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
+                      "skcipher_request_alloc for %s\n", __func__,
+                      crypto_skcipher_driver_name(s->skcipher_tfm));
+               rc = -ENOMEM;
+               goto out_free_unlock;
+       }
+
+       skcipher_request_set_callback(s->skcipher_req,
+                                     CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
+
        /* The characters in the first block effectively do the job of
         * the IV here, so we just use 0's for the IV. Note the
         * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES
         * >= ECRYPTFS_MAX_IV_BYTES. */
-       memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES);
-       s->desc.info = s->iv;
        /* TODO: Support other key modules than passphrase for
         * filename encryption */
        if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
@@ -1044,8 +1048,8 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                       "password tokens\n", __func__);
                goto out_free_unlock;
        }
-       rc = crypto_blkcipher_setkey(
-               s->desc.tfm,
+       rc = crypto_skcipher_setkey(
+               s->skcipher_tfm,
                s->auth_tok->token.password.session_key_encryption_key,
                mount_crypt_stat->global_default_fn_cipher_key_bytes);
        if (rc < 0) {
@@ -1058,14 +1062,14 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
                       mount_crypt_stat->global_default_fn_cipher_key_bytes);
                goto out_free_unlock;
        }
-       rc = crypto_blkcipher_decrypt_iv(&s->desc, s->dst_sg, s->src_sg,
-                                        s->block_aligned_filename_size);
+       skcipher_request_set_crypt(s->skcipher_req, s->src_sg, s->dst_sg,
+                                  s->block_aligned_filename_size, s->iv);
+       rc = crypto_skcipher_decrypt(s->skcipher_req);
        if (rc) {
                printk(KERN_ERR "%s: Error attempting to decrypt filename; "
                       "rc = [%d]\n", __func__, rc);
                goto out_free_unlock;
        }
-       s->i = 0;
        while (s->decrypted_filename[s->i] != '\0'
               && s->i < s->block_aligned_filename_size)
                s->i++;
@@ -1108,6 +1112,7 @@ out:
                up_write(&(auth_tok_key->sem));
                key_put(auth_tok_key);
        }
+       skcipher_request_free(s->skcipher_req);
        kfree(s);
        return rc;
 }
@@ -1667,9 +1672,8 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
        struct scatterlist dst_sg[2];
        struct scatterlist src_sg[2];
        struct mutex *tfm_mutex;
-       struct blkcipher_desc desc = {
-               .flags = CRYPTO_TFM_REQ_MAY_SLEEP
-       };
+       struct crypto_skcipher *tfm;
+       struct skcipher_request *req = NULL;
        int rc = 0;
 
        if (unlikely(ecryptfs_verbosity > 0)) {
@@ -1680,7 +1684,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                        auth_tok->token.password.session_key_encryption_key,
                        auth_tok->token.password.session_key_encryption_key_bytes);
        }
-       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&desc.tfm, &tfm_mutex,
+       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&tfm, &tfm_mutex,
                                                        crypt_stat->cipher);
        if (unlikely(rc)) {
                printk(KERN_ERR "Internal error whilst attempting to get "
@@ -1711,8 +1715,20 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                goto out;
        }
        mutex_lock(tfm_mutex);
-       rc = crypto_blkcipher_setkey(
-               desc.tfm, auth_tok->token.password.session_key_encryption_key,
+       req = skcipher_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               mutex_unlock(tfm_mutex);
+               printk(KERN_ERR "%s: Out of kernel memory whilst attempting to "
+                      "skcipher_request_alloc for %s\n", __func__,
+                      crypto_skcipher_driver_name(tfm));
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+                                     NULL, NULL);
+       rc = crypto_skcipher_setkey(
+               tfm, auth_tok->token.password.session_key_encryption_key,
                crypt_stat->key_size);
        if (unlikely(rc < 0)) {
                mutex_unlock(tfm_mutex);
@@ -1720,8 +1736,10 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                rc = -EINVAL;
                goto out;
        }
-       rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
-                                     auth_tok->session_key.encrypted_key_size);
+       skcipher_request_set_crypt(req, src_sg, dst_sg,
+                                  auth_tok->session_key.encrypted_key_size,
+                                  NULL);
+       rc = crypto_skcipher_decrypt(req);
        mutex_unlock(tfm_mutex);
        if (unlikely(rc)) {
                printk(KERN_ERR "Error decrypting; rc = [%d]\n", rc);
@@ -1738,6 +1756,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
                                  crypt_stat->key_size);
        }
 out:
+       skcipher_request_free(req);
        return rc;
 }
 
@@ -2191,16 +2210,14 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
        size_t max_packet_size;
        struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
                crypt_stat->mount_crypt_stat;
-       struct blkcipher_desc desc = {
-               .tfm = NULL,
-               .flags = CRYPTO_TFM_REQ_MAY_SLEEP
-       };
+       struct crypto_skcipher *tfm;
+       struct skcipher_request *req;
        int rc = 0;
 
        (*packet_size) = 0;
        ecryptfs_from_hex(key_rec->sig, auth_tok->token.password.signature,
                          ECRYPTFS_SIG_SIZE);
-       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&desc.tfm, &tfm_mutex,
+       rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&tfm, &tfm_mutex,
                                                        crypt_stat->cipher);
        if (unlikely(rc)) {
                printk(KERN_ERR "Internal error whilst attempting to get "
@@ -2209,12 +2226,11 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
                goto out;
        }
        if (mount_crypt_stat->global_default_cipher_key_size == 0) {
-               struct blkcipher_alg *alg = crypto_blkcipher_alg(desc.tfm);
-
                printk(KERN_WARNING "No key size specified at mount; "
-                      "defaulting to [%d]\n", alg->max_keysize);
+                      "defaulting to [%d]\n",
+                      crypto_skcipher_default_keysize(tfm));
                mount_crypt_stat->global_default_cipher_key_size =
-                       alg->max_keysize;
+                       crypto_skcipher_default_keysize(tfm);
        }
        if (crypt_stat->key_size == 0)
                crypt_stat->key_size =
@@ -2284,20 +2300,36 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
                goto out;
        }
        mutex_lock(tfm_mutex);
-       rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,
-                                    crypt_stat->key_size);
+       rc = crypto_skcipher_setkey(tfm, session_key_encryption_key,
+                                   crypt_stat->key_size);
        if (rc < 0) {
                mutex_unlock(tfm_mutex);
                ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
                                "context; rc = [%d]\n", rc);
                goto out;
        }
+
+       req = skcipher_request_alloc(tfm, GFP_KERNEL);
+       if (!req) {
+               mutex_unlock(tfm_mutex);
+               ecryptfs_printk(KERN_ERR, "Out of kernel memory whilst "
+                               "attempting to skcipher_request_alloc for "
+                               "%s\n", crypto_skcipher_driver_name(tfm));
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+                                     NULL, NULL);
+
        rc = 0;
        ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
                        crypt_stat->key_size);
-       rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
-                                     (*key_rec).enc_key_size);
+       skcipher_request_set_crypt(req, src_sg, dst_sg,
+                                  (*key_rec).enc_key_size, NULL);
+       rc = crypto_skcipher_encrypt(req);
        mutex_unlock(tfm_mutex);
+       skcipher_request_free(req);
        if (rc) {
                printk(KERN_ERR "Error encrypting; rc = [%d]\n", rc);
                goto out;