aboutsummaryrefslogtreecommitdiffstats
path: root/serve/seal.c
diff options
context:
space:
mode:
Diffstat (limited to 'serve/seal.c')
-rw-r--r--serve/seal.c142
1 files changed, 0 insertions, 142 deletions
diff --git a/serve/seal.c b/serve/seal.c
deleted file mode 100644
index c1cc55b..0000000
--- a/serve/seal.c
+++ /dev/null
@@ -1,142 +0,0 @@
-#define _GNU_SOURCE
-#include "seal.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <openssl/crypto.h>
-#include <openssl/evp.h>
-#include <openssl/hpke.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#if defined(__aarch64__) && defined(__linux__)
-#include <asm/hwcap.h>
-#include <sys/auxv.h>
-#endif
-
-struct PureSealKey { EVP_PKEY *key; };
-
-static const unsigned char info[] = "pure sealed send 1";
-static const char aes_name[] = "x25519-sha256-aes128gcm", chacha_name[] = "x25519-sha256-chacha20poly1305";
-
-/* AES-GCM where AES is in the CPU (two to three times ChaCha20-Poly1305 from
- * a kilobyte up on a Cortex-A76, research 086); ChaCha20-Poly1305, fast in
- * plain code, elsewhere. */
-static bool has_aes(void) {
-#if defined(__aarch64__) && defined(__linux__)
- return (getauxval(AT_HWCAP) & HWCAP_AES) && (getauxval(AT_HWCAP) & HWCAP_PMULL);
-#elif defined(__x86_64__) && (defined(__GNUC__) || defined(__clang__))
- return __builtin_cpu_supports("aes") && __builtin_cpu_supports("pclmul");
-#else
- return false;
-#endif
-}
-
-static bool suite_named(const char *name, OSSL_HPKE_SUITE *out) {
- OSSL_HPKE_SUITE suite = {OSSL_HPKE_KEM_ID_X25519, OSSL_HPKE_KDF_ID_HKDF_SHA256, 0};
- if (!strcmp(name, aes_name)) suite.aead_id = OSSL_HPKE_AEAD_ID_AES_GCM_128;
- else if (!strcmp(name, chacha_name)) suite.aead_id = OSSL_HPKE_AEAD_ID_CHACHA_POLY1305;
- else return false;
- *out = suite;
- return true;
-}
-
-const char *pure_seal_suite(void) { return has_aes() ? aes_name : chacha_name; }
-
-static pthread_once_t secure_once = PTHREAD_ONCE_INIT;
-static void secure_heap(void) { CRYPTO_secure_malloc_init(16384, 32); }
-
-static bool hex_value(char c, unsigned *v) {
- if (c >= '0' && c <= '9') *v = (unsigned)(c - '0');
- else if (c >= 'a' && c <= 'f') *v = (unsigned)(c - 'a' + 10);
- else if (c >= 'A' && c <= 'F') *v = (unsigned)(c - 'A' + 10);
- else return false;
- return true;
-}
-
-bool pure_seal_peer(const char *hex, unsigned char out[PURE_SEAL_KEY]) {
- if (strlen(hex) != 2 * PURE_SEAL_KEY) return false;
- for (size_t i = 0; i < PURE_SEAL_KEY; ++i) {
- unsigned high, low;
- if (!hex_value(hex[2 * i], &high) || !hex_value(hex[2 * i + 1], &low)) return false;
- out[i] = (unsigned char)(high << 4 | low);
- }
- return true;
-}
-
-PureSealKey *pure_seal_key(const char *path, char public_hex[2 * PURE_SEAL_KEY + 1], char *error, size_t size) {
- pthread_once(&secure_once, secure_heap);
- unsigned char *raw = OPENSSL_secure_malloc(PURE_SEAL_KEY), public_key[PURE_SEAL_KEY];
- PureSealKey *made = calloc(1, sizeof(*made));
- EVP_PKEY *key = NULL;
- size_t length = PURE_SEAL_KEY;
- if (!raw || !made) { snprintf(error, size, "out of memory"); goto fail; }
- int fd = open(path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
- struct stat info_;
- if (fd >= 0) {
- bool ok = !fstat(fd, &info_) && S_ISREG(info_.st_mode) && !(info_.st_mode & 077) &&
- read(fd, raw, PURE_SEAL_KEY) == PURE_SEAL_KEY && info_.st_size == PURE_SEAL_KEY;
- close(fd);
- if (!ok) { snprintf(error, size, "%s: a key is 32 bytes that only its owner may read (0600)", path); goto fail; }
- key = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, raw, PURE_SEAL_KEY);
- } else if (errno == ENOENT) {
- /* A new key: made, written whole and synced before it is used. */
- key = EVP_PKEY_Q_keygen(NULL, NULL, "X25519");
- fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600);
- bool ok = key && fd >= 0 && EVP_PKEY_get_raw_private_key(key, raw, &length) == 1 && length == PURE_SEAL_KEY &&
- write(fd, raw, PURE_SEAL_KEY) == PURE_SEAL_KEY && !fsync(fd);
- if (fd >= 0 && close(fd)) ok = false;
- if (!ok) { snprintf(error, size, "%s: cannot make a key there", path); unlink(path); goto fail; }
- } else { snprintf(error, size, "%s: %s", path, strerror(errno)); goto fail; }
- length = PURE_SEAL_KEY;
- if (!key || EVP_PKEY_get_raw_public_key(key, public_key, &length) != 1 || length != PURE_SEAL_KEY) {
- snprintf(error, size, "%s: not an X25519 key", path);
- goto fail;
- }
- for (size_t i = 0; i < PURE_SEAL_KEY; ++i) snprintf(public_hex + 2 * i, 3, "%02x", public_key[i]);
- OPENSSL_secure_clear_free(raw, PURE_SEAL_KEY);
- made->key = key;
- return made;
-fail:
- EVP_PKEY_free(key);
- if (raw) OPENSSL_secure_clear_free(raw, PURE_SEAL_KEY);
- free(made);
- return NULL;
-}
-
-void pure_seal_key_free(PureSealKey *key) {
- if (!key) return;
- EVP_PKEY_free(key->key);
- free(key);
-}
-
-bool pure_seal(const unsigned char peer[PURE_SEAL_KEY], const char *aad, const unsigned char *plain, size_t size,
- unsigned char *out) {
- OSSL_HPKE_SUITE suite;
- if (!suite_named(pure_seal_suite(), &suite)) return false;
- OSSL_HPKE_CTX *context = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_BASE, suite, OSSL_HPKE_ROLE_SENDER, NULL, NULL);
- size_t encapsulated = PURE_SEAL_KEY, sealed = size + 16;
- bool ok = context && OSSL_HPKE_encap(context, out, &encapsulated, peer, PURE_SEAL_KEY, info, sizeof(info) - 1) == 1 &&
- encapsulated == PURE_SEAL_KEY &&
- OSSL_HPKE_seal(context, out + PURE_SEAL_KEY, &sealed, (const unsigned char *)aad, strlen(aad), plain, size) == 1 &&
- sealed == size + 16;
- OSSL_HPKE_CTX_free(context);
- return ok;
-}
-
-bool pure_unseal(const PureSealKey *key, const char *suite_name, const char *aad, const unsigned char *sealed, size_t size,
- unsigned char *plain) {
- OSSL_HPKE_SUITE suite;
- if (!key || size < PURE_SEAL_OVERHEAD || !suite_named(suite_name, &suite)) return false;
- OSSL_HPKE_CTX *context = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_BASE, suite, OSSL_HPKE_ROLE_RECEIVER, NULL, NULL);
- size_t opened = size - PURE_SEAL_OVERHEAD;
- bool ok = context &&
- OSSL_HPKE_decap(context, sealed, PURE_SEAL_KEY, key->key, info, sizeof(info) - 1) == 1 &&
- OSSL_HPKE_open(context, plain, &opened, (const unsigned char *)aad, strlen(aad), sealed + PURE_SEAL_KEY,
- size - PURE_SEAL_KEY) == 1 &&
- opened == size - PURE_SEAL_OVERHEAD;
- OSSL_HPKE_CTX_free(context);
- return ok;
-}