Implement ChaCha20 and ChaCha20-Poly1305

Smoke tests: test data for ChaCha20 calculated with PyCryptodome; test
vector from RFC 7539 for ChaCha20-Poly1305.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 3e3c5eb..7794e7a 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -51,6 +51,8 @@
 #include "mbedtls/bignum.h"
 #include "mbedtls/blowfish.h"
 #include "mbedtls/camellia.h"
+#include "mbedtls/chacha20.h"
+#include "mbedtls/chachapoly.h"
 #include "mbedtls/cipher.h"
 #include "mbedtls/ccm.h"
 #include "mbedtls/cmac.h"
@@ -179,6 +181,14 @@
         case MBEDTLS_ERR_CCM_HW_ACCEL_FAILED:
             return( PSA_ERROR_HARDWARE_FAILURE );
 
+        case MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA:
+            return( PSA_ERROR_INVALID_ARGUMENT );
+
+        case MBEDTLS_ERR_CHACHAPOLY_BAD_STATE:
+            return( PSA_ERROR_BAD_STATE );
+        case MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED:
+            return( PSA_ERROR_INVALID_SIGNATURE );
+
         case MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE:
             return( PSA_ERROR_NOT_SUPPORTED );
         case MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA:
@@ -466,6 +476,12 @@
                 return( PSA_ERROR_INVALID_ARGUMENT );
             break;
 #endif
+#if defined(MBEDTLS_CHACHA20_C)
+        case PSA_KEY_TYPE_CHACHA20:
+            if( bits != 256 )
+                return( PSA_ERROR_INVALID_ARGUMENT );
+            break;
+#endif
         default:
             return( PSA_ERROR_NOT_SUPPORTED );
     }
@@ -2026,6 +2042,7 @@
         switch( alg )
         {
             case PSA_ALG_ARC4:
+            case PSA_ALG_CHACHA20:
                 mode = MBEDTLS_MODE_STREAM;
                 break;
             case PSA_ALG_CTR:
@@ -2049,6 +2066,9 @@
             case PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_GCM, 0 ):
                 mode = MBEDTLS_MODE_GCM;
                 break;
+            case PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_CHACHA20_POLY1305, 0 ):
+                mode = MBEDTLS_MODE_CHACHAPOLY;
+                break;
             default:
                 return( NULL );
         }
@@ -2084,6 +2104,9 @@
         case PSA_KEY_TYPE_ARC4:
             cipher_id_tmp = MBEDTLS_CIPHER_ID_ARC4;
             break;
+        case PSA_KEY_TYPE_CHACHA20:
+            cipher_id_tmp = MBEDTLS_CIPHER_ID_CHACHA20;
+            break;
         default:
             return( NULL );
     }
@@ -3318,6 +3341,11 @@
     {
         operation->iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type );
     }
+#if defined(MBEDTLS_CHACHA20_C)
+    else
+    if( alg == PSA_ALG_CHACHA20 )
+        operation->iv_size = 12;
+#endif
 
 exit:
     if( status == 0 )
@@ -3631,6 +3659,9 @@
 #if defined(MBEDTLS_GCM_C)
         mbedtls_gcm_context gcm;
 #endif /* MBEDTLS_GCM_C */
+#if defined(MBEDTLS_CHACHAPOLY_C)
+        mbedtls_chachapoly_context chachapoly;
+#endif /* MBEDTLS_CHACHAPOLY_C */
     } ctx;
     psa_algorithm_t core_alg;
     uint8_t full_tag_length;
@@ -3715,6 +3746,22 @@
             break;
 #endif /* MBEDTLS_GCM_C */
 
+#if defined(MBEDTLS_CHACHAPOLY_C)
+        case PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_CHACHA20_POLY1305, 0 ):
+            operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
+            operation->full_tag_length = 16;
+            /* We only support the default tag length. */
+            if( alg != PSA_ALG_CHACHA20_POLY1305 )
+                return( PSA_ERROR_NOT_SUPPORTED );
+            mbedtls_chachapoly_init( &operation->ctx.chachapoly );
+            status = mbedtls_to_psa_error(
+                mbedtls_chachapoly_setkey( &operation->ctx.chachapoly,
+                                           operation->slot->data.raw.data ) );
+            if( status != 0 )
+                goto cleanup;
+            break;
+#endif /* MBEDTLS_CHACHAPOLY_C */
+
         default:
             return( PSA_ERROR_NOT_SUPPORTED );
     }
@@ -3792,6 +3839,26 @@
     }
     else
 #endif /* MBEDTLS_CCM_C */
+#if defined(MBEDTLS_CHACHAPOLY_C)
+    if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
+    {
+        if( nonce_length != 12 || operation.tag_length != 16 )
+        {
+            status = PSA_ERROR_NOT_SUPPORTED;
+            goto exit;
+        }
+        status = mbedtls_to_psa_error(
+            mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
+                                                plaintext_length,
+                                                nonce,
+                                                additional_data,
+                                                additional_data_length,
+                                                plaintext,
+                                                ciphertext,
+                                                tag ) );
+    }
+    else
+#endif /* MBEDTLS_CHACHAPOLY_C */
     {
         return( PSA_ERROR_NOT_SUPPORTED );
     }
@@ -3883,6 +3950,26 @@
     }
     else
 #endif /* MBEDTLS_CCM_C */
+#if defined(MBEDTLS_CHACHAPOLY_C)
+    if( operation.core_alg == PSA_ALG_CHACHA20_POLY1305 )
+    {
+        if( nonce_length != 12 || operation.tag_length != 16 )
+        {
+            status = PSA_ERROR_NOT_SUPPORTED;
+            goto exit;
+        }
+        status = mbedtls_to_psa_error(
+            mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
+                                             ciphertext_length - operation.tag_length,
+                                             nonce,
+                                             additional_data,
+                                             additional_data_length,
+                                             tag,
+                                             ciphertext,
+                                             plaintext ) );
+    }
+    else
+#endif /* MBEDTLS_CHACHAPOLY_C */
     {
         return( PSA_ERROR_NOT_SUPPORTED );
     }