crypto: crypto4xx - simplify sa and state context acquisition
[linux-block.git] / drivers / crypto / amcc / crypto4xx_alg.c
index 4afca396877335653ae8f6f902d1bcdf5b3b9db3..22875ec2b2c8f3fb2859a4bb5b9e872a32593114 100644 (file)
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
 #include <crypto/sha.h>
+#include <crypto/ctr.h>
 #include "crypto4xx_reg_def.h"
-#include "crypto4xx_sa.h"
 #include "crypto4xx_core.h"
+#include "crypto4xx_sa.h"
 
 static void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h,
                                     u32 save_iv, u32 ld_h, u32 ld_iv,
@@ -62,6 +63,7 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
        sa->sa_command_1.bf.crypto_mode9_8 = cm & 3;
        sa->sa_command_1.bf.feedback_mode = cfb,
        sa->sa_command_1.bf.sa_rev = 1;
+       sa->sa_command_1.bf.hmac_muting = hmac_mc;
        sa->sa_command_1.bf.extended_seq_num = esn;
        sa->sa_command_1.bf.seq_num_mask = sn_mask;
        sa->sa_command_1.bf.mutable_bit_proc = mute;
@@ -73,29 +75,29 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
 int crypto4xx_encrypt(struct ablkcipher_request *req)
 {
        struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       unsigned int ivlen = crypto_ablkcipher_ivsize(
+               crypto_ablkcipher_reqtfm(req));
+       __le32 iv[ivlen];
 
-       ctx->direction = DIR_OUTBOUND;
-       ctx->hash_final = 0;
-       ctx->is_hash = 0;
-       ctx->pd_ctl = 0x1;
+       if (ivlen)
+               crypto4xx_memcpy_to_le32(iv, req->info, ivlen);
 
        return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
-                                 req->nbytes, req->info,
-                                 get_dynamic_sa_iv_size(ctx));
+               req->nbytes, iv, ivlen, ctx->sa_out, ctx->sa_len);
 }
 
 int crypto4xx_decrypt(struct ablkcipher_request *req)
 {
        struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       unsigned int ivlen = crypto_ablkcipher_ivsize(
+               crypto_ablkcipher_reqtfm(req));
+       __le32 iv[ivlen];
 
-       ctx->direction = DIR_INBOUND;
-       ctx->hash_final = 0;
-       ctx->is_hash = 0;
-       ctx->pd_ctl = 1;
+       if (ivlen)
+               crypto4xx_memcpy_to_le32(iv, req->info, ivlen);
 
        return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
-                                 req->nbytes, req->info,
-                                 get_dynamic_sa_iv_size(ctx));
+               req->nbytes, iv, ivlen, ctx->sa_in, ctx->sa_len);
 }
 
 /**
@@ -120,23 +122,15 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher,
        }
 
        /* Create SA */
-       if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+       if (ctx->sa_in || ctx->sa_out)
                crypto4xx_free_sa(ctx);
 
        rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4);
        if (rc)
                return rc;
 
-       if (ctx->state_record_dma_addr == 0) {
-               rc = crypto4xx_alloc_state_record(ctx);
-               if (rc) {
-                       crypto4xx_free_sa(ctx);
-                       return rc;
-               }
-       }
        /* Setup SA */
-       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
-       ctx->hash_final = 0;
+       sa = ctx->sa_in;
 
        set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV,
                                 SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE,
@@ -150,18 +144,13 @@ static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher,
                                 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
                                 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
                                 SA_NOT_COPY_HDR);
-       crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx),
-                           key, keylen);
-       sa->sa_contents = SA_AES_CONTENTS | (keylen << 2);
+       crypto4xx_memcpy_to_le32(get_dynamic_sa_key_field(sa),
+                                key, keylen);
+       sa->sa_contents.w = SA_AES_CONTENTS | (keylen << 2);
        sa->sa_command_1.bf.key_len = keylen >> 3;
-       ctx->is_hash = 0;
-       ctx->direction = DIR_INBOUND;
-       memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx),
-                       (void *)&ctx->state_record_dma_addr, 4);
-       ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx);
 
        memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4);
-       sa = (struct dynamic_sa_ctl *) ctx->sa_out;
+       sa = ctx->sa_out;
        sa->sa_command_0.bf.dir = DIR_OUTBOUND;
 
        return 0;
@@ -174,6 +163,73 @@ int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher,
                                    CRYPTO_FEEDBACK_MODE_NO_FB);
 }
 
+int crypto4xx_setkey_aes_cfb(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB,
+                                   CRYPTO_FEEDBACK_MODE_128BIT_CFB);
+}
+
+int crypto4xx_setkey_aes_ecb(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_ECB,
+                                   CRYPTO_FEEDBACK_MODE_NO_FB);
+}
+
+int crypto4xx_setkey_aes_ofb(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB,
+                                   CRYPTO_FEEDBACK_MODE_64BIT_OFB);
+}
+
+int crypto4xx_setkey_rfc3686(struct crypto_ablkcipher *cipher,
+                            const u8 *key, unsigned int keylen)
+{
+       struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
+       int rc;
+
+       rc = crypto4xx_setkey_aes(cipher, key, keylen - CTR_RFC3686_NONCE_SIZE,
+               CRYPTO_MODE_CTR, CRYPTO_FEEDBACK_MODE_NO_FB);
+       if (rc)
+               return rc;
+
+       ctx->iv_nonce = cpu_to_le32p((u32 *)&key[keylen -
+                                                CTR_RFC3686_NONCE_SIZE]);
+
+       return 0;
+}
+
+int crypto4xx_rfc3686_encrypt(struct ablkcipher_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       __le32 iv[AES_IV_SIZE / 4] = {
+               ctx->iv_nonce,
+               cpu_to_le32p((u32 *) req->info),
+               cpu_to_le32p((u32 *) (req->info + 4)),
+               cpu_to_le32(1) };
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+                                 req->nbytes, iv, AES_IV_SIZE,
+                                 ctx->sa_out, ctx->sa_len);
+}
+
+int crypto4xx_rfc3686_decrypt(struct ablkcipher_request *req)
+{
+       struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       __le32 iv[AES_IV_SIZE / 4] = {
+               ctx->iv_nonce,
+               cpu_to_le32p((u32 *) req->info),
+               cpu_to_le32p((u32 *) (req->info + 4)),
+               cpu_to_le32(1) };
+
+       return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst,
+                                 req->nbytes, iv, AES_IV_SIZE,
+                                 ctx->sa_out, ctx->sa_len);
+}
+
 /**
  * HASH SHA1 Functions
  */
@@ -185,51 +241,35 @@ static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm,
        struct crypto_alg *alg = tfm->__crt_alg;
        struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg);
        struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm);
-       struct dynamic_sa_ctl *sa;
-       struct dynamic_sa_hash160 *sa_in;
+       struct dynamic_sa_hash160 *sa;
        int rc;
 
        ctx->dev   = my_alg->dev;
-       ctx->is_hash = 1;
-       ctx->hash_final = 0;
 
        /* Create SA */
-       if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr)
+       if (ctx->sa_in || ctx->sa_out)
                crypto4xx_free_sa(ctx);
 
        rc = crypto4xx_alloc_sa(ctx, sa_len);
        if (rc)
                return rc;
 
-       if (ctx->state_record_dma_addr == 0) {
-               crypto4xx_alloc_state_record(ctx);
-               if (!ctx->state_record_dma_addr) {
-                       crypto4xx_free_sa(ctx);
-                       return -ENOMEM;
-               }
-       }
-
        crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
                                 sizeof(struct crypto4xx_ctx));
-       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
-       set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV,
+       sa = (struct dynamic_sa_hash160 *)ctx->sa_in;
+       set_dynamic_sa_command_0(&sa->ctrl, SA_SAVE_HASH, SA_NOT_SAVE_IV,
                                 SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA,
                                 SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL,
                                 SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC,
                                 SA_OPCODE_HASH, DIR_INBOUND);
-       set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH,
+       set_dynamic_sa_command_1(&sa->ctrl, 0, SA_HASH_MODE_HASH,
                                 CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF,
                                 SA_SEQ_MASK_OFF, SA_MC_ENABLE,
                                 SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD,
                                 SA_NOT_COPY_HDR);
-       ctx->direction = DIR_INBOUND;
-       sa->sa_contents = SA_HASH160_CONTENTS;
-       sa_in = (struct dynamic_sa_hash160 *) ctx->sa_in;
        /* Need to zero hash digest in SA */
-       memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest));
-       memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest));
-       sa_in->state_ptr = ctx->state_record_dma_addr;
-       ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx);
+       memset(sa->inner_digest, 0, sizeof(sa->inner_digest));
+       memset(sa->outer_digest, 0, sizeof(sa->outer_digest));
 
        return 0;
 }
@@ -240,29 +280,27 @@ int crypto4xx_hash_init(struct ahash_request *req)
        int ds;
        struct dynamic_sa_ctl *sa;
 
-       sa = (struct dynamic_sa_ctl *) ctx->sa_in;
+       sa = ctx->sa_in;
        ds = crypto_ahash_digestsize(
                        __crypto_ahash_cast(req->base.tfm));
        sa->sa_command_0.bf.digest_len = ds >> 2;
        sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA;
-       ctx->is_hash = 1;
-       ctx->direction = DIR_INBOUND;
 
        return 0;
 }
 
 int crypto4xx_hash_update(struct ahash_request *req)
 {
+       struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
        struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct scatterlist dst;
+       unsigned int ds = crypto_ahash_digestsize(ahash);
 
-       ctx->is_hash = 1;
-       ctx->hash_final = 0;
-       ctx->pd_ctl = 0x11;
-       ctx->direction = DIR_INBOUND;
+       sg_init_one(&dst, req->result, ds);
 
-       return crypto4xx_build_pd(&req->base, ctx, req->src,
-                                 (struct scatterlist *) req->result,
-                                 req->nbytes, NULL, 0);
+       return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+                                 req->nbytes, NULL, 0, ctx->sa_in,
+                                 ctx->sa_len);
 }
 
 int crypto4xx_hash_final(struct ahash_request *req)
@@ -272,15 +310,16 @@ int crypto4xx_hash_final(struct ahash_request *req)
 
 int crypto4xx_hash_digest(struct ahash_request *req)
 {
+       struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
        struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
+       struct scatterlist dst;
+       unsigned int ds = crypto_ahash_digestsize(ahash);
 
-       ctx->hash_final = 1;
-       ctx->pd_ctl = 0x11;
-       ctx->direction = DIR_INBOUND;
+       sg_init_one(&dst, req->result, ds);
 
-       return crypto4xx_build_pd(&req->base, ctx, req->src,
-                                 (struct scatterlist *) req->result,
-                                 req->nbytes, NULL, 0);
+       return crypto4xx_build_pd(&req->base, ctx, req->src, &dst,
+                                 req->nbytes, NULL, 0, ctx->sa_in,
+                                 ctx->sa_len);
 }
 
 /**