#ifndef _IPXE_GCM_H #define _IPXE_GCM_H /** @file * * Galois/Counter Mode (GCM) * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include /** A GCM counter */ struct gcm_counter { /** Initialisation vector */ uint8_t iv[12]; /** Counter value */ uint32_t value; } __attribute__ (( packed )); /** A GCM length pair */ struct gcm_lengths { /** Additional data length */ uint64_t add; /** Data length */ uint64_t data; } __attribute__ (( packed )); /** A GCM block */ union gcm_block { /** Raw bytes */ uint8_t byte[16]; /** Raw words */ uint16_t word[8]; /** Raw dwords */ uint32_t dword[4]; /** Counter */ struct gcm_counter ctr; /** Lengths */ struct gcm_lengths len; } __attribute__ (( packed )); /** GCM context */ struct gcm_context { /** Accumulated hash (X) */ union gcm_block hash; /** Accumulated lengths */ union gcm_block len; /** Counter (Y) */ union gcm_block ctr; /** Hash key (H) */ union gcm_block key; /** Underlying block cipher */ struct cipher_algorithm *raw_cipher; /** Underlying block cipher context */ uint8_t raw_ctx[0]; }; extern void gcm_tag ( struct gcm_context *context, union gcm_block *tag ); extern int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen, struct cipher_algorithm *raw_cipher ); extern void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ); extern void gcm_encrypt ( struct gcm_context *context, const void *src, void *dst, size_t len ); extern void gcm_decrypt ( struct gcm_context *context, const void *src, void *dst, size_t len ); /** * Create a GCM mode of behaviour of an existing cipher * * @v _cbc_name Name for the new CBC cipher * @v _cbc_cipher New cipher algorithm * @v _raw_cipher Underlying cipher algorithm * @v _raw_context Context structure for the underlying cipher * @v _blocksize Cipher block size */ #define GCM_CIPHER( _gcm_name, _gcm_cipher, _raw_cipher, _raw_context, \ _blocksize ) \ struct _gcm_name ## _context { \ /** GCM context */ \ struct gcm_context gcm; \ /** Underlying block cipher context */ \ _raw_context raw; \ }; \ static int _gcm_name ## _setkey ( void *ctx, const void *key, \ size_t keylen ) { \ struct _gcm_name ## _context *context = ctx; \ build_assert ( _blocksize == sizeof ( context->gcm.key ) ); \ build_assert ( ( ( void * ) &context->gcm ) == \ ( ( void * ) context ) ); \ build_assert ( ( ( void * ) &context->raw ) == \ ( ( void * ) context->gcm.raw_ctx ) ); \ return gcm_setkey ( &context->gcm, key, keylen, &_raw_cipher ); \ } \ static void _gcm_name ## _setiv ( void *ctx, const void *iv, \ size_t ivlen ) { \ struct _gcm_name ## _context *context = ctx; \ gcm_setiv ( &context->gcm, iv, ivlen ); \ } \ static void _gcm_name ## _encrypt ( void *ctx, const void *src, \ void *dst, size_t len ) { \ struct _gcm_name ## _context *context = ctx; \ gcm_encrypt ( &context->gcm, src, dst, len ); \ } \ static void _gcm_name ## _decrypt ( void *ctx, const void *src, \ void *dst, size_t len ) { \ struct _gcm_name ## _context *context = ctx; \ gcm_decrypt ( &context->gcm, src, dst, len ); \ } \ static void _gcm_name ## _auth ( void *ctx, void *auth ) { \ struct _gcm_name ## _context *context = ctx; \ union gcm_block *tag = auth; \ gcm_tag ( &context->gcm, tag ); \ } \ 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, \ .encrypt = _gcm_name ## _encrypt, \ .decrypt = _gcm_name ## _decrypt, \ .auth = _gcm_name ## _auth, \ }; #endif /* _IPXE_GCM_H */