summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/build-packet.c5
-rw-r--r--g10/encrypt.c1
-rw-r--r--g10/mainproc.c1
-rw-r--r--g10/misc.c2
-rw-r--r--g10/packet.h3
-rw-r--r--g10/parse-packet.c20
-rw-r--r--g10/pubkey-enc.c92
-rw-r--r--g10/seskey.c20
8 files changed, 103 insertions, 41 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 78828c8dc..fd315b313 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -982,6 +982,11 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
for (i=0; i < n && !rc ; i++ )
{
+ /* For Kyber we need to insert the algo before the final data
+ * element because it is not stored in the data array. */
+ if (enc->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
+ iobuf_put (a, enc->seskey_algo);
+
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
rc = gpg_mpi_write_opaque_nohdr (a, enc->data[i]);
else if (enc->pubkey_algo == PUBKEY_ALGO_ECDH)
diff --git a/g10/encrypt.c b/g10/encrypt.c
index aa0c3c6dd..f416cde53 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -1122,6 +1122,7 @@ write_pubkey_enc (ctrl_t ctrl,
enc->pubkey_algo = pk->pubkey_algo;
keyid_from_pk( pk, enc->keyid );
enc->throw_keyid = throw_keyid;
+ enc->seskey_algo = dek->algo; /* (Used only by PUBKEY_ALGO_KYBER.) */
/* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in an
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 6f3254e88..48bc463c5 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -529,6 +529,7 @@ proc_pubkey_enc (CTX c, PACKET *pkt)
x->keyid[1] = enc->keyid[1];
x->pubkey_algo = enc->pubkey_algo;
x->result = -1;
+ x->seskey_algo = enc->seskey_algo;
x->data[0] = x->data[1] = x->data[2] = x->data[3] = NULL;
if (enc->data[0])
{
diff --git a/g10/misc.c b/g10/misc.c
index ce0c04b3b..1359987d2 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -1786,7 +1786,7 @@ pubkey_get_nenc (pubkey_algo_t algo)
case PUBKEY_ALGO_ECDSA: return 0;
case PUBKEY_ALGO_ELGAMAL: return 2;
case PUBKEY_ALGO_EDDSA: return 0;
- case PUBKEY_ALGO_KYBER: return 4;
+ case PUBKEY_ALGO_KYBER: return 3;
default: return 0;
}
}
diff --git a/g10/packet.h b/g10/packet.h
index 40e5051c0..459e38dda 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -137,6 +137,8 @@ typedef struct {
byte version;
/* The algorithm used for the public key encryption scheme. */
byte pubkey_algo;
+ /* The session key algorithm used by some pubkey algos. */
+ byte seskey_algo;
/* Whether to hide the key id. This value is not directly
serialized. */
byte throw_keyid;
@@ -151,6 +153,7 @@ struct pubkey_enc_list
struct pubkey_enc_list *next;
u32 keyid[2];
int pubkey_algo;
+ int seskey_algo;
int result;
gcry_mpi_t data[PUBKEY_MAX_NENC];
};
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index c55bb1b71..8bd283b4b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1513,7 +1513,7 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
}
else if (k->pubkey_algo == PUBKEY_ALGO_KYBER)
{
- log_assert (ndata == 4);
+ log_assert (ndata == 3);
/* Get the ephemeral public key. */
n = pktlen;
k->data[0] = sos_read (inp, &n, 0);
@@ -1527,12 +1527,16 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1);
if (rc)
goto leave;
- /* Get the algorithm id. */
- rc = read_octet_string (inp, &pktlen, 0, 1, 0, k->data + 2);
- if (rc)
- goto leave;
- /* Get the wrapped symmetric key. */
- rc = read_sized_octet_string (inp, &pktlen, k->data + 3);
+ /* Get the algorithm id for the session key. */
+ if (!pktlen)
+ {
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ k->seskey_algo = iobuf_get_noeof (inp);
+ pktlen--;
+ /* Get the encrypted symmetric key. */
+ rc = read_octet_string (inp, &pktlen, 1, 0, 0, k->data + 2);
if (rc)
goto leave;
}
@@ -1551,6 +1555,8 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
}
if (list_mode)
{
+ if (k->seskey_algo)
+ es_fprintf (listfp, "\tsession key algo: %d\n", k->seskey_algo);
for (i = 0; i < ndata; i++)
{
es_fprintf (listfp, "\tdata: ");
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 873b864b5..da32ebc7b 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -194,7 +194,7 @@ get_it (ctrl_t ctrl,
{
gpg_error_t err;
byte *frame = NULL;
- unsigned int n;
+ unsigned int frameidx;
size_t nframe;
u16 csum, csum2;
int padding;
@@ -240,13 +240,15 @@ get_it (ctrl_t ctrl,
}
else if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
{
- if (!enc->data[0] || !enc->data[1] || !enc->data[2] || !enc->data[3])
+ log_debug ("seskey_algo: %d\n", enc->seskey_algo);
+ if (!enc->data[0] || !enc->data[1] || !enc->data[2])
err = gpg_error (GPG_ERR_BAD_MPI);
else
err = gcry_sexp_build (&s_data, NULL,
- "(enc-val(pqc(e%m)(k%m)(s%m)(fixed-info%s)))",
- enc->data[0], enc->data[1], enc->data[3],
- "\x1d" /*PUBKEY_ALGO_KYBER*/);
+ "(enc-val(pqc(e%m)(k%m)(s%m)(c%d)(fixed-info%s)))",
+ enc->data[0], enc->data[1], enc->data[2],
+ enc->seskey_algo,
+ "\x69");
}
else
err = gpg_error (GPG_ERR_BUG);
@@ -287,9 +289,22 @@ get_it (ctrl_t ctrl,
*/
if (DBG_CRYPTO)
log_printhex (frame, nframe, "DEK frame:");
- n = 0;
+ frameidx = 0;
- if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
+ if (sk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ /* We expect a 32 byte session key. We should not see this
+ * error here because due to the KEM mode the agent_pkdecrypt
+ * should have already failed. */
+ if (nframe != 32)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+ dek->keylen = nframe;
+ dek->algo = enc->seskey_algo;
+ }
+ else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
gcry_mpi_t decoded;
@@ -313,13 +328,21 @@ get_it (ctrl_t ctrl,
goto leave;
}
nframe -= frame[nframe-1]; /* Remove padding. */
- log_assert (!n); /* (used just below) */
+ if (4 > nframe)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+
+ dek->keylen = nframe - 3;
+ dek->algo = frame[0];
+ frameidx = 1;
}
else
{
if (padding)
{
- if (n + 7 > nframe)
+ if (7 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
@@ -331,34 +354,38 @@ get_it (ctrl_t ctrl,
* using a Smartcard we are doing it the right way and
* therefore we have to skip the zero. This should be fixed
* in gpg-agent of course. */
- if (!frame[n])
- n++;
+ frameidx = 0;
+ if (!frame[frameidx])
+ frameidx++;
- if (frame[n] == 1 && frame[nframe - 1] == 2)
+ if (frame[frameidx] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
err = gpg_error (GPG_ERR_CIPHER_ALGO);
goto leave;
}
- if (frame[n] != 2) /* Something went wrong. */
+ if (frame[frameidx] != 2) /* Something went wrong. */
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
- for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
+ /* Skip the random bytes. */
+ for (frameidx++; frameidx < nframe && frame[frameidx]; frameidx++)
;
- n++; /* Skip the zero byte. */
+ frameidx++; /* Skip the zero byte. */
}
- }
- if (n + 4 > nframe)
- {
- err = gpg_error (GPG_ERR_WRONG_SECKEY);
- goto leave;
+ if (frameidx + 4 > nframe)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
+
+ dek->keylen = nframe - (frameidx + 1) - 2;
+ dek->algo = frame[frameidx++];
}
- dek->keylen = nframe - (n + 1) - 2;
- dek->algo = frame[n++];
+ /* Check whether we support the ago. */
err = openpgp_cipher_test_algo (dek->algo);
if (err)
{
@@ -377,16 +404,21 @@ get_it (ctrl_t ctrl,
goto leave;
}
- /* Copy the key to DEK and compare the checksum. */
- csum = buf16_to_u16 (frame+nframe-2);
- memcpy (dek->key, frame + n, dek->keylen);
- for (csum2 = 0, n = 0; n < dek->keylen; n++)
- csum2 += dek->key[n];
- if (csum != csum2)
+ /* Copy the key to DEK and compare the checksum if needed. */
+ /* We use the frameidx as flag for the need of a checksum. */
+ memcpy (dek->key, frame + frameidx, dek->keylen);
+ if (frameidx)
{
- err = gpg_error (GPG_ERR_WRONG_SECKEY);
- goto leave;
+ csum = buf16_to_u16 (frame+nframe-2);
+ for (csum2 = 0, frameidx = 0; frameidx < dek->keylen; frameidx++)
+ csum2 += dek->key[frameidx];
+ if (csum != csum2)
+ {
+ err = gpg_error (GPG_ERR_WRONG_SECKEY);
+ goto leave;
+ }
}
+
if (DBG_CLOCK)
log_clock ("decryption ready");
if (DBG_CRYPTO)
diff --git a/g10/seskey.c b/g10/seskey.c
index e5397080d..2fe8e9de7 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -86,15 +86,29 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
if (DBG_CRYPTO)
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
+ if (openpgp_pk_algo == PUBKEY_ALGO_KYBER)
+ {
+ /* Straightforward encoding w/o extra checksum as used by ECDH. */
+ nframe = dek->keylen;
+ log_assert (nframe > 4); /*(for the log_debug)*/
+ frame = xmalloc_secure (nframe);
+ memcpy (frame, dek->key, nframe);
+ if (DBG_CRYPTO)
+ log_debug ("encode_session_key: "
+ "[%d] %02x %02x %02x ... %02x %02x %02x\n",
+ (int) dek->keylen, frame[0], frame[1], frame[2],
+ frame[nframe-3], frame[nframe-2], frame[nframe-1]);
+
+ return gcry_mpi_set_opaque (NULL, frame, 8*nframe);
+ }
+
csum = 0;
for (p = dek->key, i=0; i < dek->keylen; i++)
csum += *p++;
/* Shortcut for ECDH. It's padding is minimal to simply make the
output be a multiple of 8 bytes. */
- /* FIXME: We use the ECDH also for Kyber for now. */
- if (openpgp_pk_algo == PUBKEY_ALGO_ECDH
- || openpgp_pk_algo == PUBKEY_ALGO_KYBER)
+ if (openpgp_pk_algo == PUBKEY_ALGO_ECDH)
{
/* Pad to 8 byte granularity; the padding byte is the number of
* padded bytes.