stun

simple point to point tunnel
git clone git://git.2f30.org/stun
Log | Files | Refs | README

commit fdcdd2572d4476996b65742a8cce502a321bea0c
parent b59586b4ba0af5a83f144466a9fa1d72ff2d2006
Author: sin <sin@2f30.org>
Date:   Tue, 29 Mar 2016 23:57:35 +0100

more crypto work

Diffstat:
Mstun.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();