From 8e478e648fb68ac6f07e4e5cd80a5c1fefcb1cf5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 24 Oct 2022 16:52:24 +0100 Subject: [crypto] Allow initialisation vector length to vary from cipher blocksize Signed-off-by: Michael Brown --- src/tests/cipher_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/tests/cipher_test.c') diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index 800d6c138..5361502ff 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -61,7 +61,7 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, file, line ); - cipher_setiv ( cipher, ctx, test->iv ); + cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); /* Perform encryption */ cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len ); @@ -87,7 +87,7 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, file, line ); - cipher_setiv ( cipher, ctx, test->iv ); + cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); /* Perform encryption */ cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len ); @@ -143,7 +143,7 @@ cipher_cost ( struct cipher_algorithm *cipher, size_t key_len, /* Initialise cipher */ rc = cipher_setkey ( cipher, ctx, key, key_len ); assert ( rc == 0 ); - cipher_setiv ( cipher, ctx, iv ); + cipher_setiv ( cipher, ctx, iv, sizeof ( iv ) ); /* Profile cipher operation */ memset ( &profiler, 0, sizeof ( profiler ) ); -- cgit v1.2.3-55-g7522 From 0c383bf00afbef1a9cfe02829d1bc6ee46e1c16b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 24 Oct 2022 18:49:43 +0100 Subject: [crypto] Add concept of additional data to cipher algorithms Some ciphers (such as GCM) support the concept of additional authenticated data, which does not appear in the ciphertext but may affect the operation of the cipher. Allow cipher_encrypt() and cipher_decrypt() to be called with a NULL destination buffer in order to pass additional data. Signed-off-by: Michael Brown --- src/include/ipxe/crypto.h | 30 +++++++++++++++--------------- src/tests/aes_test.c | 12 ++++++------ src/tests/cipher_test.c | 14 +++++++++++++- src/tests/cipher_test.h | 14 +++++++++++++- 4 files changed, 47 insertions(+), 23 deletions(-) (limited to 'src/tests/cipher_test.c') diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 931be0502..d41448024 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -54,25 +54,25 @@ struct cipher_algorithm { size_t blocksize; /** Set key * - * @v ctx Context - * @v key Key - * @v keylen Key length - * @ret rc Return status code + * @v ctx Context + * @v key Key + * @v keylen Key length + * @ret rc Return status code */ int ( * setkey ) ( void *ctx, const void *key, size_t keylen ); /** Set initialisation vector * - * @v ctx Context - * @v iv Initialisation vector - * @v ivlen Initialisation vector length + * @v ctx Context + * @v iv Initialisation vector + * @v ivlen Initialisation vector length */ void ( * setiv ) ( void *ctx, const void *iv, size_t ivlen ); /** Encrypt data * - * @v ctx Context - * @v src Data to encrypt - * @v dst Buffer for encrypted data - * @v len Length of data + * @v ctx Context + * @v src Data to encrypt + * @v dst Buffer for encrypted data, or NULL for additional data + * @v len Length of data * * @v len is guaranteed to be a multiple of @c blocksize. */ @@ -80,10 +80,10 @@ struct cipher_algorithm { size_t len ); /** Decrypt data * - * @v ctx Context - * @v src Data to decrypt - * @v dst Buffer for decrypted data - * @v len Length of data + * @v ctx Context + * @v src Data to decrypt + * @v dst Buffer for decrypted data, or NULL for additional data + * @v len Length of data * * @v len is guaranteed to be a multiple of @c blocksize. */ diff --git a/src/tests/aes_test.c b/src/tests/aes_test.c index ad66c734c..e7201fca6 100644 --- a/src/tests/aes_test.c +++ b/src/tests/aes_test.c @@ -86,7 +86,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** AES-128-ECB (same test as AES-128-Core) */ CIPHER_TEST ( aes_128_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_128, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST, + AES_KEY_NIST_128, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, @@ -98,7 +98,7 @@ CIPHER_TEST ( aes_128_ecb, &aes_ecb_algorithm, /** AES-128-CBC */ CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm, - AES_KEY_NIST_128, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST, + AES_KEY_NIST_128, AES_IV_NIST_CBC, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, @@ -110,7 +110,7 @@ CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm, /** AES-192-ECB (same test as AES-192-Core) */ CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_192, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST, + AES_KEY_NIST_192, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc, 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, @@ -122,7 +122,7 @@ CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm, /** AES-192-CBC */ CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm, - AES_KEY_NIST_192, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST, + AES_KEY_NIST_192, AES_IV_NIST_CBC, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8, 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, @@ -134,7 +134,7 @@ CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm, /** AES-256-ECB (same test as AES-256-Core) */ CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm, - AES_KEY_NIST_256, AES_IV_NIST_DUMMY, AES_PLAINTEXT_NIST, + AES_KEY_NIST_256, AES_IV_NIST_DUMMY, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8, 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, @@ -146,7 +146,7 @@ CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm, /** AES-256-CBC */ CIPHER_TEST ( aes_256_cbc, &aes_cbc_algorithm, - AES_KEY_NIST_256, AES_IV_NIST_CBC, AES_PLAINTEXT_NIST, + AES_KEY_NIST_256, AES_IV_NIST_CBC, ADDITIONAL(), AES_PLAINTEXT_NIST, CIPHERTEXT ( 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index 5361502ff..c49b4b69b 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -63,6 +63,12 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, file, line ); cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + /* Process additional data, if applicable */ + if ( test->additional_len ) { + cipher_encrypt ( cipher, ctx, test->additional, NULL, + test->additional_len ); + } + /* Perform encryption */ cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len ); @@ -89,7 +95,13 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, file, line ); cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); - /* Perform encryption */ + /* Process additional data, if applicable */ + if ( test->additional_len ) { + cipher_decrypt ( cipher, ctx, test->additional, NULL, + test->additional_len ); + } + + /* Perform decryption */ cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len ); /* Compare against expected plaintext */ diff --git a/src/tests/cipher_test.h b/src/tests/cipher_test.h index d7c5aef8f..4139a7788 100644 --- a/src/tests/cipher_test.h +++ b/src/tests/cipher_test.h @@ -25,6 +25,10 @@ struct cipher_test { const void *iv; /** Length of initialisation vector */ size_t iv_len; + /** Additional data */ + const void *additional; + /** Length of additional data */ + size_t additional_len; /** Plaintext */ const void *plaintext; /** Ciphertext */ @@ -39,6 +43,9 @@ struct cipher_test { /** Define inline initialisation vector */ #define IV(...) { __VA_ARGS__ } +/** Define inline additional data */ +#define ADDITIONAL(...) { __VA_ARGS__ } + /** Define inline plaintext data */ #define PLAINTEXT(...) { __VA_ARGS__ } @@ -52,13 +59,16 @@ struct cipher_test { * @v CIPHER Cipher algorithm * @v KEY Key * @v IV Initialisation vector + * @v ADDITIONAL Additional data * @v PLAINTEXT Plaintext * @v CIPHERTEXT Ciphertext * @ret test Cipher test */ -#define CIPHER_TEST( name, CIPHER, KEY, IV, PLAINTEXT, CIPHERTEXT ) \ +#define CIPHER_TEST( name, CIPHER, KEY, IV, ADDITIONAL, PLAINTEXT, \ + CIPHERTEXT ) \ static const uint8_t name ## _key [] = KEY; \ static const uint8_t name ## _iv [] = IV; \ + static const uint8_t name ## _additional [] = ADDITIONAL; \ static const uint8_t name ## _plaintext [] = PLAINTEXT; \ static const uint8_t name ## _ciphertext \ [ sizeof ( name ## _plaintext ) ] = CIPHERTEXT; \ @@ -68,6 +78,8 @@ struct cipher_test { .key_len = sizeof ( name ## _key ), \ .iv = name ## _iv, \ .iv_len = sizeof ( name ## _iv ), \ + .additional = name ## _additional, \ + .additional_len = sizeof ( name ## _additional ), \ .plaintext = name ## _plaintext, \ .ciphertext = name ## _ciphertext, \ .len = sizeof ( name ## _plaintext ), \ -- cgit v1.2.3-55-g7522 From da81214cec87201dc18c0ce71224367e13a6edfb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 24 Oct 2022 19:20:41 +0100 Subject: [crypto] Add concept of authentication tag to cipher algorithms Some ciphers (such as GCM) support the concept of a tag that can be used to authenticate the encrypted data. Add a cipher method for generating an authentication tag. Signed-off-by: Michael Brown --- src/crypto/aes.c | 2 ++ src/crypto/arc4.c | 2 ++ src/crypto/crypto_null.c | 6 ++++++ src/include/ipxe/cbc.h | 2 ++ src/include/ipxe/crypto.h | 18 ++++++++++++++++++ src/include/ipxe/ecb.h | 2 ++ src/tests/aes_test.c | 12 ++++++------ src/tests/cipher_test.c | 14 ++++++++++++++ src/tests/cipher_test.h | 13 ++++++++++++- 9 files changed, 64 insertions(+), 7 deletions(-) (limited to 'src/tests/cipher_test.c') diff --git a/src/crypto/aes.c b/src/crypto/aes.c index d7393285f..4a7668b6b 100644 --- a/src/crypto/aes.c +++ b/src/crypto/aes.c @@ -783,10 +783,12 @@ struct cipher_algorithm aes_algorithm = { .name = "aes", .ctxsize = sizeof ( struct aes_context ), .blocksize = AES_BLOCKSIZE, + .authsize = 0, .setkey = aes_setkey, .setiv = cipher_null_setiv, .encrypt = aes_encrypt, .decrypt = aes_decrypt, + .auth = cipher_null_auth, }; /* AES in Electronic Codebook mode */ diff --git a/src/crypto/arc4.c b/src/crypto/arc4.c index 0dba2fc59..4d98abead 100644 --- a/src/crypto/arc4.c +++ b/src/crypto/arc4.c @@ -119,8 +119,10 @@ struct cipher_algorithm arc4_algorithm = { .name = "ARC4", .ctxsize = ARC4_CTX_SIZE, .blocksize = 1, + .authsize = 0, .setkey = arc4_setkey, .setiv = cipher_null_setiv, .encrypt = arc4_xor, .decrypt = arc4_xor, + .auth = cipher_null_auth, }; diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index ef6041b5b..26cfbfc4e 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -76,14 +76,20 @@ void cipher_null_decrypt ( void *ctx __unused, const void *src, void *dst, memcpy ( dst, src, len ); } +void cipher_null_auth ( void *ctx __unused, void *auth __unused ) { + /* Do nothing */ +} + struct cipher_algorithm cipher_null = { .name = "null", .ctxsize = 0, .blocksize = 1, + .authsize = 0, .setkey = cipher_null_setkey, .setiv = cipher_null_setiv, .encrypt = cipher_null_encrypt, .decrypt = cipher_null_decrypt, + .auth = cipher_null_auth, }; int pubkey_null_init ( void *ctx __unused, const void *key __unused, diff --git a/src/include/ipxe/cbc.h b/src/include/ipxe/cbc.h index 5c8740365..eead045ed 100644 --- a/src/include/ipxe/cbc.h +++ b/src/include/ipxe/cbc.h @@ -95,10 +95,12 @@ struct cipher_algorithm _cbc_cipher = { \ .name = #_cbc_name, \ .ctxsize = sizeof ( struct _cbc_name ## _context ), \ .blocksize = _blocksize, \ + .authsize = 0, \ .setkey = _cbc_name ## _setkey, \ .setiv = _cbc_name ## _setiv, \ .encrypt = _cbc_name ## _encrypt, \ .decrypt = _cbc_name ## _decrypt, \ + .auth = cipher_null_auth, \ }; #endif /* _IPXE_CBC_H */ diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index d41448024..e807aeb52 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -52,6 +52,8 @@ struct cipher_algorithm { size_t ctxsize; /** Block size */ size_t blocksize; + /** Authentication tag size */ + size_t authsize; /** Set key * * @v ctx Context @@ -89,6 +91,12 @@ struct cipher_algorithm { */ void ( * decrypt ) ( void *ctx, const void *src, void *dst, size_t len ); + /** Generate authentication tag + * + * @v ctx Context + * @v auth Authentication tag + */ + void ( * auth ) ( void *ctx, void *auth ); }; /** A public key algorithm */ @@ -215,10 +223,19 @@ static inline void cipher_decrypt ( struct cipher_algorithm *cipher, cipher_decrypt ( (cipher), (ctx), (src), (dst), (len) ); \ } while ( 0 ) +static inline void cipher_auth ( struct cipher_algorithm *cipher, void *ctx, + void *auth ) { + cipher->auth ( ctx, auth ); +} + static inline int is_stream_cipher ( struct cipher_algorithm *cipher ) { return ( cipher->blocksize == 1 ); } +static inline int is_auth_cipher ( struct cipher_algorithm *cipher ) { + return cipher->authsize; +} + static inline int pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, const void *key, size_t key_len ) { return pubkey->init ( ctx, key, key_len ); @@ -274,6 +291,7 @@ extern void cipher_null_encrypt ( void *ctx, const void *src, void *dst, size_t len ); extern void cipher_null_decrypt ( void *ctx, const void *src, void *dst, size_t len ); +extern void cipher_null_auth ( void *ctx, void *auth ); extern int pubkey_null_init ( void *ctx, const void *key, size_t key_len ); extern size_t pubkey_null_max_len ( void *ctx ); diff --git a/src/include/ipxe/ecb.h b/src/include/ipxe/ecb.h index 6c40c6126..1d2ebf716 100644 --- a/src/include/ipxe/ecb.h +++ b/src/include/ipxe/ecb.h @@ -47,10 +47,12 @@ struct cipher_algorithm _ecb_cipher = { \ .name = #_ecb_name, \ .ctxsize = sizeof ( _raw_context ), \ .blocksize = _blocksize, \ + .authsize = 0, \ .setkey = _ecb_name ## _setkey, \ .setiv = _ecb_name ## _setiv, \ .encrypt = _ecb_name ## _encrypt, \ .decrypt = _ecb_name ## _decrypt, \ + .auth = cipher_null_auth, \ }; #endif /* _IPXE_ECB_H */ diff --git a/src/tests/aes_test.c b/src/tests/aes_test.c index e7201fca6..be119c8d8 100644 --- a/src/tests/aes_test.c +++ b/src/tests/aes_test.c @@ -94,7 +94,7 @@ CIPHER_TEST ( aes_128_ecb, &aes_ecb_algorithm, 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88, 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, - 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4 ) ); + 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4 ), AUTH() ); /** AES-128-CBC */ CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm, @@ -106,7 +106,7 @@ CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm, 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, - 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) ); + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ), AUTH() ); /** AES-192-ECB (same test as AES-192-Core) */ CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm, @@ -118,7 +118,7 @@ CIPHER_TEST ( aes_192_ecb, &aes_ecb_algorithm, 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e, 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, - 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e ) ); + 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e ), AUTH() ); /** AES-192-CBC */ CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm, @@ -130,7 +130,7 @@ CIPHER_TEST ( aes_192_cbc, &aes_cbc_algorithm, 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0, 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, - 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd ) ); + 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd ), AUTH() ); /** AES-256-ECB (same test as AES-256-Core) */ CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm, @@ -142,7 +142,7 @@ CIPHER_TEST ( aes_256_ecb, &aes_ecb_algorithm, 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d, 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, - 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7 ) ); + 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7 ), AUTH() ); /** AES-256-CBC */ CIPHER_TEST ( aes_256_cbc, &aes_cbc_algorithm, @@ -154,7 +154,7 @@ CIPHER_TEST ( aes_256_cbc, &aes_cbc_algorithm, 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, - 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) ); + 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ), AUTH() ); /** * Perform AES self-test diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index c49b4b69b..cc732c2e0 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -57,6 +57,7 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, size_t len = test->len; uint8_t ctx[cipher->ctxsize]; uint8_t ciphertext[len]; + uint8_t auth[cipher->authsize]; /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, @@ -65,6 +66,7 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, /* Process additional data, if applicable */ if ( test->additional_len ) { + okx ( is_auth_cipher ( cipher ), file, line ); cipher_encrypt ( cipher, ctx, test->additional, NULL, test->additional_len ); } @@ -74,6 +76,11 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, /* Compare against expected ciphertext */ okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line ); + + /* Check authentication tag */ + okx ( cipher->authsize == test->auth_len, file, line ); + cipher_auth ( cipher, ctx, auth ); + okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); } /** @@ -89,6 +96,7 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, size_t len = test->len; uint8_t ctx[cipher->ctxsize]; uint8_t plaintext[len]; + uint8_t auth[cipher->authsize]; /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, @@ -97,6 +105,7 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, /* Process additional data, if applicable */ if ( test->additional_len ) { + okx ( is_auth_cipher ( cipher ), file, line ); cipher_decrypt ( cipher, ctx, test->additional, NULL, test->additional_len ); } @@ -106,6 +115,11 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, /* Compare against expected plaintext */ okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line ); + + /* Check authentication tag */ + okx ( cipher->authsize == test->auth_len, file, line ); + cipher_auth ( cipher, ctx, auth ); + okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); } /** diff --git a/src/tests/cipher_test.h b/src/tests/cipher_test.h index 4139a7788..519d12e8d 100644 --- a/src/tests/cipher_test.h +++ b/src/tests/cipher_test.h @@ -35,6 +35,10 @@ struct cipher_test { const void *ciphertext; /** Length of text */ size_t len; + /** Authentication tag */ + const void *auth; + /** Length of authentication tag */ + size_t auth_len; }; /** Define inline key */ @@ -52,6 +56,9 @@ struct cipher_test { /** Define inline ciphertext data */ #define CIPHERTEXT(...) { __VA_ARGS__ } +/** Define inline authentication tag */ +#define AUTH(...) { __VA_ARGS__ } + /** * Define a cipher test * @@ -62,16 +69,18 @@ struct cipher_test { * @v ADDITIONAL Additional data * @v PLAINTEXT Plaintext * @v CIPHERTEXT Ciphertext + * @v AUTH Authentication tag * @ret test Cipher test */ #define CIPHER_TEST( name, CIPHER, KEY, IV, ADDITIONAL, PLAINTEXT, \ - CIPHERTEXT ) \ + CIPHERTEXT, AUTH ) \ static const uint8_t name ## _key [] = KEY; \ static const uint8_t name ## _iv [] = IV; \ static const uint8_t name ## _additional [] = ADDITIONAL; \ static const uint8_t name ## _plaintext [] = PLAINTEXT; \ static const uint8_t name ## _ciphertext \ [ sizeof ( name ## _plaintext ) ] = CIPHERTEXT; \ + static const uint8_t name ## _auth [] = AUTH; \ static struct cipher_test name = { \ .cipher = CIPHER, \ .key = name ## _key, \ @@ -83,6 +92,8 @@ struct cipher_test { .plaintext = name ## _plaintext, \ .ciphertext = name ## _ciphertext, \ .len = sizeof ( name ## _plaintext ), \ + .auth = name ## _auth, \ + .auth_len = sizeof ( name ## _auth ), \ } extern void cipher_encrypt_okx ( struct cipher_test *test, const char *file, -- cgit v1.2.3-55-g7522 From 30243ad73957a2e1cc4aedc3f23be66cdf399f00 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 28 Oct 2022 16:27:10 +0100 Subject: [crypto] Add concept of cipher alignment size The GCM cipher mode of operation (in common with other counter-based modes of operation) has a notion of blocksize that does not neatly fall into our current abstraction: it does operate in 16-byte blocks but allows for an arbitrary overall data length (i.e. the final block may be incomplete). Model this by adding a concept of alignment size. Each call to encrypt() or decrypt() must begin at a multiple of the alignment size from the start of the data stream. This allows us to model GCM by using a block size of 1 byte and an alignment size of 16 bytes. As a side benefit, this same concept allows us to neatly model the fact that raw AES can encrypt only a single 16-byte block, by specifying an alignment size of zero on this cipher. Signed-off-by: Michael Brown --- src/crypto/aes.c | 1 + src/crypto/arc4.c | 1 + src/crypto/crypto_null.c | 1 + src/include/ipxe/cbc.h | 1 + src/include/ipxe/crypto.h | 18 +++++++++++++++++- src/include/ipxe/ecb.h | 1 + src/include/ipxe/gcm.h | 1 + src/tests/cipher_test.c | 10 ++++++++++ 8 files changed, 33 insertions(+), 1 deletion(-) (limited to 'src/tests/cipher_test.c') diff --git a/src/crypto/aes.c b/src/crypto/aes.c index aeeaa1d2c..5200e7760 100644 --- a/src/crypto/aes.c +++ b/src/crypto/aes.c @@ -784,6 +784,7 @@ struct cipher_algorithm aes_algorithm = { .name = "aes", .ctxsize = sizeof ( struct aes_context ), .blocksize = AES_BLOCKSIZE, + .alignsize = 0, .authsize = 0, .setkey = aes_setkey, .setiv = cipher_null_setiv, diff --git a/src/crypto/arc4.c b/src/crypto/arc4.c index 4d98abead..3b6adec19 100644 --- a/src/crypto/arc4.c +++ b/src/crypto/arc4.c @@ -119,6 +119,7 @@ struct cipher_algorithm arc4_algorithm = { .name = "ARC4", .ctxsize = ARC4_CTX_SIZE, .blocksize = 1, + .alignsize = 1, .authsize = 0, .setkey = arc4_setkey, .setiv = cipher_null_setiv, diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index 26cfbfc4e..0ad463c3e 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -84,6 +84,7 @@ struct cipher_algorithm cipher_null = { .name = "null", .ctxsize = 0, .blocksize = 1, + .alignsize = 1, .authsize = 0, .setkey = cipher_null_setkey, .setiv = cipher_null_setiv, diff --git a/src/include/ipxe/cbc.h b/src/include/ipxe/cbc.h index eead045ed..382fc9036 100644 --- a/src/include/ipxe/cbc.h +++ b/src/include/ipxe/cbc.h @@ -95,6 +95,7 @@ struct cipher_algorithm _cbc_cipher = { \ .name = #_cbc_name, \ .ctxsize = sizeof ( struct _cbc_name ## _context ), \ .blocksize = _blocksize, \ + .alignsize = _blocksize, \ .authsize = 0, \ .setkey = _cbc_name ## _setkey, \ .setiv = _cbc_name ## _setiv, \ diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 842f2f633..ba09c9468 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -51,8 +51,24 @@ struct cipher_algorithm { const char *name; /** Context size */ size_t ctxsize; - /** Block size */ + /** Block size + * + * Every call to encrypt() or decrypt() must be for a multiple + * of this size. + */ size_t blocksize; + /** Alignment size + * + * Every call to encrypt() or decrypt() must begin at a + * multiple of this offset from the start of the stream. + * (Equivalently: all but the last call to encrypt() or + * decrypt() must be for a multiple of this size.) + * + * For ciphers supporting additional data, the main data + * stream and additional data stream are both considered to + * begin at offset zero. + */ + size_t alignsize; /** Authentication tag size */ size_t authsize; /** Set key diff --git a/src/include/ipxe/ecb.h b/src/include/ipxe/ecb.h index 1d2ebf716..db22d996d 100644 --- a/src/include/ipxe/ecb.h +++ b/src/include/ipxe/ecb.h @@ -47,6 +47,7 @@ struct cipher_algorithm _ecb_cipher = { \ .name = #_ecb_name, \ .ctxsize = sizeof ( _raw_context ), \ .blocksize = _blocksize, \ + .alignsize = _blocksize, \ .authsize = 0, \ .setkey = _ecb_name ## _setkey, \ .setiv = _ecb_name ## _setiv, \ diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h index 658685486..d93eecd8e 100644 --- a/src/include/ipxe/gcm.h +++ b/src/include/ipxe/gcm.h @@ -121,6 +121,7 @@ struct cipher_algorithm _gcm_cipher = { \ .name = #_gcm_name, \ .ctxsize = sizeof ( struct _gcm_name ## _context ), \ .blocksize = 1, \ + .alignsize = sizeof ( union gcm_block ), \ .authsize = sizeof ( union gcm_block ), \ .setkey = _gcm_name ## _setkey, \ .setiv = _gcm_name ## _setiv, \ diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index cc732c2e0..2ead3c827 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -131,8 +131,18 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, */ void cipher_okx ( struct cipher_test *test, const char *file, unsigned int line ) { + struct cipher_algorithm *cipher = test->cipher; + size_t len = test->len; + /* Sanity checks */ + okx ( cipher->blocksize != 0, file, line ); + okx ( ( len % cipher->blocksize ) == 0, file, line ); + okx ( ( cipher->alignsize % cipher->blocksize ) == 0, file, line ); + + /* Report encryption test result */ cipher_encrypt_okx ( test, file, line ); + + /* Report decryption test result */ cipher_decrypt_okx ( test, file, line ); } -- cgit v1.2.3-55-g7522 From 63fdd9b5816c752120c315c04c1d6878f3c13143 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Nov 2022 16:14:42 +0000 Subject: [tests] Verify ability to reset cipher initialisation vector TLS relies upon the ability to reuse a cipher by resetting only the initialisation vector while reusing the existing key. Add verification of resetting the initialisation vector to the cipher self-tests. Signed-off-by: Michael Brown --- src/tests/cipher_test.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src/tests/cipher_test.c') diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index 2ead3c827..0d0eac1d8 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -81,6 +81,25 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, okx ( cipher->authsize == test->auth_len, file, line ); cipher_auth ( cipher, ctx, auth ); okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); + + /* Reset initialisation vector */ + cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + + /* Process additional data, if applicable */ + if ( test->additional_len ) { + cipher_encrypt ( cipher, ctx, test->additional, NULL, + test->additional_len ); + } + + /* Perform encryption */ + cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len ); + + /* Compare against expected ciphertext */ + okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line ); + + /* Check authentication tag */ + cipher_auth ( cipher, ctx, auth ); + okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); } /** @@ -120,6 +139,25 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, okx ( cipher->authsize == test->auth_len, file, line ); cipher_auth ( cipher, ctx, auth ); okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); + + /* Reset initialisation vector */ + cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + + /* Process additional data, if applicable */ + if ( test->additional_len ) { + cipher_decrypt ( cipher, ctx, test->additional, NULL, + test->additional_len ); + } + + /* Perform decryption */ + cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len ); + + /* Compare against expected plaintext */ + okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line ); + + /* Check authentication tag */ + cipher_auth ( cipher, ctx, auth ); + okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); } /** -- cgit v1.2.3-55-g7522 From f5c829b6f8397c4083bb19b00aa147bd7a628e5e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Nov 2022 16:50:01 +0000 Subject: [tests] Verify ability to perform in-place encryption and decryption TLS relies upon the ability of ciphers to perform in-place decryption, in order to avoid allocating additional I/O buffers for received data. Add verification of in-place encryption and decryption to the cipher self-tests. Signed-off-by: Michael Brown --- src/tests/cipher_test.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/tests/cipher_test.c') diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index 0d0eac1d8..b7a982752 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -91,8 +91,9 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, test->additional_len ); } - /* Perform encryption */ - cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len ); + /* Perform in-place encryption */ + memcpy ( ciphertext, test->plaintext, len ); + cipher_encrypt ( cipher, ctx, ciphertext, ciphertext, len ); /* Compare against expected ciphertext */ okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line ); @@ -149,8 +150,9 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, test->additional_len ); } - /* Perform decryption */ - cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len ); + /* Perform in-place decryption */ + memcpy ( plaintext, test->ciphertext, len ); + cipher_decrypt ( cipher, ctx, plaintext, plaintext, len ); /* Compare against expected plaintext */ okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line ); -- cgit v1.2.3-55-g7522