v11-0002-Add-AEAD-functions-for-both-frontend-and-backend.patch
application/octet-stream
Filename: v11-0002-Add-AEAD-functions-for-both-frontend-and-backend.patch
Type: application/octet-stream
Part: 5
Message:
Re: Internal key management system
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v11-0002
Subject: Add AEAD functions for both frontend and backend.
| File | + | − |
|---|---|---|
| src/common/aead.c | 147 | 0 |
| src/common/Makefile | 1 | 0 |
| src/include/common/aead.h | 54 | 0 |
From 94cba72826818437196b400a0fbe7a35a22b99ad Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 26 May 2020 13:15:41 +0900
Subject: [PATCH v11 2/7] Add AEAD functions for both frontend and backend.
---
src/common/Makefile | 1 +
src/common/aead.c | 147 ++++++++++++++++++++++++++++++++++++++
src/include/common/aead.h | 54 ++++++++++++++
3 files changed, 202 insertions(+)
create mode 100644 src/common/aead.c
create mode 100644 src/include/common/aead.h
diff --git a/src/common/Makefile b/src/common/Makefile
index 6429fd6af2..b220fa4dcf 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -46,6 +46,7 @@ LIBS += $(PTHREAD_LIBS)
# If you add objects here, see also src/tools/msvc/Mkvcbuild.pm
OBJS_COMMON = \
+ aead.o \
archive.o \
base64.o \
checksum_helper.o \
diff --git a/src/common/aead.c b/src/common/aead.c
new file mode 100644
index 0000000000..fbdfe905ce
--- /dev/null
+++ b/src/common/aead.c
@@ -0,0 +1,147 @@
+/*-------------------------------------------------------------------------
+ *
+ * aead.c
+ * Shared frontend/backend code for AEAD
+ *
+ * This contains the common low-level functions needed in both frontend and
+ * backend, for implement the Authenticated Encryption with Associated
+ * Data (AEAD) that are based on the composition of the Advanced Encryption
+ * Standard (AES) in the Cipher Block Chaining (CBC) mode of operation for
+ * encryption, and the HMAC-SHA message authentication code (MAC).
+ *
+ * This AEAD algorithm is derived from the specification draft of
+ * Authenticated Encryption with AES-CBC and HMAC-SHA[1]. It uses an
+ * Authenticated Encryption with Associated Data, following an
+ * Encrypt-then-MAC approach. Our AEAD algorithm uses AES-256 encryption
+ * in the CBC mode of operation for encryption to encrypt data with a random
+ * initialization vector (IV), and then compute HMAC-SHA512 of encrypted data.
+ * The cipher text consists of the HMAC, IV and encrypted data.
+ *
+ * [1] https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05
+ *
+ * Portions Copyright (c) 2020, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/common/aead.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/aead.h"
+#include "common/cipher.h"
+
+/* Return an AEAD context initialized with the given keys */
+PgAeadCtx *
+pg_create_aead_ctx(uint8 key[PG_AEAD_ENC_KEY_LEN], uint8 mackey[PG_AEAD_MAC_KEY_LEN])
+{
+ PgAeadCtx *ctx;
+
+ ctx = (PgAeadCtx *) palloc0(sizeof(PgAeadCtx));
+
+ /* Create and initialize a cipher context */
+ ctx->cipherctx = pg_cipher_ctx_create(PG_CIPHER_AES_CBC, key, PG_AEAD_ENC_KEY_LEN);
+ if (ctx->cipherctx == NULL)
+ return NULL;
+
+ /* Set encryption key and MAC key */
+ memcpy(ctx->key, key, PG_AEAD_ENC_KEY_LEN);
+ memcpy(ctx->mackey, mackey, PG_AEAD_MAC_KEY_LEN);
+
+ return ctx;
+}
+
+/* Free the AEAD context */
+void
+pg_free_aead_ctx(PgAeadCtx *ctx)
+{
+ if (!ctx)
+ return;
+
+ Assert(ctx->cipherctx);
+
+ pg_cipher_ctx_free(ctx->cipherctx);
+
+#ifndef FRONTEND
+ pfree(ctx);
+#else
+ pg_free(ctx);
+#endif
+}
+
+/*
+ * Encrypt the given data. Return true and set encrypted data to 'out' if
+ * success. Otherwise return false. The caller must allocate sufficient space
+ * for cipher data calculated by using AEADSizeOfCipherText(). Please note that
+ * this function modifies 'out' data even on failure case.
+ */
+bool
+pg_aead_encrypt(PgAeadCtx *ctx, uint8 *in, int inlen, uint8 *out, int *outlen)
+{
+ uint8 *hmac;
+ uint8 *iv;
+ uint8 *enc;
+ int enclen;
+
+ Assert(ctx && in && out);
+
+ hmac = out;
+ iv = hmac + PG_AEAD_HMAC_LEN;
+ enc = iv + PG_AES_IV_SIZE;
+
+ /* Generate IV */
+ if (!pg_strong_random(iv, PG_AES_IV_SIZE))
+ return false;
+
+ if (!pg_cipher_encrypt(ctx->cipherctx, in, inlen, enc, &enclen, iv))
+ return false;
+
+ if (!pg_HMAC_SHA512(ctx->mackey, enc, enclen, hmac))
+ return false;
+
+ *outlen = AEADSizeOfCipherText(inlen);;
+ Assert(*outlen == PG_AEAD_HMAC_LEN + PG_AES_IV_SIZE + enclen);
+
+ return true;
+}
+
+/*
+ * Decrypt the given Data. Return true and set plain text data to `out` if
+ * success. Otherwise return false. The caller must allocate sufficient space
+ * for cipher data calculated by using AEADSizeOfPlainText(). Please note that
+ * this function modifies 'out' data even on failure case.
+ */
+bool
+pg_aead_decrypt(PgAeadCtx *ctx, uint8 *in, int inlen, uint8 *out, int *outlen)
+{
+ uint8 hmac[PG_AEAD_HMAC_LEN];
+ uint8 *expected_hmac;
+ uint8 *iv;
+ uint8 *enc;
+ int enclen;
+
+ Assert(ctx && in && out);
+
+ expected_hmac = in;
+ iv = expected_hmac + PG_AEAD_HMAC_LEN;
+ enc = iv + PG_AES_IV_SIZE;
+ enclen = inlen - (enc - in);
+
+ /* Verify the correctness of HMAC */
+ if (!pg_HMAC_SHA512(ctx->mackey, enc, enclen, hmac))
+ return false;
+
+ if (memcmp(hmac, expected_hmac, PG_AEAD_HMAC_LEN) != 0)
+ return false;
+
+ /* Decrypt encrypted data */
+ if (!pg_cipher_decrypt(ctx->cipherctx, enc, enclen, out, outlen, iv))
+ return false;
+
+ return true;
+}
diff --git a/src/include/common/aead.h b/src/include/common/aead.h
new file mode 100644
index 0000000000..d295387fa8
--- /dev/null
+++ b/src/include/common/aead.h
@@ -0,0 +1,54 @@
+/*-------------------------------------------------------------------------
+ *
+ * aead.h
+ * Declarations for utility function for AEAD
+ *
+ * Portions Copyright (c) 2020, PostgreSQL Global Development Group
+ *
+ * src/include/common/aead.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _PG_AEAD_H
+#define _PG_AEAD_H
+
+#include "common/cipher.h"
+
+/* Encryption key and MAC key used for AEAD */
+#define PG_AEAD_ENC_KEY_LEN PG_AES256_KEY_LEN
+#define PG_AEAD_MAC_KEY_LEN PG_HMAC_SHA512_KEY_LEN
+#define PG_AEAD_HMAC_LEN PG_HMAC_SHA512_LEN
+
+/* AEAD key consists of encryption key and mac key */
+#define PG_AEAD_KEY_LEN (PG_AEAD_ENC_KEY_LEN + PG_AEAD_MAC_KEY_LEN)
+
+/*
+ * Size of encrypted key size with padding. We use PKCS#7 padding,
+ * described in RFC 5652.
+ */
+#define SizeOfDataWithPadding(klen) \
+ ((int)(klen) + (PG_AES_BLOCK_SIZE - ((int)(klen) % PG_AES_BLOCK_SIZE)))
+
+/* Macros to compute the size of cipher text and plain text */
+#define AEADSizeOfCipherText(len) \
+ (PG_AEAD_MAC_KEY_LEN + PG_AES_IV_SIZE + SizeOfDataWithPadding((int)(len)))
+#define AEADSizeOfPlainText(klen) \
+ ((int)(klen) - (PG_AEAD_MAC_KEY_LEN + PG_AES_IV_SIZE))
+
+/* Key wrapping cipher context */
+typedef struct PgAeadCtx
+{
+ uint8 key[PG_AEAD_ENC_KEY_LEN];
+ uint8 mackey[PG_AEAD_MAC_KEY_LEN];
+ PgCipherCtx *cipherctx;
+} PgAeadCtx;
+
+extern PgAeadCtx *pg_create_aead_ctx(uint8 key[PG_AEAD_ENC_KEY_LEN],
+ uint8 mackey[PG_AEAD_MAC_KEY_LEN]);
+extern void pg_free_aead_ctx(PgAeadCtx *ctx);
+extern bool pg_aead_encrypt(PgAeadCtx *ctx, uint8 *in, int inlen,
+ uint8 *out, int *outlen);
+extern bool pg_aead_decrypt(PgAeadCtx *ctx, uint8 *in, int inlen,
+ uint8 *out, int *outlen);
+
+#endif /* _PG_AEAD_H */
--
2.23.0