Skip to content

Commit

Permalink
XAES-256-GCM: fix reference implementations
Browse files Browse the repository at this point in the history
Thanks to @bleichenbacher-daniel for catching the Go bug.
  • Loading branch information
FiloSottile committed May 26, 2024
1 parent f092dec commit 0a4d025
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 23 deletions.
4 changes: 2 additions & 2 deletions XAES-256-GCM/reference.go → XAES-256-GCM/go/XAES-256-GCM.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ func New(key []byte) (cipher.AEAD, error) {
x.c, _ = aes.NewCipher(key)
x.c.Encrypt(x.k1[:], x.k1[:])

// Shift left k1 by one bit, then XOR with 0b10000111 if the MSB was set.
var msb byte
for i := len(x.k1) - 1; i >= 0; i-- {
msb = x.k1[i] >> 7
x.k1[i] = x.k1[i]<<1 | msb
msb, x.k1[i] = x.k1[i]>>7, x.k1[i]<<1|msb
}
x.k1[len(x.k1)-1] ^= msb * 0b10000111

Expand Down
3 changes: 3 additions & 0 deletions XAES-256-GCM/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module xaes256gcm

go 1.20
21 changes: 0 additions & 21 deletions XAES-256-GCM/openssl.c

This file was deleted.

94 changes: 94 additions & 0 deletions XAES-256-GCM/openssl/openssl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#include <string.h>

int derive_key(unsigned char out[32], const unsigned char key[32],
const unsigned char nonce[24]) {
EVP_KDF *kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);
EVP_KDF_free(kdf);

OSSL_PARAM params[9], *p = params;
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER, "AES256", 0);
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MAC, "CMAC", 0);
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_MODE, "COUNTER", 0);
int use_l = 0;
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_L, &use_l);
int r = 16;
*p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_R, &r);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void *)key, 32);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, "X", 1);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, (void *)nonce, 12);
*p = OSSL_PARAM_construct_end();

int res = EVP_KDF_derive(kctx, out, 32, params);
EVP_KDF_CTX_free(kctx);
return res == 1;
}

int seal_aes_256_gcm(const unsigned char *plaintext, size_t plaintext_len,
const unsigned char key[32], const unsigned char nonce[12],
unsigned char **ciphertext) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) return -1;

int res = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, key, nonce);
if (res != 1) goto err;

int tag_len = EVP_CIPHER_CTX_tag_length(ctx);
*ciphertext = OPENSSL_malloc(plaintext_len + tag_len);
if (!*ciphertext) goto err;

int ciphertext_len;
res = EVP_EncryptUpdate(ctx, *ciphertext, &ciphertext_len, plaintext, plaintext_len);
if (res != 1) goto err;

int final_len;
res = EVP_EncryptFinal_ex(ctx, *ciphertext + ciphertext_len, &final_len);
if (res != 1 || final_len != 0) goto err;

res = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, *ciphertext + ciphertext_len);
if (res != 1) goto err;

EVP_CIPHER_CTX_free(ctx);
return ciphertext_len + tag_len;

err:
EVP_CIPHER_CTX_free(ctx);
if (*ciphertext) OPENSSL_free(*ciphertext);
*ciphertext = NULL;
return -1;
}

int seal_xaes_256_gcm(const unsigned char *plaintext, size_t plaintext_len,
const unsigned char key[32],
const unsigned char nonce[24],
unsigned char **ciphertext) {
unsigned char derived_key[32];
if (!derive_key(derived_key, key, nonce)) return 0;
return seal_aes_256_gcm(plaintext, plaintext_len, derived_key, nonce + 12, ciphertext);
}

int main() {
const unsigned char key[32] = {
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
const unsigned char nonce[24] = {
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};

const unsigned char *plaintext = (const unsigned char *)"Hello, XAES-256-GCM!";
size_t plaintext_len = strlen((const char *)plaintext);

unsigned char *ciphertext;
int ciphertext_len = seal_xaes_256_gcm(plaintext, plaintext_len, key, nonce, &ciphertext);
if (ciphertext_len < 0) return 1;

for (size_t i = 0; i < ciphertext_len; i++) printf("%02x", ciphertext[i]);
printf("\n");

OPENSSL_free(ciphertext);
return 0;
}

0 comments on commit 0a4d025

Please sign in to comment.