summaryrefslogtreecommitdiffstats
path: root/src/include/ipxe/gcm.h
diff options
context:
space:
mode:
authorMichael Brown2022-10-24 19:52:21 +0200
committerMichael Brown2022-10-25 14:21:30 +0200
commit8fce26730c4df7a9792bb144c75c2c5b998c91af (patch)
treeac415615c4688747286656273faee5c1456313f5 /src/include/ipxe/gcm.h
parent[crypto] Add concept of authentication tag to cipher algorithms (diff)
downloadipxe-8fce26730c4df7a9792bb144c75c2c5b998c91af.tar.gz
ipxe-8fce26730c4df7a9792bb144c75c2c5b998c91af.tar.xz
ipxe-8fce26730c4df7a9792bb144c75c2c5b998c91af.zip
[crypto] Add block cipher Galois/Counter mode of operation
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/include/ipxe/gcm.h')
-rw-r--r--src/include/ipxe/gcm.h132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h
new file mode 100644
index 00000000..65868548
--- /dev/null
+++ b/src/include/ipxe/gcm.h
@@ -0,0 +1,132 @@
+#ifndef _IPXE_GCM_H
+#define _IPXE_GCM_H
+
+/** @file
+ *
+ * Galois/Counter Mode (GCM)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+
+/** 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 {
+ /** Hash key (H) */
+ union gcm_block key;
+ /** Counter (Y) */
+ union gcm_block ctr;
+ /** Accumulated hash (X) */
+ union gcm_block hash;
+ /** Accumulated lengths */
+ union gcm_block len;
+ /** 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; \
+ linker_assert ( _blocksize == sizeof ( context->gcm.key ), \
+ _gcm_name ## _unsupported_blocksize ); \
+ linker_assert ( ( ( void * ) &context->gcm ) == ctx, \
+ _gcm_name ## _context_layout_error ); \
+ linker_assert ( ( ( void * ) &context->raw ) == \
+ ( ( void * ) context->gcm.raw_ctx ), \
+ _gcm_name ## _context_layout_error ); \
+ 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, \
+ .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 */