commit fdcdd2572d4476996b65742a8cce502a321bea0c
parent b59586b4ba0af5a83f144466a9fa1d72ff2d2006
Author: sin <sin@2f30.org>
Date: Tue, 29 Mar 2016 23:57:35 +0100
more crypto work
Diffstat:
M | stun.c | | | 119 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
1 file changed, 48 insertions(+), 71 deletions(-)
diff --git a/stun.c b/stun.c
@@ -22,22 +22,14 @@
* 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 sha1.
+ * using aes-256-cbc hashed with sha512.
*
* All tunneled traffic is encapsulated inside the TCP payload.
* The packet format is shown below:
*
- * [UNPADDED PAYLOAD LENGTH][PADDED PAYLOAD]
+ * [PAYLOAD LENGTH] [IV] [PAYLOAD]
*
- * The payload is encrypted and padded to 16 bytes. The payload length is a
- * two-octet field that describes the length of the unpadded payload.
- * When the receiver processes a packet it needs to pad the payload length in order
- * to decrypt the packet. The unpadded length is then used to determine the size
- * of the actual decrypted payload.
- *
- * The maximum payload length allowed is 4095 bytes. The maximum padded payload
- * length is therefore 4096 bytes. Values at 0x8000 or above are reserved for internal
- * error conditions.
+ * Where payload length is 2 octets and IV is 16 octets.
*/
#include <sys/types.h>
@@ -87,17 +79,18 @@
#define CHALLENGETIMEO 1 /* in seconds */
#define RECONNECTTIMEO 60 /* in seconds */
#define HDRLEN 2
+#define IVLEN 16
#define PKTLENMASK 0xfff
#define BADPKT 0x8000
-#define MTU 1440
+#define MTU 1424
enum {
TUNDEV,
TAPDEV
};
-EVP_CIPHER_CTX enc, dec;
-unsigned char aeskey[32], aesiv[32];
+EVP_CIPHER_CTX ectx, dctx;
+unsigned char aeskey[EVP_MAX_KEY_LENGTH];
char *argv0;
char *host;
char *port = "12080";
@@ -170,24 +163,12 @@ revokeprivs(void)
}
int
-padto(int len, int blocksize)
-{
- return len + blocksize - len % blocksize;
-}
-
-int
-padlen(int len, int blocksize)
-{
- return padto(len, blocksize) - len;
-}
-
-int
prepkey(unsigned char *pw, int pwlen)
{
int ret, nrounds = 5;
- ret = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(),
- NULL, pw, pwlen, nrounds, aeskey, aesiv);
+ ret = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(),
+ NULL, pw, pwlen, nrounds, aeskey, NULL);
if (ret != 32)
logerr("wrong key size %d", ret);
return 0;
@@ -197,42 +178,38 @@ int
aesinit(EVP_CIPHER_CTX *ectx, EVP_CIPHER_CTX *dctx)
{
EVP_CIPHER_CTX_init(ectx);
- EVP_EncryptInit_ex(ectx, EVP_aes_256_cbc(), NULL, NULL, NULL);
- EVP_EncryptInit_ex(ectx, EVP_aes_256_cbc(), NULL, aeskey, aesiv);
- EVP_CIPHER_CTX_set_padding(ectx, 0);
-
EVP_CIPHER_CTX_init(dctx);
- EVP_DecryptInit_ex(dctx, EVP_aes_256_cbc(), NULL, NULL, NULL);
- EVP_DecryptInit_ex(dctx, EVP_aes_256_cbc(), NULL, aeskey, aesiv);
- EVP_CIPHER_CTX_set_padding(dctx, 0);
return 0;
}
-void
-aesterm(EVP_CIPHER_CTX *ectx, EVP_CIPHER_CTX *dctx)
-{
- EVP_CIPHER_CTX_cleanup(ectx);
- EVP_CIPHER_CTX_cleanup(dctx);
-}
-
int
-aesenc(EVP_CIPHER_CTX *ctx, unsigned char *ct, unsigned char *pt, int plen)
+aesenc(EVP_CIPHER_CTX *ctx, unsigned char *ct, unsigned char *pt, int plen,
+ unsigned char *key, unsigned char *iv)
{
- int clen;
+ int clen, flen;
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+ logerr("EVP_EncryptInit_ex failed");
if (EVP_EncryptUpdate(ctx, ct, &clen, pt, plen) != 1)
logerr("EVP_EncryptUpdate failed");
- return clen;
+ if (EVP_EncryptFinal_ex(ctx, ct + clen, &flen) != 1)
+ logerr("EVP_EncryptFinal_ex failed");
+ return clen + flen;
}
int
-aesdec(EVP_CIPHER_CTX *ctx, unsigned char *pt, unsigned char *ct, int clen)
+aesdec(EVP_CIPHER_CTX *ctx, unsigned char *pt, unsigned char *ct, int clen,
+ unsigned char *key, unsigned char *iv)
{
- int plen;
+ int plen, flen;
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+ logerr("EVP_DecryptInit_ex failed");
if (EVP_DecryptUpdate(ctx, pt, &plen, ct, clen) != 1)
logerr("EVP_DecryptUpdate failed");
- return plen;
+ if (EVP_DecryptFinal_ex(ctx, pt + plen, &flen) != 1)
+ logerr("EVP_DecryptFinal_ex failed");
+ return plen + flen;
}
#if defined(__linux__)
@@ -453,18 +430,16 @@ writenet(int fd, unsigned char *pt, int len)
{
unsigned char payload[MTU + AES_BLOCK_SIZE];
unsigned char hdr[HDRLEN];
- unsigned char pkt[sizeof(hdr) + sizeof(payload)];
-
- /* fill padding with random bytes */
- if (padlen(len, AES_BLOCK_SIZE) > 0)
- arc4random_buf(&payload[len], padlen(len, AES_BLOCK_SIZE));
+ unsigned char iv[IVLEN];
+ unsigned char pkt[sizeof(hdr) + sizeof(payload) + sizeof(iv)];
+ arc4random_buf(iv, IVLEN);
+ len = aesenc(&ectx, payload, pt, len, aeskey, iv);
pack16(hdr, len);
- len = padto(len, AES_BLOCK_SIZE);
- aesenc(&enc, payload, pt, len);
memcpy(pkt, hdr, HDRLEN);
- memcpy(&pkt[HDRLEN], payload, len);
- len += HDRLEN;
+ memcpy(&pkt[HDRLEN], iv, IVLEN);
+ memcpy(&pkt[HDRLEN + IVLEN], payload, len);
+ len += IVLEN + HDRLEN;
return writeall(fd, pkt, len);
}
@@ -473,38 +448,43 @@ readnet(int fd, unsigned char *pt, int len)
{
unsigned char payload[MTU + AES_BLOCK_SIZE];
unsigned char hdr[HDRLEN];
- int n, pktlen, paddedlen;
+ unsigned char iv[IVLEN];
+ int n, pktlen;
- /* read unpadded packet length */
+ /* read packet length */
n = readall(fd, hdr, HDRLEN);
if (n <= 0)
return n;
pktlen = unpack16(hdr);
pktlen &= PKTLENMASK;
- paddedlen = padto(pktlen, AES_BLOCK_SIZE);
+
+ /* read IV */
+ n = readall(fd, iv, IVLEN);
+ if (n <= 0)
+ return n;
/* discard bad packets */
- if (pktlen > len || paddedlen > sizeof(payload)) {
- while (paddedlen) {
- if (paddedlen > sizeof(payload))
+ if (pktlen > sizeof(payload)) {
+ while (pktlen) {
+ if (pktlen > sizeof(payload))
len = sizeof(payload);
else
- len = paddedlen;
+ len = pktlen;
n = readall(fd, payload, len);
if (n <= 0)
break;
- paddedlen -= n;
+ pktlen -= n;
}
return BADPKT;
}
/* read encrypted payload */
- n = readall(fd, payload, paddedlen);
+ n = readall(fd, payload, pktlen);
if (n <= 0)
return n;
- aesdec(&dec, pt, payload, paddedlen);
+ pktlen = aesdec(&dctx, pt, payload, pktlen, aeskey, iv);
return pktlen;
}
@@ -670,7 +650,6 @@ serversetup(int devfd)
setsockopt(netfd, IPPROTO_TCP, TCP_NODELAY, (int []){1}, sizeof(int));
- aesinit(&enc, &dec);
ret = challenge(netfd);
if (ret < 0) {
logwarn("server -> client challenge failed");
@@ -685,7 +664,6 @@ serversetup(int devfd)
tunnel(netfd, devfd);
err:
- aesterm(&enc, &dec);
close(netfd);
if (debug)
logdbg("remote peer disconnected: %s",
@@ -729,7 +707,6 @@ clientsetup(int devfd)
if (debug)
logdbg("connected to %s:%s", host, port);
- aesinit(&enc, &dec);
ret = response(netfd);
if (ret < 0) {
logwarn("client -> server response failed");
@@ -745,7 +722,6 @@ clientsetup(int devfd)
ret = tunnel(netfd, devfd);
err:
logwarn("connection to %s:%s dropped", host, port);
- aesterm(&enc, &dec);
close(netfd);
return ret;
}
@@ -837,6 +813,7 @@ main(int argc, char *argv[])
prepkey((unsigned char *)pw, strlen(pw));
explicit_bzero(pw, strlen(pw));
+ aesinit(&ectx, &dctx);
if (sflag)
return serversetup(devfd);
revokeprivs();