psa: Add mbedtls_psa_cipher_encrypt/decrypt_setup functions

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 94d0c05..1c9905c 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -29,6 +29,7 @@
 #include "psa_crypto_service_integration.h"
 #include "psa/crypto.h"
 
+#include "psa_crypto_cipher.h"
 #include "psa_crypto_core.h"
 #include "psa_crypto_invasive.h"
 #include "psa_crypto_driver_wrappers.h"
@@ -3379,100 +3380,6 @@
 /* Symmetric cryptography */
 /****************************************************************/
 
-static psa_status_t psa_cipher_setup_internal(
-    psa_cipher_operation_t *operation,
-    const psa_key_attributes_t *attributes,
-    const uint8_t *key_buffer, size_t key_buffer_size,
-    psa_algorithm_t alg,
-    mbedtls_operation_t cipher_operation )
-{
-    int ret = 0;
-    size_t key_bits;
-    const mbedtls_cipher_info_t *cipher_info = NULL;
-    psa_key_type_t key_type = attributes->core.type;
-
-    (void)key_buffer_size;
-
-    /* Proceed with initializing an mbed TLS cipher context if no driver is
-     * available for the given algorithm & key. */
-    mbedtls_cipher_init( &operation->ctx.cipher );
-
-    /* Once the cipher context is initialised, it needs to be freed using
-     * psa_cipher_abort. Indicate there is something to be freed through setting
-     * alg, and indicate the operation is being done using mbedtls crypto through
-     * setting mbedtls_in_use. */
-    operation->alg = alg;
-    operation->mbedtls_in_use = 1;
-
-    key_bits = attributes->core.bits;
-    cipher_info = mbedtls_cipher_info_from_psa( alg, key_type,
-                                                key_bits, NULL );
-    if( cipher_info == NULL )
-        return( PSA_ERROR_NOT_SUPPORTED );
-
-    ret = mbedtls_cipher_setup( &operation->ctx.cipher, cipher_info );
-    if( ret != 0 )
-        goto exit;
-
-#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DES)
-    if( key_type == PSA_KEY_TYPE_DES && key_bits == 128 )
-    {
-        /* Two-key Triple-DES is 3-key Triple-DES with K1=K3 */
-        uint8_t keys[24];
-        memcpy( keys, key_buffer, 16 );
-        memcpy( keys + 16, key_buffer, 8 );
-        ret = mbedtls_cipher_setkey( &operation->ctx.cipher,
-                                     keys,
-                                     192, cipher_operation );
-    }
-    else
-#endif
-    {
-        ret = mbedtls_cipher_setkey( &operation->ctx.cipher, key_buffer,
-                                     (int) key_bits, cipher_operation );
-    }
-    if( ret != 0 )
-        goto exit;
-
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \
-    defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7)
-    switch( alg )
-    {
-        case PSA_ALG_CBC_NO_PADDING:
-            ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
-                                                   MBEDTLS_PADDING_NONE );
-            break;
-        case PSA_ALG_CBC_PKCS7:
-            ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
-                                                   MBEDTLS_PADDING_PKCS7 );
-            break;
-        default:
-            /* The algorithm doesn't involve padding. */
-            ret = 0;
-            break;
-    }
-    if( ret != 0 )
-        goto exit;
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING || MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 */
-
-    operation->block_size = ( PSA_ALG_IS_STREAM_CIPHER( alg ) ? 1 :
-                              PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type ) );
-    if( ( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG ) != 0 &&
-        alg != PSA_ALG_ECB_NO_PADDING )
-    {
-        operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type );
-    }
-#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20)
-    else
-    if( ( alg == PSA_ALG_STREAM_CIPHER ) &&
-        ( key_type == PSA_KEY_TYPE_CHACHA20 ) )
-        operation->iv_size = 12;
-#endif
-
-exit:
-    return( mbedtls_to_psa_error( ret ) );
-}
-
 static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation,
                                       mbedtls_svc_key_id_t key,
                                       psa_algorithm_t alg,
@@ -3535,10 +3442,17 @@
     psa_key_attributes_t attributes = {
       .core = slot->attr
     };
-    status = psa_cipher_setup_internal( operation, &attributes,
-                                        slot->key.data,
-                                        slot->key.bytes,
-                                        alg, cipher_operation );
+    /* Try doing the operation through a driver before using software fallback. */
+    if( cipher_operation == MBEDTLS_ENCRYPT )
+        status = mbedtls_psa_cipher_encrypt_setup( operation, &attributes,
+                                                   slot->key.data,
+                                                   slot->key.bytes,
+                                                   alg );
+    else
+        status = mbedtls_psa_cipher_decrypt_setup( operation, &attributes,
+                                                   slot->key.data,
+                                                   slot->key.bytes,
+                                                   alg );
 
 exit:
     if( status == PSA_SUCCESS )
diff --git a/library/psa_crypto_cipher.c b/library/psa_crypto_cipher.c
index d6ad902..73a2dab 100644
--- a/library/psa_crypto_cipher.c
+++ b/library/psa_crypto_cipher.c
@@ -23,5 +23,124 @@
 #if defined(MBEDTLS_PSA_CRYPTO_C)
 
 #include <psa_crypto_cipher.h>
+#include "psa_crypto_core.h"
+#include "mbedtls/cipher.h"
 
+#include <string.h>
+
+static psa_status_t cipher_setup(
+    psa_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg,
+    mbedtls_operation_t cipher_operation )
+{
+    int ret = 0;
+    size_t key_bits;
+    const mbedtls_cipher_info_t *cipher_info = NULL;
+    psa_key_type_t key_type = attributes->core.type;
+
+    (void)key_buffer_size;
+
+    /* Proceed with initializing an mbed TLS cipher context if no driver is
+     * available for the given algorithm & key. */
+    mbedtls_cipher_init( &operation->ctx.cipher );
+
+    /* Once the cipher context is initialised, it needs to be freed using
+     * psa_cipher_abort. Indicate there is something to be freed through setting
+     * alg, and indicate the operation is being done using mbedtls crypto through
+     * setting mbedtls_in_use. */
+    operation->alg = alg;
+    operation->mbedtls_in_use = 1;
+
+    key_bits = attributes->core.bits;
+    cipher_info = mbedtls_cipher_info_from_psa( alg, key_type,
+                                                key_bits, NULL );
+    if( cipher_info == NULL )
+        return( PSA_ERROR_NOT_SUPPORTED );
+
+    ret = mbedtls_cipher_setup( &operation->ctx.cipher, cipher_info );
+    if( ret != 0 )
+        goto exit;
+
+#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DES)
+    if( key_type == PSA_KEY_TYPE_DES && key_bits == 128 )
+    {
+        /* Two-key Triple-DES is 3-key Triple-DES with K1=K3 */
+        uint8_t keys[24];
+        memcpy( keys, key_buffer, 16 );
+        memcpy( keys + 16, key_buffer, 8 );
+        ret = mbedtls_cipher_setkey( &operation->ctx.cipher,
+                                     keys,
+                                     192, cipher_operation );
+    }
+    else
+#endif
+    {
+        ret = mbedtls_cipher_setkey( &operation->ctx.cipher, key_buffer,
+                                     (int) key_bits, cipher_operation );
+    }
+    if( ret != 0 )
+        goto exit;
+
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7)
+    switch( alg )
+    {
+        case PSA_ALG_CBC_NO_PADDING:
+            ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
+                                                   MBEDTLS_PADDING_NONE );
+            break;
+        case PSA_ALG_CBC_PKCS7:
+            ret = mbedtls_cipher_set_padding_mode( &operation->ctx.cipher,
+                                                   MBEDTLS_PADDING_PKCS7 );
+            break;
+        default:
+            /* The algorithm doesn't involve padding. */
+            ret = 0;
+            break;
+    }
+    if( ret != 0 )
+        goto exit;
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING || MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7 */
+
+    operation->block_size = ( PSA_ALG_IS_STREAM_CIPHER( alg ) ? 1 :
+                              PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type ) );
+    if( ( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG ) != 0 &&
+        alg != PSA_ALG_ECB_NO_PADDING )
+    {
+        operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type );
+    }
+#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20)
+    else
+    if( ( alg == PSA_ALG_STREAM_CIPHER ) &&
+        ( key_type == PSA_KEY_TYPE_CHACHA20 ) )
+        operation->iv_size = 12;
+#endif
+
+exit:
+    return( mbedtls_to_psa_error( ret ) );
+}
+
+psa_status_t mbedtls_psa_cipher_encrypt_setup(
+    psa_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg )
+{
+    return( cipher_setup( operation, attributes,
+                          key_buffer, key_buffer_size,
+                          alg, MBEDTLS_ENCRYPT ) );
+}
+
+psa_status_t mbedtls_psa_cipher_decrypt_setup(
+    psa_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg )
+{
+    return( cipher_setup( operation, attributes,
+                          key_buffer, key_buffer_size,
+                          alg, MBEDTLS_DECRYPT ) );
+}
 #endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/library/psa_crypto_cipher.h b/library/psa_crypto_cipher.h
index 223da77..e3231fc 100644
--- a/library/psa_crypto_cipher.h
+++ b/library/psa_crypto_cipher.h
@@ -23,4 +23,64 @@
 
 #include <psa/crypto.h>
 
+/**
+ * \brief Set the key for a multipart symmetric encryption operation.
+ *
+ * \note The signature of this function is that of a PSA driver
+ *       cipher_encrypt_setup entry point. This function behaves as a
+ *       cipher_encrypt_setup entry point as defined in the PSA driver
+ *       interface specification for transparent drivers.
+ *
+ * \param[in,out] operation     The operation object to set up. It has been
+ *                              initialized as per the documentation for
+ *                              #psa_cipher_operation_t and not yet in use.
+ * \param[in] attributes        The attributes of the key to use for the
+ *                              operation.
+ * \param[in] key_buffer        The buffer containing the key context.
+ * \param[in] key_buffer_size   Size of the \p key_buffer buffer in bytes.
+ * \param[in] alg               The cipher algorithm to compute
+ *                              (\c PSA_ALG_XXX value such that
+ *                              #PSA_ALG_IS_CIPHER(\p alg) is true).
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t mbedtls_psa_cipher_encrypt_setup(
+    psa_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg );
+
+/**
+ * \brief Set the key for a multipart symmetric decryption operation.
+ *
+ * \note The signature of this function is that of a PSA driver
+ *       cipher_decrypt_setup entry point. This function behaves as a
+ *       cipher_decrypt_setup entry point as defined in the PSA driver
+ *       interface specification for transparent drivers.
+ *
+ * \param[in,out] operation     The operation object to set up. It has been
+ *                              initialized as per the documentation for
+ *                              #psa_cipher_operation_t and not yet in use.
+ * \param[in] attributes        The attributes of the key to use for the
+ *                              operation.
+ * \param[in] key_buffer        The buffer containing the key context.
+ * \param[in] key_buffer_size   Size of the \p key_buffer buffer in bytes.
+ * \param[in] alg               The cipher algorithm to compute
+ *                              (\c PSA_ALG_XXX value such that
+ *                              #PSA_ALG_IS_CIPHER(\p alg) is true).
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t mbedtls_psa_cipher_decrypt_setup(
+    psa_cipher_operation_t *operation,
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg );
+
 #endif /* PSA_CRYPTO_CIPHER_H */