diff --git a/programs/.gitignore b/programs/.gitignore index d58253d49..453ae0d13 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -29,6 +29,7 @@ pkey/rsa_sign pkey/rsa_sign_pss pkey/rsa_verify pkey/rsa_verify_pss +psa/crypto_examples psa/psa_constant_names psa/psa_constant_names_generated.c psa/key_ladder_demo diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 4cdae7821..661b12071 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(aes) add_subdirectory(hash) add_subdirectory(pkey) +add_subdirectory(psa) add_subdirectory(random) add_subdirectory(ssl) add_subdirectory(test) diff --git a/programs/Makefile b/programs/Makefile index 9e1a5279e..b1534071c 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -60,6 +60,7 @@ APPS = aes/aescrypt2$(EXEXT) aes/crypt_and_hash$(EXEXT) \ pkey/rsa_decrypt$(EXEXT) pkey/rsa_encrypt$(EXEXT) \ pkey/rsa_sign$(EXEXT) pkey/rsa_verify$(EXEXT) \ pkey/rsa_sign_pss$(EXEXT) pkey/rsa_verify_pss$(EXEXT) \ + psa/crypto_examples$(EXEXT) \ psa/key_ladder_demo$(EXEXT) psa/psa_constant_names$(EXEXT) \ ssl/dtls_client$(EXEXT) ssl/dtls_server$(EXEXT) \ ssl/ssl_client1$(EXEXT) ssl/ssl_client2$(EXEXT) \ @@ -308,6 +309,10 @@ x509/req_app$(EXEXT): x509/req_app.c $(DEP) echo " CC x509/req_app.c" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) x509/req_app.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ +psa/crypto_examples$(EXEXT): psa/crypto_examples.c $(DEP) + echo " CC psa/crypto_examples.c" + $(CC) $(LOCAL_CFLAGS) $(CFLAGS) psa/crypto_examples.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ + clean: ifndef WINDOWS rm -f $(APPS) $(EXTRA_GENERATED) diff --git a/programs/psa/CMakeLists.txt b/programs/psa/CMakeLists.txt new file mode 100644 index 000000000..a0fe803d7 --- /dev/null +++ b/programs/psa/CMakeLists.txt @@ -0,0 +1,7 @@ +add_executable(crypto_examples crypto_examples.c) +target_link_libraries(crypto_examples mbedtls) + +install(TARGETS crypto_examples + DESTINATION "bin" + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + diff --git a/programs/psa/crypto_examples.c b/programs/psa/crypto_examples.c new file mode 100644 index 000000000..e8b64f19a --- /dev/null +++ b/programs/psa/crypto_examples.c @@ -0,0 +1,331 @@ +#include "psa/crypto.h" +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#define ASSERT( predicate ) \ + do \ + { \ + if( ! ( predicate ) ) \ + { \ + mbedtls_printf( "\tassertion failed at %s:%d - '%s'\r\n", \ + __FILE__, __LINE__, #predicate); \ + goto exit; \ + } \ + } while ( 0 ) + +#define ASSERT_STATUS( actual, expected ) \ + do \ + { \ + if( ( actual ) != ( expected ) ) \ + { \ + mbedtls_printf( "\tassertion failed at %s:%d - " \ + "actual:%d expected:%d\r\n", __FILE__, __LINE__, \ + (psa_status_t) actual, (psa_status_t) expected ); \ + goto exit; \ + } \ + } while ( 0 ) + +#if !defined(MBEDTLS_PSA_CRYPTO_C) || !defined(MBEDTLS_AES_C) || \ + !defined(MBEDTLS_CIPHER_MODE_CBC) || !defined(MBEDTLS_CIPHER_MODE_CTR) || \ + !defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int main( void ) +{ + mbedtls_printf( "MBEDTLS_PSA_CRYPTO_C and/or MBEDTLS_AES_C and/or " + "MBEDTLS_CIPHER_MODE_CBC and/or MBEDTLS_CIPHER_MODE_CTR " + "and/or MBEDTLS_CIPHER_MODE_WITH_PADDING " + "not defined.\r\n" ); + return( 0 ); +} +#else + +/* Use key slot 1 for our cipher key. Key slot 0 is reserved as unused. */ +static const psa_key_slot_t key_slot_cipher = 1; + +static psa_status_t set_key_policy( psa_key_slot_t key_slot, + psa_key_usage_t key_usage, + psa_algorithm_t alg ) +{ + psa_status_t status; + psa_key_policy_t policy; + + psa_key_policy_init( &policy ); + psa_key_policy_set_usage( &policy, key_usage, alg ); + status = psa_set_key_policy( key_slot, &policy ); + ASSERT_STATUS( status, PSA_SUCCESS ); +exit: + return( status ); +} + +static psa_status_t cipher_operation( psa_cipher_operation_t *operation, + const uint8_t * input, + size_t input_size, + size_t part_size, + uint8_t * output, + size_t output_size, + size_t *output_len ) +{ + psa_status_t status; + size_t bytes_to_write = 0, bytes_written = 0, len = 0; + + *output_len = 0; + while( bytes_written != input_size ) + { + bytes_to_write = ( input_size - bytes_written > part_size ? + part_size : + input_size - bytes_written ); + + status = psa_cipher_update( operation, input + bytes_written, + bytes_to_write, output + *output_len, + output_size - *output_len, &len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + bytes_written += bytes_to_write; + *output_len += len; + } + + status = psa_cipher_finish( operation, output + *output_len, + output_size - *output_len, &len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + *output_len += len; + +exit: + return( status ); +} + +static psa_status_t cipher_encrypt( psa_key_slot_t key_slot, + psa_algorithm_t alg, + uint8_t * iv, + size_t iv_size, + const uint8_t * input, + size_t input_size, + size_t part_size, + uint8_t * output, + size_t output_size, + size_t *output_len ) +{ + psa_status_t status; + psa_cipher_operation_t operation; + size_t iv_len = 0; + + memset( &operation, 0, sizeof( operation ) ); + status = psa_cipher_encrypt_setup( &operation, key_slot, alg ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = psa_cipher_generate_iv( &operation, iv, iv_size, &iv_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_operation( &operation, input, input_size, part_size, + output, output_size, output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + +exit: + psa_cipher_abort( &operation ); + return( status ); +} + +static psa_status_t cipher_decrypt( psa_key_slot_t key_slot, + psa_algorithm_t alg, + const uint8_t * iv, + size_t iv_size, + const uint8_t * input, + size_t input_size, + size_t part_size, + uint8_t * output, + size_t output_size, + size_t *output_len ) +{ + psa_status_t status; + psa_cipher_operation_t operation; + + memset( &operation, 0, sizeof( operation ) ); + status = psa_cipher_decrypt_setup( &operation, key_slot, alg ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = psa_cipher_set_iv( &operation, iv, iv_size ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_operation( &operation, input, input_size, part_size, + output, output_size, output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + +exit: + psa_cipher_abort( &operation ); + return( status ); +} + +static psa_status_t +cipher_example_encrypt_decrypt_aes_cbc_nopad_1_block( void ) +{ + enum { + block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( PSA_KEY_TYPE_AES ), + key_bits = 256, + part_size = block_size, + }; + const psa_algorithm_t alg = PSA_ALG_CBC_BASE | + PSA_ALG_BLOCK_CIPHER_PAD_NONE; + + psa_status_t status; + size_t output_len = 0; + uint8_t iv[block_size]; + uint8_t input[block_size]; + uint8_t encrypt[block_size]; + uint8_t decrypt[block_size]; + + status = psa_generate_random( input, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = set_key_policy( key_slot_cipher, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, + alg ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = psa_generate_key( key_slot_cipher, PSA_KEY_TYPE_AES, key_bits, + NULL, 0 ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_encrypt( key_slot_cipher, alg, iv, sizeof( iv ), + input, sizeof( input ), part_size, + encrypt, sizeof( encrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_decrypt( key_slot_cipher, alg, iv, sizeof( iv ), + encrypt, output_len, part_size, + decrypt, sizeof( decrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = memcmp( input, decrypt, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + +exit: + psa_destroy_key( key_slot_cipher ); + return( status ); +} + +static psa_status_t cipher_example_encrypt_decrypt_aes_cbc_pkcs7_multi( void ) +{ + enum { + block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( PSA_KEY_TYPE_AES ), + key_bits = 256, + input_size = 100, + part_size = 10, + }; + + const psa_algorithm_t alg = PSA_ALG_CBC_BASE | + PSA_ALG_BLOCK_CIPHER_PAD_PKCS7; + + psa_status_t status; + size_t output_len = 0; + uint8_t iv[block_size], input[input_size], + encrypt[input_size + block_size], decrypt[input_size + block_size]; + + status = psa_generate_random( input, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = set_key_policy( key_slot_cipher, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, + alg ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = psa_generate_key( key_slot_cipher, PSA_KEY_TYPE_AES, key_bits, + NULL, 0 ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_encrypt( key_slot_cipher, alg, iv, sizeof( iv ), + input, sizeof( input ), part_size, + encrypt, sizeof( encrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_decrypt( key_slot_cipher, alg, iv, sizeof( iv ), + encrypt, output_len, part_size, + decrypt, sizeof( decrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = memcmp( input, decrypt, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + +exit: + psa_destroy_key( key_slot_cipher ); + return( status ); +} + +static psa_status_t cipher_example_encrypt_decrypt_aes_ctr_multi( void ) +{ + enum { + block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( PSA_KEY_TYPE_AES ), + key_bits = 256, + input_size = 100, + part_size = 10, + }; + const psa_algorithm_t alg = PSA_ALG_CTR; + + psa_status_t status; + size_t output_len = 0; + uint8_t iv[block_size], input[input_size], encrypt[input_size], + decrypt[input_size]; + + status = psa_generate_random( input, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = set_key_policy( key_slot_cipher, + PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT, + alg ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = psa_generate_key( key_slot_cipher, PSA_KEY_TYPE_AES, key_bits, + NULL, 0 ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_encrypt( key_slot_cipher, alg, iv, sizeof( iv ), + input, sizeof( input ), part_size, + encrypt, sizeof( encrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = cipher_decrypt( key_slot_cipher, alg, iv, sizeof( iv ), + encrypt, output_len, part_size, + decrypt, sizeof( decrypt ), &output_len ); + ASSERT_STATUS( status, PSA_SUCCESS ); + + status = memcmp( input, decrypt, sizeof( input ) ); + ASSERT_STATUS( status, PSA_SUCCESS ); + +exit: + psa_destroy_key( key_slot_cipher ); + return( status ); +} + +static void cipher_examples( void ) +{ + psa_status_t status; + + mbedtls_printf( "cipher encrypt/decrypt AES CBC no padding:\r\n" ); + status = cipher_example_encrypt_decrypt_aes_cbc_nopad_1_block( ); + if( status == PSA_SUCCESS ) + mbedtls_printf( "\tsuccess!\r\n" ); + + mbedtls_printf( "cipher encrypt/decrypt AES CBC PKCS7 multipart:\r\n" ); + status = cipher_example_encrypt_decrypt_aes_cbc_pkcs7_multi( ); + if( status == PSA_SUCCESS ) + mbedtls_printf( "\tsuccess!\r\n" ); + + mbedtls_printf( "cipher encrypt/decrypt AES CTR multipart:\r\n" ); + status = cipher_example_encrypt_decrypt_aes_ctr_multi( ); + if( status == PSA_SUCCESS ) + mbedtls_printf( "\tsuccess!\r\n" ); +} + +int main( void ) +{ + ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + cipher_examples( ); +exit: + mbedtls_psa_crypto_free( ); + return( 0 ); +} +#endif /* MBEDTLS_PSA_CRYPTO_C && MBEDTLS_AES_C && MBEDTLS_CIPHER_MODE_CBC && + MBEDTLS_CIPHER_MODE_CTR && MBEDTLS_CIPHER_MODE_WITH_PADDING */