]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Add concept of authentication tag to cipher algorithms
authorMichael Brown <mcb30@ipxe.org>
Mon, 24 Oct 2022 18:20:41 +0000 (19:20 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 25 Oct 2022 12:21:30 +0000 (13:21 +0100)
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 <mcb30@ipxe.org>
src/crypto/aes.c
src/crypto/arc4.c
src/crypto/crypto_null.c
src/include/ipxe/cbc.h
src/include/ipxe/crypto.h
src/include/ipxe/ecb.h
src/tests/aes_test.c
src/tests/cipher_test.c
src/tests/cipher_test.h

index d7393285f2616cb2d7ffcd8a56e02720cbfddbfe..4a7668b6ba0b7741e3fd242779e774512ae65277 100644 (file)
@@ -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 */
index 0dba2fc599bc9a55a7879be61639d309fb8c8115..4d98abead47cd28012855e100a22974b81daa618 100644 (file)
@@ -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,
 };
index ef6041b5b45ee5a3a6b6656ac252dc2dbbbd1e58..26cfbfc4e51a590fdedfbce1c55582642f883e20 100644 (file)
@@ -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,
index 5c874036573b992f3b303c68a8741597829f81b8..eead045ed95926b6dd23f236ff57570baa4cf86d 100644 (file)
@@ -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 */
index d41448024c80801a0da6974345eeb8e612ad23bb..e807aeb522c6425a169546a97515a2641aa8f274 100644 (file)
@@ -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 );
index 6c40c6126f3819c4024ae032af320824a72230b5..1d2ebf716cf6064e2f12fd07fb81ae4aac919225 100644 (file)
@@ -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 */
index e7201fca6c7731641c698ba10822fe9206c9eda8..be119c8d805ccd6ad9a051075a6df847a1fbb95b 100644 (file)
@@ -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
index c49b4b69bd947a7f64f6371d869e5dd458a58227..cc732c2e08f4b0f10975425532fbf2b4b86a1863 100644 (file)
@@ -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 );
 }
 
 /**
index 4139a7788c47b382cb65e8550585f4712bfe4877..519d12e8df000d9426b883918bf02e315b2c4346 100644 (file)
@@ -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,