crypto: inside-secure - implement IV retrieval
authorAntoine Tenart <antoine.tenart@bootlin.com>
Mon, 27 May 2019 14:51:03 +0000 (16:51 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 6 Jun 2019 06:38:56 +0000 (14:38 +0800)
This patch adds support for retrieving intermediate IV from the crypto
engine when using the CBC block mode with AES and (3)DES. The retrieved
IV is copied to the request IV buffer, as requested by the kernel crypto
API.

This fix boot tests added by
commit 8efd972ef96a ("crypto: testmgr - support checking skcipher output IV").

Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/inside-secure/safexcel.h
drivers/crypto/inside-secure/safexcel_cipher.c

index 0bc8859f9d06f19e5c9e575c3c564b24a0030bbe..ca6ece5607cdd967d7e29ed4b53690c93bdc9ef3 100644 (file)
@@ -339,6 +339,7 @@ struct safexcel_context_record {
 #define CONTEXT_CONTROL_IV3                    BIT(8)
 #define CONTEXT_CONTROL_DIGEST_CNT             BIT(9)
 #define CONTEXT_CONTROL_COUNTER_MODE           BIT(10)
+#define CONTEXT_CONTROL_CRYPTO_STORE           BIT(12)
 #define CONTEXT_CONTROL_HASH_STORE             BIT(19)
 
 /* The hash counter given to the engine in the context has a granularity of
@@ -431,6 +432,10 @@ struct safexcel_token {
 
 #define EIP197_TOKEN_HASH_RESULT_VERIFY                BIT(16)
 
+#define EIP197_TOKEN_CTX_OFFSET(x)             (x)
+#define EIP197_TOKEN_DIRECTION_EXTERNAL                BIT(11)
+#define EIP197_TOKEN_EXEC_IF_SUCCESSFUL                (0x1 << 12)
+
 #define EIP197_TOKEN_STAT_LAST_HASH            BIT(0)
 #define EIP197_TOKEN_STAT_LAST_PACKET          BIT(1)
 #define EIP197_TOKEN_OPCODE_DIRECTION          0x0
@@ -438,6 +443,7 @@ struct safexcel_token {
 #define EIP197_TOKEN_OPCODE_NOOP               EIP197_TOKEN_OPCODE_INSERT
 #define EIP197_TOKEN_OPCODE_RETRIEVE           0x4
 #define EIP197_TOKEN_OPCODE_VERIFY             0xd
+#define EIP197_TOKEN_OPCODE_CTX_ACCESS         0xe
 #define EIP197_TOKEN_OPCODE_BYPASS             GENMASK(3, 0)
 
 static inline void eip197_noop_token(struct safexcel_token *token)
@@ -448,6 +454,8 @@ static inline void eip197_noop_token(struct safexcel_token *token)
 
 /* Instructions */
 #define EIP197_TOKEN_INS_INSERT_HASH_DIGEST    0x1c
+#define EIP197_TOKEN_INS_ORIGIN_IV0            0x14
+#define EIP197_TOKEN_INS_ORIGIN_LEN(x)         ((x) << 5)
 #define EIP197_TOKEN_INS_TYPE_OUTPUT           BIT(5)
 #define EIP197_TOKEN_INS_TYPE_HASH             BIT(6)
 #define EIP197_TOKEN_INS_TYPE_CRYTO            BIT(7)
index aca1cdf333623d4bca4e8111a501d8cd1c17fd05..cedfb121c27859c9cd32bc769b56d957e4c6baa8 100644 (file)
@@ -59,26 +59,26 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
                                    u32 length)
 {
        struct safexcel_token *token;
-       unsigned offset = 0;
+       u32 offset = 0, block_sz = 0;
 
        if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
                switch (ctx->alg) {
                case SAFEXCEL_DES:
-                       offset = DES_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, DES_BLOCK_SIZE);
+                       block_sz = DES_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
                        break;
                case SAFEXCEL_3DES:
-                       offset = DES3_EDE_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, DES3_EDE_BLOCK_SIZE);
+                       block_sz = DES3_EDE_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_2_TOKEN_IV_CMD;
                        break;
                case SAFEXCEL_AES:
-                       offset = AES_BLOCK_SIZE / sizeof(u32);
-                       memcpy(cdesc->control_data.token, iv, AES_BLOCK_SIZE);
+                       block_sz = AES_BLOCK_SIZE;
                        cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
                        break;
                }
+
+               offset = block_sz / sizeof(u32);
+               memcpy(cdesc->control_data.token, iv, block_sz);
        }
 
        token = (struct safexcel_token *)(cdesc->control_data.token + offset);
@@ -90,6 +90,25 @@ static void safexcel_skcipher_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
        token[0].instructions = EIP197_TOKEN_INS_LAST |
                                EIP197_TOKEN_INS_TYPE_CRYTO |
                                EIP197_TOKEN_INS_TYPE_OUTPUT;
+
+       if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+               u32 last = (EIP197_MAX_TOKENS - 1) - offset;
+
+               token[last].opcode = EIP197_TOKEN_OPCODE_CTX_ACCESS;
+               token[last].packet_length = EIP197_TOKEN_DIRECTION_EXTERNAL |
+                                           EIP197_TOKEN_EXEC_IF_SUCCESSFUL|
+                                           EIP197_TOKEN_CTX_OFFSET(0x2);
+               token[last].stat = EIP197_TOKEN_STAT_LAST_HASH |
+                       EIP197_TOKEN_STAT_LAST_PACKET;
+               token[last].instructions =
+                       EIP197_TOKEN_INS_ORIGIN_LEN(block_sz / sizeof(u32)) |
+                       EIP197_TOKEN_INS_ORIGIN_IV0;
+
+               /* Store the updated IV values back in the internal context
+                * registers.
+                */
+               cdesc->control_data.control1 |= CONTEXT_CONTROL_CRYPTO_STORE;
+       }
 }
 
 static void safexcel_aead_token(struct safexcel_cipher_ctx *ctx, u8 *iv,
@@ -559,6 +578,7 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv,
 {
        struct skcipher_request *req = skcipher_request_cast(async);
        struct safexcel_cipher_req *sreq = skcipher_request_ctx(req);
+       struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(async->tfm);
        int err;
 
        if (sreq->needs_inv) {
@@ -569,6 +589,24 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv,
                err = safexcel_handle_req_result(priv, ring, async, req->src,
                                                 req->dst, req->cryptlen, sreq,
                                                 should_complete, ret);
+
+               if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CBC) {
+                       u32 block_sz = 0;
+
+                       switch (ctx->alg) {
+                       case SAFEXCEL_DES:
+                               block_sz = DES_BLOCK_SIZE;
+                               break;
+                       case SAFEXCEL_3DES:
+                               block_sz = DES3_EDE_BLOCK_SIZE;
+                               break;
+                       case SAFEXCEL_AES:
+                               block_sz = AES_BLOCK_SIZE;
+                               break;
+                       }
+
+                       memcpy(req->iv, ctx->base.ctxr->data, block_sz);
+               }
        }
 
        return err;