commit 9734f2f0f23e09432cca1dedc124b96e7be3f28f
parent ca1de5ef5c391b6d1ea74fa1e142ca011bdc5159
Author: lash <dev@holbrook.no>
Date: Wed, 2 Apr 2025 22:06:44 +0100
Implement missing MAC verification in decrypt, cert test still croaking
Diffstat:
5 files changed, 149 insertions(+), 34 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@ all: lib
make -C src all
lib:
- make -C src lib
+ make -C src dev-lib
test: all
make -C src test
diff --git a/src/cli/main.c b/src/cli/main.c
@@ -119,25 +119,26 @@ int main(int argc, char **argv) {
return 1;
}
cert = lq_certificate_new(NULL);
- r = lq_certificate_request(cert, req, pk_alice);
- if (r != ERR_OK) {
- lq_ui_free();
- return 1;
- }
-
- res = lq_msg_new("foo", 4);
- if (res == NULL) {
- lq_ui_free();
- return 1;
- }
- r = lq_certificate_respond(cert, res, pk_bob);
- if (r != ERR_OK) {
- lq_ui_free();
- return 1;
- }
+// r = lq_certificate_request(cert, req, pk_alice);
+// if (r != ERR_OK) {
+// lq_ui_free();
+// return 1;
+// }
+//
+// res = lq_msg_new("foo", 4);
+// if (res == NULL) {
+// lq_ui_free();
+// return 1;
+// }
+// r = lq_certificate_respond(cert, res, pk_bob);
+// if (r != ERR_OK) {
+// lq_ui_free();
+// return 1;
+// }
r = lq_certificate_verify(cert, pubk_alice, NULL);
+ lq_msg_free(req);
lq_certificate_free(cert);
lq_ui_free();
diff --git a/src/crypto/gcrypt.c b/src/crypto/gcrypt.c
@@ -18,6 +18,8 @@
#define CHACHA20_KEY_LENGTH_BYTES 32
#define CHACHA20_NONCE_LENGTH_BYTES 12
+#define POLY1305_MAC_LEN 16
+#define POLY1305_MAC_KEYLEN 32
/// Lookup mode for key in store.
enum gpg_find_mode_e {
@@ -47,10 +49,7 @@ static char *gpg_version = NULL;
static int gpg_cfg_idx_dir;
/// default digest id.
-static int gpg_passphrase_digest = GCRY_MD_SHA256;
-
-/// digest length of hashed password.
-static int gpg_passphrase_digest_len;
+static int gpg_passphrase_digest = GCRY_MD_SHA512;
/// zero fp value
const static char gpg_fingerprint_zero[LQ_FP_LEN];
@@ -84,8 +83,6 @@ int lq_crypto_init(const char *base) {
}
debug_x(LLOG_DEBUG, "gpg", "using gpg", 1, MORGEL_TYP_STR, 0, "version", gpg_version);
- //gpg_passphrase_digest_len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
- gpg_passphrase_digest_len = gcry_md_get_algo_dlen(GCRY_MD_SHA512);
gpg_cfg_idx_dir = lq_config_register(LQ_TYP_STR, "CRYPTODIR");
p = path;
@@ -159,6 +156,103 @@ static void free_handle(gcry_cipher_hd_t *h) {
gcry_cipher_close(*h);
}
+// Puts mac in mac and newly generated mac key in mac_key
+// in is a buffer of in_len which must be cipher blocksize.
+// no data validation checking is done.
+static int create_mac(char *mac, char *mac_key, const char *in, size_t in_len) {
+ int r;
+ char *p;
+ size_t maclen;
+ gcry_mac_hd_t h;
+ gcry_error_t e;
+
+ r = gcry_mac_open(&h, GCRY_MAC_POLY1305, 0, NULL);
+ if (r) {
+ return r;
+ }
+
+ e = gcry_mac_setkey(h, mac_key, POLY1305_MAC_KEYLEN);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ e = gcry_mac_write(h, in, in_len);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ maclen = POLY1305_MAC_LEN;
+ e = gcry_mac_read(h, mac, &maclen);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ gcry_mac_close(h);
+
+ if (maclen != POLY1305_MAC_LEN) {
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ return ERR_OK;
+}
+
+static int verify_mac(char *mac, char *mac_key, const char *in, size_t in_len) {
+ int r;
+ char *p;
+ size_t maclen;
+ gcry_mac_hd_t h;
+ gcry_error_t e;
+
+ r = gcry_mac_open(&h, GCRY_MAC_POLY1305, 0, NULL);
+ if (r) {
+ return r;
+ }
+
+ e = gcry_mac_setkey(h, mac_key, POLY1305_MAC_KEYLEN);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ e = gcry_mac_write(h, in, in_len);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ maclen = POLY1305_MAC_LEN;
+ e = gcry_mac_read(h, mac, &maclen);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ e = gcry_mac_verify(h, mac, maclen);
+ if (e) {
+ gcry_mac_close(h);
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ gcry_mac_close(h);
+
+ if (maclen != POLY1305_MAC_LEN) {
+ p = (char*)gcry_strerror(e);
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, p);
+ }
+
+ return ERR_OK;
+}
int encryptb (char *ciphertext, size_t ciphertext_len, const char *indata, size_t indata_len, const char *key, const char *nonce) {
const char *p;
int r;
@@ -181,6 +275,7 @@ int encryptb (char *ciphertext, size_t ciphertext_len, const char *indata, size_
free_handle(&h);
+
return ERR_OK;
}
@@ -379,7 +474,7 @@ LQStore *key_store_get() {
/**
* \todo consistent endianness for key length in persistent storage (fwrite)
* \todo doc must have enough in path for path + fingerprint hex
- *
+ * \todo check capacity in buffer for both ciphertext, nonce and mac.
*/
static int key_create_store(struct gpg_store *gpg, const char *passphrase, size_t passphrase_len) {
char *p;
@@ -396,6 +491,7 @@ static int key_create_store(struct gpg_store *gpg, const char *passphrase, size_
char buf_val[LQ_STORE_VAL_MAX];
char ciphertext[LQ_CRYPTO_BUFLEN];
char passphrase_hash[LQ_DIGEST_LEN];
+ char mac[POLY1305_MAC_LEN];
// Create the private key and corresponding public key.
r = key_create(gpg);
@@ -430,6 +526,14 @@ static int key_create_store(struct gpg_store *gpg, const char *passphrase, size_
return debug_logerr(LLOG_ERROR, ERR_KEY_LOCK, "encrypt private key");
}
+ c += CHACHA20_NONCE_LENGTH_BYTES;
+ r = create_mac(mac, passphrase_hash + CHACHA20_KEY_LENGTH_BYTES, v, m+sizeof(int));
+ if (r) {
+ return debug_logerr(LLOG_ERROR, ERR_CIPHER, "mac generation fail");
+ return r;
+ }
+ lq_cpy(ciphertext + c, mac, POLY1305_MAC_LEN);
+
// Export the key (fingerprint) and value (ciphertext) to put in the store.
// (We don't need the inner private key pointer anymore, so we re-use it.)
pubk = lq_publickey_new(gpg->public_key);
@@ -440,6 +544,7 @@ static int key_create_store(struct gpg_store *gpg, const char *passphrase, size_
lq_cpy(buf_key, gpg->fingerprint, LQ_FP_LEN);
lq_cpy(buf_val, nonce, CHACHA20_NONCE_LENGTH_BYTES);
lq_cpy(buf_val + CHACHA20_NONCE_LENGTH_BYTES, ciphertext, c);
+ lq_cpy(buf_val + CHACHA20_NONCE_LENGTH_BYTES + c, mac, POLY1305_MAC_LEN);
lq_publickey_free(pubk);
// Retrieve the store.
@@ -449,7 +554,7 @@ static int key_create_store(struct gpg_store *gpg, const char *passphrase, size_
}
// Write the ciphertext to the store.
- l = c + CHACHA20_NONCE_LENGTH_BYTES;
+ l = c + CHACHA20_NONCE_LENGTH_BYTES + POLY1305_MAC_LEN;
c = LQ_FP_LEN;
r = store->put(LQ_CONTENT_KEY, store, buf_key, &c, buf_val, l);
if (r) {
@@ -589,7 +694,12 @@ static int key_from_store(struct gpg_store *gpg, const char *passphrase, size_t
nonce = in;
p = (char*)in + CHACHA20_NONCE_LENGTH_BYTES;
in_len -= CHACHA20_NONCE_LENGTH_BYTES;
- r = decryptb(out, p, in_len, passphrase_hash, nonce);
+ r = decryptb(out, p, in_len - POLY1305_MAC_LEN, passphrase_hash, nonce);
+ if (r) {
+ return ERR_KEY_UNLOCK;
+ }
+
+ r = verify_mac(p + in_len - POLY1305_MAC_LEN, passphrase_hash + CHACHA20_KEY_LENGTH_BYTES, out, in_len - POLY1305_MAC_LEN);
if (r) {
return ERR_KEY_UNLOCK;
}
diff --git a/src/lq/msg.c b/src/lq/msg.c
@@ -59,7 +59,8 @@ LQSig* lq_msg_sign_extra(LQMsg *msg, LQPrivKey *pk, const char *salt, const char
}
void lq_msg_free(LQMsg *msg) {
- if (msg->pubkey->pk = NULL) {
+ //if (msg->pubkey->pk = NULL) {
+ if (msg->pubkey != NULL) {
lq_free(msg->pubkey);
}
lq_free(msg->data);
diff --git a/src/test/Makefile b/src/test/Makefile
@@ -1,7 +1,8 @@
OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
INCLUDES := -I.. -I../aux/include `pkg-config --cflags libtasn1 libgcrypt`
CFLAGS += $(INCLUDES) -Wall -g3
-LIBS := ../asn1/defs_asn1_tab.o `pkg-config --libs libtasn1 libgcrypt` -L../aux/lib -llash -lhashmap
+#LIBS := ../asn1/defs_asn1_tab.o `pkg-config --libs libtasn1 libgcrypt` -L../aux/lib -llash -lhashmap
+LIBS := ../asn1/defs_asn1_tab.o `pkg-config --libs libtasn1 libgcrypt` -L.. -L../aux/lib -lqaeda -lhashmap
#LDFLAGS := -lcheck -lsubunit -lm $(LIBS)
LDFLAGS := -lcheck $(LIBS)
COMMONOBJS = ../mem/std.o ../lq/config.o ../lq/err.o ../lq/base.o ../debug.o
@@ -20,14 +21,16 @@ test: all
build:
#$(CC) $(CFLAGS) test_test.c -o test_test_bin $(COMMONOBJS) ../io/dummy.o ../store/mem.o $(LDFLAGS)
- $(CC) $(CFLAGS) test_test.c -o test_test_bin $(COMMONOBJS) ../io/std.o ../store/file.o $(LDFLAGS)
+ #$(CC) $(CFLAGS) test_test.c -o test_test_bin $(COMMONOBJS) ../io/std.o ../store/file.o $(LDFLAGS)
+ $(CC) $(CFLAGS) test_test.c -o test_test_bin $(COMMONOBJS) $(LDFLAGS)
$(CC) $(CFLAGS) test_debug.c -o test_debug_bin $(COMMONOBJS) $(LDFLAGS)
$(CC) $(CFLAGS) test_config.c -o test_config_bin $(COMMONOBJS) $(LDFLAGS)
- $(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o $(LDFLAGS) -lgcrypt
- $(CC) $(CFLAGS) test_msg.c -o test_msg_bin $(COMMONOBJS) ../store/file.o ../store/dummy.o ../io/std.o ../crypto/gcrypt.o ../lq/msg.o $(LDFLAGS)
- $(CC) $(CFLAGS) test_cert.c -o test_cert_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o ../store/dummy.o ../lq/msg.o ../lq/cert.o $(LDFLAGS)
- $(CC) $(CFLAGS) test_trust.c -o test_trust_bin $(COMMONOBJS) ../store/file.o ../io/std.c ../crypto/gcrypt.o ../lq/trust.o $(LDFLAGS)
- $(CC) $(CFLAGS) test_store.c -o test_store_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o $(LDFLAGS)
+ #$(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin $(COMMONOBJS) ../store/file.o ../io/std.o ../crypto/gcrypt.o $(LDFLAGS) -lgcrypt
+ $(CC) $(CFLAGS) test_crypto.c -o test_crypto_bin $(COMMONOBJS) $(LDFLAGS) -lgcrypt
+ $(CC) $(CFLAGS) test_msg.c -o test_msg_bin $(COMMONOBJS) ../store/dummy.o $(LDFLAGS) -lgcrypt
+ $(CC) $(CFLAGS) test_cert.c -o test_cert_bin $(COMMONOBJS) ../store/dummy.o $(LDFLAGS) -lgcrypt
+ $(CC) $(CFLAGS) test_trust.c -o test_trust_bin $(COMMONOBJS) $(LDFLAGS)
+ $(CC) $(CFLAGS) test_store.c -o test_store_bin $(COMMONOBJS) $(LDFLAGS) -lgcrypt
clean:
rm -vf test_*_bin