commit a277455f7772361c9a3f4a68c33fe539f7435267
parent fdcdd2572d4476996b65742a8cce502a321bea0c
Author: sin <sin@2f30.org>
Date: Wed, 30 Mar 2016 09:12:36 +0100
Switch to aes-256-gcm
Diffstat:
M | stun.c | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++---------------- |
1 file changed, 48 insertions(+), 16 deletions(-)
diff --git a/stun.c b/stun.c
@@ -22,7 +22,7 @@
* The sender verifies that the correct response was received.
*
* All communication is encrypted using a pre-shared symmetric key, currently
- * using aes-256-cbc hashed with sha512.
+ * using aes-256-gcm hashed with sha512.
*
* All tunneled traffic is encapsulated inside the TCP payload.
* The packet format is shown below:
@@ -80,9 +80,10 @@
#define RECONNECTTIMEO 60 /* in seconds */
#define HDRLEN 2
#define IVLEN 16
+#define TAGLEN 16
#define PKTLENMASK 0xfff
#define BADPKT 0x8000
-#define MTU 1424
+#define MTU 1400
enum {
TUNDEV,
@@ -167,7 +168,7 @@ prepkey(unsigned char *pw, int pwlen)
{
int ret, nrounds = 5;
- ret = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(),
+ ret = EVP_BytesToKey(EVP_aes_256_gcm(), EVP_sha512(),
NULL, pw, pwlen, nrounds, aeskey, NULL);
if (ret != 32)
logerr("wrong key size %d", ret);
@@ -184,31 +185,56 @@ aesinit(EVP_CIPHER_CTX *ectx, EVP_CIPHER_CTX *dctx)
int
aesenc(EVP_CIPHER_CTX *ctx, unsigned char *ct, unsigned char *pt, int plen,
- unsigned char *key, unsigned char *iv)
+ unsigned char *key, unsigned char *iv, unsigned char *tag, int taglen)
{
int clen, flen;
- if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1)
logerr("EVP_EncryptInit_ex failed");
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, IVLEN, NULL) != 1)
+ logerr("EVP_CTRL_GCM_SET_IVLEN failed");
+
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv) != 1)
+ logerr("EVP_EncryptInit_ex failed");
+
if (EVP_EncryptUpdate(ctx, ct, &clen, pt, plen) != 1)
logerr("EVP_EncryptUpdate failed");
+
if (EVP_EncryptFinal_ex(ctx, ct + clen, &flen) != 1)
logerr("EVP_EncryptFinal_ex failed");
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAGLEN, tag) != 1)
+ logerr("EVP_CTRL_GCM_GET_TAG failed");
+
return clen + flen;
}
int
aesdec(EVP_CIPHER_CTX *ctx, unsigned char *pt, unsigned char *ct, int clen,
- unsigned char *key, unsigned char *iv)
+ unsigned char *key, unsigned char *iv, unsigned char *tag, int taglen)
{
int plen, flen;
- if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1)
+ logerr("EVP_DecryptInit_ex failed");
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, IVLEN, NULL) != 1)
+ logerr("EVP_CTRL_GCM_SET_IVLEN failed");
+
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv) != 1)
logerr("EVP_DecryptInit_ex failed");
+
if (EVP_DecryptUpdate(ctx, pt, &plen, ct, clen) != 1)
logerr("EVP_DecryptUpdate failed");
+
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TAGLEN, tag) != 1)
+ logerr("EVP_CTRL_GCM_SET_TAG failed");
+
+ /* if this fails, someone has tampered with the packet in transit */
if (EVP_DecryptFinal_ex(ctx, pt + plen, &flen) != 1)
- logerr("EVP_DecryptFinal_ex failed");
+ return -1;
+
return plen + flen;
}
@@ -429,17 +455,17 @@ int
writenet(int fd, unsigned char *pt, int len)
{
unsigned char payload[MTU + AES_BLOCK_SIZE];
- unsigned char hdr[HDRLEN];
- unsigned char iv[IVLEN];
- unsigned char pkt[sizeof(hdr) + sizeof(payload) + sizeof(iv)];
+ unsigned char hdr[HDRLEN], iv[IVLEN], tag[TAGLEN];
+ unsigned char pkt[sizeof(hdr) + sizeof(payload) + sizeof(iv) + sizeof(tag)];
arc4random_buf(iv, IVLEN);
- len = aesenc(&ectx, payload, pt, len, aeskey, iv);
+ len = aesenc(&ectx, payload, pt, len, aeskey, iv, tag, TAGLEN);
pack16(hdr, len);
memcpy(pkt, hdr, HDRLEN);
memcpy(&pkt[HDRLEN], iv, IVLEN);
memcpy(&pkt[HDRLEN + IVLEN], payload, len);
- len += IVLEN + HDRLEN;
+ memcpy(&pkt[HDRLEN + IVLEN + len], tag, TAGLEN);
+ len += IVLEN + HDRLEN + TAGLEN;
return writeall(fd, pkt, len);
}
@@ -447,8 +473,7 @@ int
readnet(int fd, unsigned char *pt, int len)
{
unsigned char payload[MTU + AES_BLOCK_SIZE];
- unsigned char hdr[HDRLEN];
- unsigned char iv[IVLEN];
+ unsigned char hdr[HDRLEN], iv[IVLEN], tag[TAGLEN];
int n, pktlen;
/* read packet length */
@@ -484,7 +509,14 @@ readnet(int fd, unsigned char *pt, int len)
if (n <= 0)
return n;
- pktlen = aesdec(&dctx, pt, payload, pktlen, aeskey, iv);
+ /* read tag */
+ n = readall(fd, tag, TAGLEN);
+ if (n <= 0)
+ return n;
+
+ pktlen = aesdec(&dctx, pt, payload, pktlen, aeskey, iv, tag, TAGLEN);
+ if (pktlen < 0)
+ return BADPKT;
return pktlen;
}