Linting and formatting of .c and .h with C/C++ IntelliSence

This commit is contained in:
conc3rned
2024-09-17 16:19:54 +03:00
parent 8c94e3230e
commit c1db09b19e
80 changed files with 9996 additions and 8587 deletions

View File

@@ -2,64 +2,65 @@
#include "checksum.h"
#include <netinet/in.h>
//#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
//#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
// #define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
// #define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
static uint16_t from64to16(uint64_t x)
{
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x>>16) + (uint16_t)(x>>32) + (uint16_t)(x>>48);
return (uint16_t)u + (uint16_t)(u>>16);
uint32_t u = (uint32_t)(uint16_t)x + (uint16_t)(x >> 16) + (uint16_t)(x >> 32) + (uint16_t)(x >> 48);
return (uint16_t)u + (uint16_t)(u >> 16);
}
// this function preserves data alignment requirements (otherwise it will be damn slow on mips arch)
// and uses 64-bit arithmetics to improve speed
// taken from linux source code
static uint16_t do_csum(const uint8_t * buff, size_t len)
// taken from Linux source code
static uint16_t do_csum(const uint8_t *buff, size_t len)
{
uint8_t odd;
size_t count;
uint64_t result,w,carry=0;
uint64_t result, w, carry = 0;
uint16_t u16;
if (!len) return 0;
if (!len)
return 0;
odd = (uint8_t)(1 & (size_t)buff);
if (odd)
{
// any endian compatible
u16 = 0;
*((uint8_t*)&u16+1) = *buff;
*((uint8_t *)&u16 + 1) = *buff;
result = u16;
len--;
buff++;
}
else
result = 0;
count = len >> 1; /* nr of 16-bit words.. */
count = len >> 1; /* nr of 16-bit words.. */
if (count)
{
if (2 & (size_t) buff)
if (2 & (size_t)buff)
{
result += *(uint16_t *) buff;
result += *(uint16_t *)buff;
count--;
len -= 2;
buff += 2;
}
count >>= 1; /* nr of 32-bit words.. */
count >>= 1; /* nr of 32-bit words.. */
if (count)
{
if (4 & (size_t) buff)
if (4 & (size_t)buff)
{
result += *(uint32_t *) buff;
result += *(uint32_t *)buff;
count--;
len -= 4;
buff += 4;
}
count >>= 1; /* nr of 64-bit words.. */
count >>= 1; /* nr of 64-bit words.. */
if (count)
{
do
{
w = *(uint64_t *) buff;
w = *(uint64_t *)buff;
count--;
buff += 8;
result += carry;
@@ -71,13 +72,13 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
}
if (len & 4)
{
result += *(uint32_t *) buff;
result += *(uint32_t *)buff;
buff += 4;
}
}
if (len & 2)
{
result += *(uint16_t *) buff;
result += *(uint16_t *)buff;
buff += 2;
}
}
@@ -85,54 +86,54 @@ static uint16_t do_csum(const uint8_t * buff, size_t len)
{
// any endian compatible
u16 = 0;
*(uint8_t*)&u16 = *buff;
*(uint8_t *)&u16 = *buff;
result += u16;
}
u16 = from64to16(result);
if (odd) u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
if (odd)
u16 = ((u16 >> 8) & 0xff) | ((u16 & 0xff) << 8);
return u16;
}
uint16_t csum_partial(const void *buff, size_t len)
{
return do_csum(buff,len);
return do_csum(buff, len);
}
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
{
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len+proto));
return ~from64to16((uint64_t)saddr + daddr + sum + htonl(len + proto));
}
uint16_t ip4_compute_csum(const void *buff, size_t len)
{
return ~from64to16(do_csum(buff,len));
return ~from64to16(do_csum(buff, len));
}
void ip4_fix_checksum(struct ip *ip)
{
ip->ip_sum = 0;
ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl<<2);
ip->ip_sum = ip4_compute_csum(ip, ip->ip_hl << 2);
}
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
{
uint64_t a = (uint64_t)sum + htonl(len+proto) +
*(uint32_t*)saddr + *((uint32_t*)saddr+1) + *((uint32_t*)saddr+2) + *((uint32_t*)saddr+3) +
*(uint32_t*)daddr + *((uint32_t*)daddr+1) + *((uint32_t*)daddr+2) + *((uint32_t*)daddr+3);
uint64_t a = (uint64_t)sum + htonl(len + proto) +
*(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) +
*(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
return ~from64to16(a);
}
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{
tcp->th_sum = 0;
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
tcp->th_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
}
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
tcp->th_sum = 0;
tcp->th_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp,len));
tcp->th_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_TCP, csum_partial(tcp, len));
}
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{
if (ip)
tcp4_fix_checksum(tcp, len, &ip->ip_src, &ip->ip_dst);
@@ -140,17 +141,17 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr,dest_addr->s_addr,len,IPPROTO_UDP,csum_partial(udp,len));
udp->uh_sum = csum_tcpudp_magic(src_addr->s_addr, dest_addr->s_addr, len, IPPROTO_UDP, csum_partial(udp, len));
}
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr)
{
udp->uh_sum = 0;
udp->uh_sum = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_UDP,csum_partial(udp,len));
udp->uh_sum = csum_ipv6_magic(src_addr, dest_addr, len, IPPROTO_UDP, csum_partial(udp, len));
}
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr)
void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr)
{
if (ip)
udp4_fix_checksum(udp, len, &ip->ip_src, &ip->ip_dst);

View File

@@ -18,10 +18,10 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
uint16_t ip4_compute_csum(const void *buff, size_t len);
void ip4_fix_checksum(struct ip *ip);
void tcp4_fix_checksum(struct tcphdr *tcp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void tcp4_fix_checksum(struct tcphdr *tcp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void tcp6_fix_checksum(struct tcphdr *tcp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void tcp_fix_checksum(struct tcphdr *tcp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void udp4_fix_checksum(struct udphdr *udp, size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp, size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const struct ip6_hdr *ip6hdr);

View File

@@ -12,11 +12,11 @@ static void ut_oom_recover(void *elem)
oom = true;
}
static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
static const char *connstate_s[] = {"SYN", "ESTABLISHED", "FIN"};
static void connswap(const t_conn *c, t_conn *c2)
{
memset(c2,0,sizeof(*c2));
memset(c2, 0, sizeof(*c2));
c2->l3proto = c->l3proto;
c2->l4proto = c->l4proto;
c2->src = c->dst;
@@ -49,7 +49,11 @@ static void ConntrackFreeElem(t_conntrack_pool *elem)
static void ConntrackPoolDestroyPool(t_conntrack_pool **pp)
{
t_conntrack_pool *elem, *tmp;
HASH_ITER(hh, *pp, elem, tmp) { HASH_DEL(*pp, elem); ConntrackFreeElem(elem); }
HASH_ITER(hh, *pp, elem, tmp)
{
HASH_DEL(*pp, elem);
ConntrackFreeElem(elem);
}
}
void ConntrackPoolDestroy(t_conntrack *p)
{
@@ -61,7 +65,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
p->timeout_syn = timeout_syn;
p->timeout_established = timeout_established;
p->timeout_fin = timeout_fin;
p->timeout_udp= timeout_udp;
p->timeout_udp = timeout_udp;
p->t_purge_interval = purge_interval;
time(&p->t_last_purge);
p->pool = NULL;
@@ -69,7 +73,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
memset(c,0,sizeof(*c));
memset(c, 0, sizeof(*c));
if (ip)
{
c->l3proto = IPPROTO_IP;
@@ -87,7 +91,6 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct ip *ip, const s
extract_ports(tcphdr, udphdr, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
}
static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *c)
{
t_conntrack_pool *t;
@@ -97,7 +100,7 @@ static t_conntrack_pool *ConntrackPoolSearch(t_conntrack_pool *p, const t_conn *
static void ConntrackInitTrack(t_ctrack *t)
{
memset(t,0,sizeof(*t));
memset(t, 0, sizeof(*t));
t->scale_orig = t->scale_reply = SCALE_NONE;
time(&t->t_start);
rawpacket_queue_init(&t->delayed);
@@ -111,11 +114,16 @@ static void ConntrackReInitTrack(t_ctrack *t)
static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
{
t_conntrack_pool *ctnew;
if (!(ctnew = malloc(sizeof(*ctnew)))) return NULL;
if (!(ctnew = malloc(sizeof(*ctnew))))
return NULL;
ctnew->conn = *c;
oom = false;
HASH_ADD(hh, *pp, conn, sizeof(*c), ctnew);
if (oom) { free(ctnew); return NULL; }
if (oom)
{
free(ctnew);
return NULL;
}
ConntrackInitTrack(&ctnew->track);
return ctnew;
}
@@ -128,38 +136,41 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse)
{
t->pcounter_reply++;
t->pdcounter_reply+=!!len_payload;
t->pdcounter_reply += !!len_payload;
}
else
{
t->pcounter_orig++;
t->pdcounter_orig+=!!len_payload;
t->pdcounter_orig += !!len_payload;
}
if (tcphdr)
{
if (tcp_syn_segment(tcphdr))
{
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
if (t->state != SYN)
ConntrackReInitTrack(t); // erase current entry
t->seq0 = ntohl(tcphdr->th_seq);
}
else if (tcp_synack_segment(tcphdr))
{
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1;
if (t->state != SYN)
ConntrackReInitTrack(t); // erase current entry
if (!t->seq0)
t->seq0 = ntohl(tcphdr->th_ack) - 1;
t->ack0 = ntohl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN|TH_RST))
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
{
t->state = FIN;
}
else
{
if (t->state==SYN)
if (t->state == SYN)
{
t->state=ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1;
t->state = ESTABLISHED;
if (!bReverse && !t->ack0)
t->ack0 = ntohl(tcphdr->th_ack) - 1;
}
}
scale = tcp_find_scale_factor(tcphdr);
@@ -169,8 +180,8 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
t->ack_last = ntohl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload;
t->winsize_reply = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale;
if (scale != SCALE_NONE)
t->scale_reply = scale;
}
else
{
@@ -178,20 +189,21 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
t->winsize_orig = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale;
if (scale != SCALE_NONE)
t->scale_orig = scale;
}
}
else
{
if (bReverse)
{
t->ack_last=t->pos_reply;
t->pos_reply+=len_payload;
t->ack_last = t->pos_reply;
t->pos_reply += len_payload;
}
else
{
t->seq_last=t->pos_orig;
t->pos_orig+=len_payload;
t->seq_last = t->pos_orig;
t->pos_orig += len_payload;
}
}
@@ -200,23 +212,27 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse)
{
t_conn conn,connswp;
t_conn conn, connswp;
t_conntrack_pool *ctr;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
if (bReverse) *bReverse = false;
if (ctrack) *ctrack = &ctr->track;
if (bReverse)
*bReverse = false;
if (ctrack)
*ctrack = &ctr->track;
return true;
}
else
{
connswap(&conn,&connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp)))
connswap(&conn, &connswp);
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{
if (bReverse) *bReverse = true;
if (ctrack) *ctrack = &ctr->track;
if (bReverse)
*bReverse = true;
if (ctrack)
*ctrack = &ctr->track;
return true;
}
}
@@ -233,25 +249,25 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
t_conntrack_pool *ctr;
bool b_rev;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if ((ctr=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=false), tcphdr, len_payload);
ConntrackFeedPacket(&ctr->track, (b_rev = false), tcphdr, len_payload);
goto ok;
}
else
{
connswap(&conn,&connswp);
if ((ctr=ConntrackPoolSearch(*pp,&connswp)))
connswap(&conn, &connswp);
if ((ctr = ConntrackPoolSearch(*pp, &connswp)))
{
ConntrackFeedPacket(&ctr->track, (b_rev=true), tcphdr, len_payload);
ConntrackFeedPacket(&ctr->track, (b_rev = true), tcphdr, len_payload);
goto ok;
}
}
b_rev = tcphdr && tcp_synack_segment(tcphdr);
if ((tcphdr && tcp_syn_segment(tcphdr)) || b_rev || udphdr)
{
if ((ctr=ConntrackNew(pp, b_rev ? &connswp : &conn)))
if ((ctr = ConntrackNew(pp, b_rev ? &connswp : &conn)))
{
ConntrackFeedPacket(&ctr->track, b_rev, tcphdr, len_payload);
goto ok;
@@ -259,32 +275,36 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct ip *ip, co
}
return false;
ok:
if (ctrack) *ctrack = &ctr->track;
if (bReverse) *bReverse = b_rev;
if (ctrack)
*ctrack = &ctr->track;
if (bReverse)
*bReverse = b_rev;
return true;
}
bool ConntrackPoolFeed(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, size_t len_payload, t_ctrack **ctrack, bool *bReverse)
{
return ConntrackPoolFeedPool(&p->pool,ip,ip6,tcphdr,udphdr,len_payload,ctrack,bReverse);
return ConntrackPoolFeedPool(&p->pool, ip, ip6, tcphdr, udphdr, len_payload, ctrack, bReverse);
}
static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
t_conn conn, connswp;
t_conntrack_pool *t;
ConntrackExtractConn(&conn,false,ip,ip6,tcphdr,udphdr);
if (!(t=ConntrackPoolSearch(*pp,&conn)))
ConntrackExtractConn(&conn, false, ip, ip6, tcphdr, udphdr);
if (!(t = ConntrackPoolSearch(*pp, &conn)))
{
connswap(&conn,&connswp);
t=ConntrackPoolSearch(*pp,&connswp);
connswap(&conn, &connswp);
t = ConntrackPoolSearch(*pp, &connswp);
}
if (!t) return false;
HASH_DEL(*pp, t); ConntrackFreeElem(t);
if (!t)
return false;
HASH_DEL(*pp, t);
ConntrackFreeElem(t);
return true;
}
bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr)
{
return ConntrackPoolDropPool(&p->pool,ip,ip6,tcphdr,udphdr);
return ConntrackPoolDropPool(&p->pool, ip, ip6, tcphdr, udphdr);
}
void ConntrackPoolPurge(t_conntrack *p)
@@ -292,19 +312,19 @@ void ConntrackPoolPurge(t_conntrack *p)
time_t tidle, tnow = time(NULL);
t_conntrack_pool *t, *tmp;
if ((tnow - p->t_last_purge)>=p->t_purge_interval)
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
{
HASH_ITER(hh, p->pool , t, tmp) {
HASH_ITER(hh, p->pool, t, tmp)
{
tidle = tnow - t->track.t_last;
if ( t->track.b_cutoff ||
(t->conn.l4proto==IPPROTO_TCP && (
(t->track.state==SYN && tidle>=p->timeout_syn) ||
(t->track.state==ESTABLISHED && tidle>=p->timeout_established) ||
(t->track.state==FIN && tidle>=p->timeout_fin))
) || (t->conn.l4proto==IPPROTO_UDP && tidle>=p->timeout_udp)
)
if (t->track.b_cutoff ||
(t->conn.l4proto == IPPROTO_TCP && ((t->track.state == SYN && tidle >= p->timeout_syn) ||
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
(t->track.state == FIN && tidle >= p->timeout_fin))) ||
(t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp))
{
HASH_DEL(p->pool, t); ConntrackFreeElem(t);
HASH_DEL(p->pool, t);
ConntrackFreeElem(t);
}
}
p->t_last_purge = tnow;
@@ -313,52 +333,59 @@ void ConntrackPoolPurge(t_conntrack *p)
static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsize)
{
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize) *buf=0;
if (!inet_ntop(family_from_proto(l3proto), a, buf, bufsize) && bufsize)
*buf = 0;
}
static const char *ConntrackProtoName(t_l7proto proto)
{
switch(proto)
switch (proto)
{
case HTTP: return "HTTP";
case TLS: return "TLS";
case QUIC: return "QUIC";
case WIREGUARD: return "WIREGUARD";
case DHT: return "DHT";
default: return "UNKNOWN";
case HTTP:
return "HTTP";
case TLS:
return "TLS";
case QUIC:
return "QUIC";
case WIREGUARD:
return "WIREGUARD";
case DHT:
return "DHT";
default:
return "UNKNOWN";
}
}
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
char sa1[40],sa2[40];
char sa1[40], sa2[40];
time_t tnow = time(NULL);
HASH_ITER(hh, p->pool, t, tmp) {
HASH_ITER(hh, p->pool, t, tmp)
{
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu packets_orig=d%llu/n%llu packets_reply=d%llu/n%llu ",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto==IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply);
if (t->conn.l4proto==IPPROTO_TCP)
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.state] : "-",
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig,
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply);
if (t->conn.l4proto == IPPROTO_TCP)
printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d",
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.winsize_orig, t->track.scale_orig==SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply==SCALE_NONE ? -1 : t->track.scale_reply);
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
t->track.winsize_orig, t->track.scale_orig == SCALE_NONE ? -1 : t->track.scale_orig,
t->track.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply);
else
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
t->track.seq_last, t->track.pos_orig,
t->track.ack_last, t->track.pos_reply);
printf(" req_retrans=%u cutoff=%u wss_cutoff=%u d_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_wssize_cutoff, t->track.b_desync_cutoff, t->track.hostname, ConntrackProtoName(t->track.l7proto));
};
}
void ReasmClear(t_reassemble *reasm)
{
if (reasm->packet)
@@ -371,7 +398,8 @@ void ReasmClear(t_reassemble *reasm)
bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
{
reasm->packet = malloc(size_requested);
if (!reasm->packet) return false;
if (!reasm->packet)
return false;
reasm->size = size_requested;
reasm->size_present = 0;
reasm->seq = seq_start;
@@ -380,19 +408,23 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
bool ReasmResize(t_reassemble *reasm, size_t new_size)
{
uint8_t *p = realloc(reasm->packet, new_size);
if (!p) return false;
if (!p)
return false;
reasm->packet = p;
reasm->size = new_size;
if (reasm->size_present > new_size) reasm->size_present = new_size;
if (reasm->size_present > new_size)
reasm->size_present = new_size;
return true;
}
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
{
if (reasm->seq!=seq) return false; // fail session if out of sequence
if (reasm->seq != seq)
return false; // fail session if out of sequence
size_t szcopy;
szcopy = reasm->size - reasm->size_present;
if (len<szcopy) szcopy = len;
if (len < szcopy)
szcopy = len;
memcpy(reasm->packet + reasm->size_present, payload, szcopy);
reasm->size_present += szcopy;
reasm->seq += (uint32_t)szcopy;
@@ -401,5 +433,5 @@ bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t le
}
bool ReasmHasSpace(t_reassemble *reasm, size_t len)
{
return (reasm->size_present+len)<=reasm->size;
return (reasm->size_present + len) <= reasm->size;
}

View File

@@ -1,6 +1,5 @@
#pragma once
// this conntrack is not bullet-proof
// its designed to satisfy dpi desync needs only
@@ -19,68 +18,82 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
//#define HASH_BLOOM 20
// #define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#undef HASH_FUNCTION
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
#define RETRANS_COUNTER_STOP ((uint8_t)-1)
#define RETRANS_COUNTER_STOP ((uint8_t) - 1)
typedef union {
typedef union
{
struct in_addr ip;
struct in6_addr ip6;
} t_addr;
typedef struct
{
t_addr src, dst;
uint16_t sport,dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint16_t sport, dport;
uint8_t l3proto; // IPPROTO_IP, IPPROTO_IPV6
uint8_t l4proto; // IPPROTO_TCP, IPPROTO_UDP
} t_conn;
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
typedef struct {
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
size_t size_present; // how many bytes already stored in 'packet'
typedef struct
{
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
size_t size_present; // how many bytes already stored in 'packet'
} t_reassemble;
// SYN - SYN or SYN/ACK received
// ESTABLISHED - any except SYN or SYN/ACK received
// FIN - FIN or RST received
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
typedef enum
{
SYN = 0,
ESTABLISHED,
FIN
} t_connstate;
typedef enum
{
UNKNOWN = 0,
HTTP,
TLS,
QUIC,
WIREGUARD,
DHT
} t_l7proto;
typedef struct
{
// common state
time_t t_start, t_last;
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pcounter_orig, pcounter_reply; // packet counter
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
// tcp only state, not used in udp
t_connstate state;
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
uint32_t seq0, ack0; // starting seq and ack
uint16_t winsize_orig, winsize_reply; // last seen window size
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present, req_seq_finalized, req_seq_abandoned;
uint32_t req_seq_start, req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t autottl;
bool b_cutoff; // mark for deletion
bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff;
t_l7proto l7proto;
char *hostname;
bool hostname_ah_check; // should perform autohostlist checks
bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig;
struct rawpacket_tailhead delayed;
} t_ctrack;
@@ -88,13 +101,13 @@ typedef struct
typedef struct
{
t_ctrack track;
UT_hash_handle hh; // makes this structure hashable
t_conn conn; // key
UT_hash_handle hh; // makes this structure hashable
t_conn conn; // key
} t_conntrack_pool;
typedef struct
{
// inactivity time to purge an entry in each connection state
uint32_t timeout_syn,timeout_established,timeout_fin,timeout_udp;
uint32_t timeout_syn, timeout_established, timeout_fin, timeout_udp;
time_t t_purge_interval, t_last_purge;
t_conntrack_pool *pool;
} t_conntrack;
@@ -117,5 +130,5 @@ void ReasmClear(t_reassemble *reasm);
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len);
// check if it has enough space to buffer 'len' bytes
bool ReasmHasSpace(t_reassemble *reasm, size_t len);
inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;}
inline static bool ReasmIsFull(t_reassemble *reasm) {return !ReasmIsEmpty(reasm) && (reasm->size==reasm->size_present);}
inline static bool ReasmIsEmpty(t_reassemble *reasm) { return !reasm->size; }
inline static bool ReasmIsFull(t_reassemble *reasm) { return !ReasmIsEmpty(reasm) && (reasm->size == reasm->size_present); }

View File

@@ -1,6 +1,6 @@
#pragma once
#include "gcm.h"
#include "gcm.h"
// mode : AES_ENCRYPT, AES_DECRYPT
int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len);

View File

@@ -1,29 +1,29 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#include "aes.h"
static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below)
static int aes_tables_inited = 0; // run-once flag for performing key
// expasion table generation (see below)
/*
* The following static local tables must be filled-in before the first use of
* the GCM or AES ciphers. They are used for the AES key expansion/scheduling
@@ -37,175 +37,189 @@ static int aes_tables_inited = 0; // run-once flag for performing key
* the GCM input, we ONLY NEED AES encryption. Thus, to save space AES
* decryption is typically disabled by setting AES_DECRYPTION to 0 in aes.h.
*/
// We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
// We always need our forward tables
static uchar FSb[256]; // Forward substitution box (FSb)
static uint32_t FT0[256]; // Forward key schedule assembly tables
static uint32_t FT1[256];
static uint32_t FT2[256];
static uint32_t FT3[256];
#if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
#if AES_DECRYPTION // We ONLY need reverse for decryption
static uchar RSb[256]; // Reverse substitution box (RSb)
static uint32_t RT0[256]; // Reverse key schedule assembly tables
static uint32_t RT1[256];
static uint32_t RT2[256];
static uint32_t RT3[256];
#endif /* AES_DECRYPTION */
#endif /* AES_DECRYPTION */
static uint32_t RCON[10]; // AES round constants
static uint32_t RCON[10]; // AES round constants
/*
* Platform Endianness Neutralizing Load and Store Macro definitions
* AES wants platform-neutral Little Endian (LE) byte ordering
*/
#define GET_UINT32_LE(n,b,i) { \
(n) = ( (uint32_t) (b)[(i) ] ) \
| ( (uint32_t) (b)[(i) + 1] << 8 ) \
| ( (uint32_t) (b)[(i) + 2] << 16 ) \
| ( (uint32_t) (b)[(i) + 3] << 24 ); }
#define GET_UINT32_LE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
}
#define PUT_UINT32_LE(n,b,i) { \
(b)[(i) ] = (uchar) ( (n) ); \
(b)[(i) + 1] = (uchar) ( (n) >> 8 ); \
(b)[(i) + 2] = (uchar) ( (n) >> 16 ); \
(b)[(i) + 3] = (uchar) ( (n) >> 24 ); }
#define PUT_UINT32_LE(n, b, i) \
{ \
(b)[(i)] = (uchar)((n)); \
(b)[(i) + 1] = (uchar)((n) >> 8); \
(b)[(i) + 2] = (uchar)((n) >> 16); \
(b)[(i) + 3] = (uchar)((n) >> 24); \
}
/*
* AES forward and reverse encryption round processing macros
*/
#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \
FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \
FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y0 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \
FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \
FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
FT3[ ( Y2 >> 24 ) & 0xFF ]; \
}
/*
* AES forward and reverse encryption round processing macros
*/
#define AES_FROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ FT0[(Y0) & 0xFF] ^ \
FT1[(Y1 >> 8) & 0xFF] ^ \
FT2[(Y2 >> 16) & 0xFF] ^ \
FT3[(Y3 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ FT0[(Y1) & 0xFF] ^ \
FT1[(Y2 >> 8) & 0xFF] ^ \
FT2[(Y3 >> 16) & 0xFF] ^ \
FT3[(Y0 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ FT0[(Y2) & 0xFF] ^ \
FT1[(Y3 >> 8) & 0xFF] ^ \
FT2[(Y0 >> 16) & 0xFF] ^ \
FT3[(Y1 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ FT0[(Y3) & 0xFF] ^ \
FT1[(Y0 >> 8) & 0xFF] ^ \
FT2[(Y1 >> 16) & 0xFF] ^ \
FT3[(Y2 >> 24) & 0xFF]; \
}
#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \
{ \
X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \
RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y1 >> 24 ) & 0xFF ]; \
\
X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \
RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y2 >> 24 ) & 0xFF ]; \
\
X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \
RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y3 >> 24 ) & 0xFF ]; \
\
X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \
RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \
RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \
RT3[ ( Y0 >> 24 ) & 0xFF ]; \
}
#define AES_RROUND(X0, X1, X2, X3, Y0, Y1, Y2, Y3) \
{ \
X0 = *RK++ ^ RT0[(Y0) & 0xFF] ^ \
RT1[(Y3 >> 8) & 0xFF] ^ \
RT2[(Y2 >> 16) & 0xFF] ^ \
RT3[(Y1 >> 24) & 0xFF]; \
\
X1 = *RK++ ^ RT0[(Y1) & 0xFF] ^ \
RT1[(Y0 >> 8) & 0xFF] ^ \
RT2[(Y3 >> 16) & 0xFF] ^ \
RT3[(Y2 >> 24) & 0xFF]; \
\
X2 = *RK++ ^ RT0[(Y2) & 0xFF] ^ \
RT1[(Y1 >> 8) & 0xFF] ^ \
RT2[(Y0 >> 16) & 0xFF] ^ \
RT3[(Y3 >> 24) & 0xFF]; \
\
X3 = *RK++ ^ RT0[(Y3) & 0xFF] ^ \
RT1[(Y2 >> 8) & 0xFF] ^ \
RT2[(Y1 >> 16) & 0xFF] ^ \
RT3[(Y0 >> 24) & 0xFF]; \
}
/*
* These macros improve the readability of the key
* generation initialization code by collapsing
* repetitive common operations into logical pieces.
*/
#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 )
#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) )
#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 )
#define MIX(x,y) { y = ( (y << 1) | (y >> 7) ) & 0xFF; x ^= y; }
#define CPY128 { *RK++ = *SK++; *RK++ = *SK++; \
*RK++ = *SK++; *RK++ = *SK++; }
/*
* These macros improve the readability of the key
* generation initialization code by collapsing
* repetitive common operations into logical pieces.
*/
#define ROTL8(x) ((x << 8) & 0xFFFFFFFF) | (x >> 24)
#define XTIME(x) ((x << 1) ^ ((x & 0x80) ? 0x1B : 0x00))
#define MUL(x, y) ((x && y) ? pow[(log[x] + log[y]) % 255] : 0)
#define MIX(x, y) \
{ \
y = ((y << 1) | (y >> 7)) & 0xFF; \
x ^= y; \
}
#define CPY128 \
{ \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
*RK++ = *SK++; \
}
/******************************************************************************
*
* AES_INIT_KEYGEN_TABLES
*
* Fills the AES key expansion tables allocated above with their static
* data. This is not "per key" data, but static system-wide read-only
* table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once
* at system initialization to setup the tables for all subsequent use.
*
******************************************************************************/
/******************************************************************************
*
* AES_INIT_KEYGEN_TABLES
*
* Fills the AES key expansion tables allocated above with their static
* data. This is not "per key" data, but static system-wide read-only
* table data. THIS FUNCTION IS NOT THREAD SAFE. It must be called once
* at system initialization to setup the tables for all subsequent use.
*
******************************************************************************/
void aes_init_keygen_tables(void)
{
int i, x, y, z; // general purpose iteration and computation locals
int i, x, y, z; // general purpose iteration and computation locals
int pow[256];
int log[256];
if (aes_tables_inited) return;
if (aes_tables_inited)
return;
// fill the 'pow' and 'log' tables over GF(2^8)
for (i = 0, x = 1; i < 256; i++) {
for (i = 0, x = 1; i < 256; i++)
{
pow[i] = x;
log[x] = i;
x = (x ^ XTIME(x)) & 0xFF;
}
// compute the round constants
for (i = 0, x = 1; i < 10; i++) {
for (i = 0, x = 1; i < 10; i++)
{
RCON[i] = (uint32_t)x;
x = XTIME(x) & 0xFF;
}
// fill the forward and reverse substitution boxes
FSb[0x00] = 0x63;
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
RSb[0x63] = 0x00;
#endif /* AES_DECRYPTION */
for (i = 1; i < 256; i++) {
for (i = 1; i < 256; i++)
{
x = y = pow[255 - log[i]];
MIX(x, y);
MIX(x, y);
MIX(x, y);
MIX(x, y);
FSb[i] = (uchar)(x ^= 0x63);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
RSb[x] = (uchar)i;
#endif /* AES_DECRYPTION */
}
// generate the forward and reverse key expansion tables
for (i = 0; i < 256; i++) {
for (i = 0; i < 256; i++)
{
x = FSb[i];
y = XTIME(x) & 0xFF;
z = (y ^ x) & 0xFF;
FT0[i] = ((uint32_t)y) ^ ((uint32_t)x << 8) ^
((uint32_t)x << 16) ^ ((uint32_t)z << 24);
((uint32_t)x << 16) ^ ((uint32_t)z << 24);
FT1[i] = ROTL8(FT0[i]);
FT2[i] = ROTL8(FT1[i]);
FT3[i] = ROTL8(FT2[i]);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
x = RSb[i];
RT0[i] = ((uint32_t)MUL(0x0E, x)) ^
((uint32_t)MUL(0x09, x) << 8) ^
((uint32_t)MUL(0x0D, x) << 16) ^
((uint32_t)MUL(0x0B, x) << 24);
((uint32_t)MUL(0x09, x) << 8) ^
((uint32_t)MUL(0x0D, x) << 16) ^
((uint32_t)MUL(0x0B, x) << 24);
RT1[i] = ROTL8(RT0[i]);
RT2[i] = ROTL8(RT1[i]);
RT3[i] = ROTL8(RT2[i]);
#endif /* AES_DECRYPTION */
}
aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher
aes_tables_inited = 1; // flag that the tables have been generated
} // to permit subsequent use of the AES cipher
/******************************************************************************
*
@@ -218,25 +232,27 @@ void aes_init_keygen_tables(void)
*
******************************************************************************/
int aes_set_encryption_key(aes_context *ctx,
const uchar *key,
uint keysize)
const uchar *key,
uint keysize)
{
uint i; // general purpose iteration local
uint i; // general purpose iteration local
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
for (i = 0; i < (keysize >> 2); i++) {
for (i = 0; i < (keysize >> 2); i++)
{
GET_UINT32_LE(RK[i], key, i << 2);
}
switch (ctx->rounds)
{
case 10:
for (i = 0; i < 10; i++, RK += 4) {
for (i = 0; i < 10; i++, RK += 4)
{
RK[4] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
((uint32_t)FSb[(RK[3] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[3] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[3] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[3]) & 0xFF] << 24);
RK[5] = RK[1] ^ RK[4];
RK[6] = RK[2] ^ RK[5];
@@ -245,12 +261,13 @@ int aes_set_encryption_key(aes_context *ctx,
break;
case 12:
for (i = 0; i < 8; i++, RK += 6) {
for (i = 0; i < 8; i++, RK += 6)
{
RK[6] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
((uint32_t)FSb[(RK[5] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[5] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[5] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[5]) & 0xFF] << 24);
RK[7] = RK[1] ^ RK[6];
RK[8] = RK[2] ^ RK[7];
@@ -261,22 +278,23 @@ int aes_set_encryption_key(aes_context *ctx,
break;
case 14:
for (i = 0; i < 7; i++, RK += 8) {
for (i = 0; i < 7; i++, RK += 8)
{
RK[8] = RK[0] ^ RCON[i] ^
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
((uint32_t)FSb[(RK[7] >> 8) & 0xFF]) ^
((uint32_t)FSb[(RK[7] >> 16) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[7] >> 24) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[7]) & 0xFF] << 24);
RK[9] = RK[1] ^ RK[8];
RK[10] = RK[2] ^ RK[9];
RK[11] = RK[3] ^ RK[10];
RK[12] = RK[4] ^
((uint32_t)FSb[(RK[11]) & 0xFF]) ^
((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
((uint32_t)FSb[(RK[11]) & 0xFF]) ^
((uint32_t)FSb[(RK[11] >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(RK[11] >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(RK[11] >> 24) & 0xFF] << 24);
RK[13] = RK[5] ^ RK[12];
RK[14] = RK[6] ^ RK[13];
@@ -287,10 +305,10 @@ int aes_set_encryption_key(aes_context *ctx,
default:
return -1;
}
return(0);
return (0);
}
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
/******************************************************************************
*
@@ -303,36 +321,38 @@ int aes_set_encryption_key(aes_context *ctx,
*
******************************************************************************/
int aes_set_decryption_key(aes_context *ctx,
const uchar *key,
uint keysize)
const uchar *key,
uint keysize)
{
int i, j;
aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
aes_context cty; // a calling aes context for set_encryption_key
uint32_t *RK = ctx->rk; // initialize our RoundKey buffer pointer
uint32_t *SK;
int ret;
cty.rounds = ctx->rounds; // initialize our local aes context
cty.rk = cty.buf; // round count and key buf pointer
cty.rounds = ctx->rounds; // initialize our local aes context
cty.rk = cty.buf; // round count and key buf pointer
if ((ret = aes_set_encryption_key(&cty, key, keysize)) != 0)
return(ret);
return (ret);
SK = cty.rk + cty.rounds * 4;
CPY128 // copy a 128-bit block from *SK to *RK
CPY128 // copy a 128-bit block from *SK to *RK
for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8) {
for (j = 0; j < 4; j++, SK++) {
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
for (i = ctx->rounds - 1, SK -= 8; i > 0; i--, SK -= 8)
{
for (j = 0; j < 4; j++, SK++)
{
*RK++ = RT0[FSb[(*SK) & 0xFF]] ^
RT1[FSb[(*SK >> 8) & 0xFF]] ^
RT2[FSb[(*SK >> 16) & 0xFF]] ^
RT3[FSb[(*SK >> 24) & 0xFF]];
}
}
CPY128 // copy a 128-bit block from *SK to *RK
memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return(0);
}
CPY128 // copy a 128-bit block from *SK to *RK
memset(&cty, 0, sizeof(aes_context)); // clear local aes context
return (0);
}
#endif /* AES_DECRYPTION */
@@ -344,34 +364,42 @@ int aes_set_decryption_key(aes_context *ctx,
* Invoked to establish the key schedule for subsequent encryption/decryption
*
******************************************************************************/
int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
int aes_setkey(aes_context *ctx, // AES context provided by our caller
int mode, // ENCRYPT or DECRYPT flag
const uchar *key, // pointer to the key
uint keysize) // key length in bytes
{
// since table initialization is not thread safe, we could either add
// system-specific mutexes and init the AES key generation tables on
// demand, or ask the developer to simply call "gcm_initialize" once during
// application startup before threading begins. That's what we choose.
if (!aes_tables_inited) return (-1); // fail the call when not inited.
if (!aes_tables_inited)
return (-1); // fail the call when not inited.
ctx->mode = mode; // capture the key type we're creating
ctx->rk = ctx->buf; // initialize our round key pointer
ctx->mode = mode; // capture the key type we're creating
ctx->rk = ctx->buf; // initialize our round key pointer
switch (keysize) // set the rounds count based upon the keysize
switch (keysize) // set the rounds count based upon the keysize
{
case 16: ctx->rounds = 10; break; // 16-byte, 128-bit key
case 24: ctx->rounds = 12; break; // 24-byte, 192-bit key
case 32: ctx->rounds = 14; break; // 32-byte, 256-bit key
default: return(-1);
case 16:
ctx->rounds = 10;
break; // 16-byte, 128-bit key
case 24:
ctx->rounds = 12;
break; // 24-byte, 192-bit key
case 32:
ctx->rounds = 14;
break; // 32-byte, 256-bit key
default:
return (-1);
}
#if AES_DECRYPTION
if (mode == DECRYPT) // expand our key for encryption or decryption
return(aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */
#endif /* AES_DECRYPTION */
return(aes_set_encryption_key(ctx, key, keysize));
if (mode == DECRYPT) // expand our key for encryption or decryption
return (aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */
#endif /* AES_DECRYPTION */
return (aes_set_encryption_key(ctx, key, keysize));
}
/******************************************************************************
@@ -384,20 +412,24 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
*
******************************************************************************/
int aes_cipher(aes_context *ctx,
const uchar input[16],
uchar output[16])
const uchar input[16],
uchar output[16])
{
int i;
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; // general purpose locals
RK = ctx->rk;
GET_UINT32_LE(X0, input, 0); X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE(X1, input, 4); X1 ^= *RK++; // input buffer in a storage
GET_UINT32_LE(X2, input, 8); X2 ^= *RK++; // memory endian-neutral way
GET_UINT32_LE(X3, input, 12); X3 ^= *RK++;
GET_UINT32_LE(X0, input, 0);
X0 ^= *RK++; // load our 128-bit
GET_UINT32_LE(X1, input, 4);
X1 ^= *RK++; // input buffer in a storage
GET_UINT32_LE(X2, input, 8);
X2 ^= *RK++; // memory endian-neutral way
GET_UINT32_LE(X3, input, 12);
X3 ^= *RK++;
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
if (ctx->mode == DECRYPT)
{
@@ -409,29 +441,29 @@ int aes_cipher(aes_context *ctx,
AES_RROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \
((uint32_t)RSb[(Y0) & 0xFF]) ^
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
X0 = *RK++ ^
((uint32_t)RSb[(Y0) & 0xFF]) ^
((uint32_t)RSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y1 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \
((uint32_t)RSb[(Y1) & 0xFF]) ^
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
X1 = *RK++ ^
((uint32_t)RSb[(Y1) & 0xFF]) ^
((uint32_t)RSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y2 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \
((uint32_t)RSb[(Y2) & 0xFF]) ^
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
X2 = *RK++ ^
((uint32_t)RSb[(Y2) & 0xFF]) ^
((uint32_t)RSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y3 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \
((uint32_t)RSb[(Y3) & 0xFF]) ^
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
X3 = *RK++ ^
((uint32_t)RSb[(Y3) & 0xFF]) ^
((uint32_t)RSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)RSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)RSb[(Y0 >> 24) & 0xFF] << 24);
}
else /* ENCRYPT */
{
@@ -445,31 +477,31 @@ int aes_cipher(aes_context *ctx,
AES_FROUND(Y0, Y1, Y2, Y3, X0, X1, X2, X3);
X0 = *RK++ ^ \
((uint32_t)FSb[(Y0) & 0xFF]) ^
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
X0 = *RK++ ^
((uint32_t)FSb[(Y0) & 0xFF]) ^
((uint32_t)FSb[(Y1 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y2 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y3 >> 24) & 0xFF] << 24);
X1 = *RK++ ^ \
((uint32_t)FSb[(Y1) & 0xFF]) ^
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
X1 = *RK++ ^
((uint32_t)FSb[(Y1) & 0xFF]) ^
((uint32_t)FSb[(Y2 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y3 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y0 >> 24) & 0xFF] << 24);
X2 = *RK++ ^ \
((uint32_t)FSb[(Y2) & 0xFF]) ^
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
X2 = *RK++ ^
((uint32_t)FSb[(Y2) & 0xFF]) ^
((uint32_t)FSb[(Y3 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y0 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y1 >> 24) & 0xFF] << 24);
X3 = *RK++ ^ \
((uint32_t)FSb[(Y3) & 0xFF]) ^
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
X3 = *RK++ ^
((uint32_t)FSb[(Y3) & 0xFF]) ^
((uint32_t)FSb[(Y0 >> 8) & 0xFF] << 8) ^
((uint32_t)FSb[(Y1 >> 16) & 0xFF] << 16) ^
((uint32_t)FSb[(Y2 >> 24) & 0xFF] << 24);
#if AES_DECRYPTION // whether AES decryption is supported
#if AES_DECRYPTION // whether AES decryption is supported
}
#endif /* AES_DECRYPTION */
@@ -478,6 +510,6 @@ int aes_cipher(aes_context *ctx,
PUT_UINT32_LE(X2, output, 8);
PUT_UINT32_LE(X3, output, 12);
return(0);
return (0);
}
/* end of aes.c */

View File

@@ -1,35 +1,35 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of the AES Rijndael
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
* of this work was correctness & accuracy. It is written in 'C' without any
* particular focus upon optimization or speed. It should be endian (memory
* byte order) neutral since the few places that care are handled explicitly.
*
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#pragma once
/******************************************************************************/
#define AES_DECRYPTION 0 // whether AES decryption is supported
#define AES_DECRYPTION 0 // whether AES decryption is supported
/******************************************************************************/
#include <string.h>
#define AES_ENCRYPT 1 // specify whether we're encrypting
#define AES_DECRYPT 0 // or decrypting
#define AES_ENCRYPT 1 // specify whether we're encrypting
#define AES_DECRYPT 0 // or decrypting
#if defined(_MSC_VER)
#include <basetsd.h>
@@ -38,41 +38,39 @@ typedef UINT32 uint32_t;
#include <inttypes.h>
#endif
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned char uchar; // add some convienent shorter types
typedef unsigned int uint;
/******************************************************************************
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
******************************************************************************/
void aes_init_keygen_tables(void);
/******************************************************************************
* AES_CONTEXT : cipher context / holds inter-call data
******************************************************************************/
typedef struct {
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
typedef struct
{
int mode; // 1 for Encryption, 0 for Decryption
int rounds; // keysize-based rounds count
uint32_t *rk; // pointer to current round key
uint32_t buf[68]; // key expansion buffer
} aes_context;
/******************************************************************************
* AES_SETKEY : called to expand the key for encryption or decryption
******************************************************************************/
int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
int aes_setkey(aes_context *ctx, // pointer to context
int mode, // 1 or 0 for Encrypt/Decrypt
const uchar *key, // AES input key
uint keysize); // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
// returns 0 for success
/******************************************************************************
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
******************************************************************************/
int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success
int aes_cipher(aes_context *ctx, // pointer to context
const uchar input[16], // 128-bit block to en/decipher
uchar output[16]); // 128-bit output result block
// returns 0 for success

View File

@@ -1,26 +1,26 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#include "gcm.h"
#include "aes.h"
@@ -41,80 +41,79 @@
*
******************************************************************************/
/* Calculating the "GHASH"
*
* There are many ways of calculating the so-called GHASH in software, each with
* a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
* an intriguing construction which takes two 128-bit strings (also the cipher's
* block size and the fundamental operation size for the system) and hashes them
* into a third 128-bit result.
*
* Many implementation solutions have been worked out that use large precomputed
* table lookups in place of more time consuming bit fiddling, and this approach
* can be scaled easily upward or downward as needed to change the time/space
* tradeoff. It's been studied extensively and there's a solid body of theory and
* practice. For example, without using any lookup tables an implementation
* might obtain 119 cycles per byte throughput, whereas using a simple, though
* large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
* cycles per byte.
*
* And Intel's processors have, since 2010, included an instruction which does
* the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
*
* Since SQRL is interactive, and only processing a few 128-bit blocks, I've
* settled upon a relatively slower but appealing small-table compromise which
* folds a bunch of not only time consuming but also bit twiddling into a simple
* 16-entry table which is attributed to Victor Shoup's 1996 work while at
* Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
* Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
* See, also section 4.1 of the "gcm-revised-spec" cited above.
*/
/* Calculating the "GHASH"
*
* There are many ways of calculating the so-called GHASH in software, each with
* a traditional size vs performance tradeoff. The GHASH (Galois field hash) is
* an intriguing construction which takes two 128-bit strings (also the cipher's
* block size and the fundamental operation size for the system) and hashes them
* into a third 128-bit result.
*
* Many implementation solutions have been worked out that use large precomputed
* table lookups in place of more time consuming bit fiddling, and this approach
* can be scaled easily upward or downward as needed to change the time/space
* tradeoff. It's been studied extensively and there's a solid body of theory and
* practice. For example, without using any lookup tables an implementation
* might obtain 119 cycles per byte throughput, whereas using a simple, though
* large, key-specific 64 kbyte 8-bit lookup table the performance jumps to 13
* cycles per byte.
*
* And Intel's processors have, since 2010, included an instruction which does
* the entire 128x128->128 bit job in just several 64x64->128 bit pieces.
*
* Since SQRL is interactive, and only processing a few 128-bit blocks, I've
* settled upon a relatively slower but appealing small-table compromise which
* folds a bunch of not only time consuming but also bit twiddling into a simple
* 16-entry table which is attributed to Victor Shoup's 1996 work while at
* Bellcore: "On Fast and Provably Secure MessageAuthentication Based on
* Universal Hashing." See: http://www.shoup.net/papers/macs.pdf
* See, also section 4.1 of the "gcm-revised-spec" cited above.
*/
/*
* This 16-entry table of pre-computed constants is used by the
* GHASH multiplier to improve over a strictly table-free but
* significantly slower 128x128 bit multiple within GF(2^128).
*/
/*
* This 16-entry table of pre-computed constants is used by the
* GHASH multiplier to improve over a strictly table-free but
* significantly slower 128x128 bit multiple within GF(2^128).
*/
static const uint64_t last4[16] = {
0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0 };
0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0};
/*
* Platform Endianness Neutralizing Load and Store Macro definitions
* GCM wants platform-neutral Big Endian (BE) byte ordering
*/
#define GET_UINT32_BE(n,b,i) { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); }
#define GET_UINT32_BE(n, b, i) \
{ \
(n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); \
}
#define PUT_UINT32_BE(n,b,i) { \
(b)[(i) ] = (uchar) ( (n) >> 24 ); \
(b)[(i) + 1] = (uchar) ( (n) >> 16 ); \
(b)[(i) + 2] = (uchar) ( (n) >> 8 ); \
(b)[(i) + 3] = (uchar) ( (n) ); }
#define PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i)] = (uchar)((n) >> 24); \
(b)[(i) + 1] = (uchar)((n) >> 16); \
(b)[(i) + 2] = (uchar)((n) >> 8); \
(b)[(i) + 3] = (uchar)((n)); \
}
/******************************************************************************
*
* GCM_INITIALIZE
*
* Must be called once to initialize the GCM library.
*
* At present, this only calls the AES keygen table generator, which expands
* the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
* MUST be called during system initialization before a multi-threading
* environment is running.
*
******************************************************************************/
/******************************************************************************
*
* GCM_INITIALIZE
*
* Must be called once to initialize the GCM library.
*
* At present, this only calls the AES keygen table generator, which expands
* the AES keying tables for use. This is NOT A THREAD-SAFE function, so it
* MUST be called during system initialization before a multi-threading
* environment is running.
*
******************************************************************************/
int gcm_initialize(void)
{
aes_init_keygen_tables();
return(0);
return (0);
}
/******************************************************************************
*
* GCM_MULT
@@ -124,9 +123,9 @@ int gcm_initialize(void)
* 'x' and 'output' are seen as elements of GCM's GF(2^128) Galois field.
*
******************************************************************************/
static void gcm_mult(gcm_context *ctx, // pointer to established context
const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector
static void gcm_mult(gcm_context *ctx, // pointer to established context
const uchar x[16], // pointer to 128-bit input vector
uchar output[16]) // pointer to 128-bit output vector
{
int i;
uchar lo, hi, rem;
@@ -137,11 +136,13 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
zh = ctx->HH[lo];
zl = ctx->HL[lo];
for (i = 15; i >= 0; i--) {
for (i = 15; i >= 0; i--)
{
lo = (uchar)(x[i] & 0x0f);
hi = (uchar)(x[i] >> 4);
if (i != 15) {
if (i != 15)
{
rem = (uchar)(zl & 0x0f);
zl = (zh << 60) | (zl >> 4);
zh = (zh >> 4);
@@ -162,7 +163,6 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
PUT_UINT32_BE(zl, output, 12);
}
/******************************************************************************
*
* GCM_SETKEY
@@ -172,26 +172,26 @@ static void gcm_mult(gcm_context *ctx, // pointer to established context
*
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
const uchar *key, // pointer to the AES encryption key
const uint keysize) // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
{
int ret, i, j;
uint64_t hi, lo;
uint64_t vl, vh;
unsigned char h[16];
memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset(h, 0, 16); // initialize the block to encrypt
memset(ctx, 0, sizeof(gcm_context)); // zero caller-provided GCM context
memset(h, 0, 16); // initialize the block to encrypt
// encrypt the null 128-bit block to generate a key-based value
// which is then used to initialize our GHASH lookup tables
if ((ret = aes_setkey(&ctx->aes_ctx, AES_ENCRYPT, key, keysize)) != 0)
return(ret);
return (ret);
if ((ret = aes_cipher(&ctx->aes_ctx, h, h)) != 0)
return(ret);
return (ret);
GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian
GET_UINT32_BE(hi, h, 0); // pack h as two 64-bit ints, big-endian
GET_UINT32_BE(lo, h, 4);
vh = (uint64_t)hi << 32 | lo;
@@ -199,31 +199,33 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
GET_UINT32_BE(lo, h, 12);
vl = (uint64_t)hi << 32 | lo;
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HL[8] = vl; // 8 = 1000 corresponds to 1 in GF(2^128)
ctx->HH[8] = vh;
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
ctx->HH[0] = 0; // 0 corresponds to 0 in GF(2^128)
ctx->HL[0] = 0;
for (i = 4; i > 0; i >>= 1) {
for (i = 4; i > 0; i >>= 1)
{
uint32_t T = (uint32_t)(vl & 1) * 0xe1000000U;
vl = (vh << 63) | (vl >> 1);
vh = (vh >> 1) ^ ((uint64_t)T << 32);
ctx->HL[i] = vl;
ctx->HH[i] = vh;
}
for (i = 2; i < 16; i <<= 1) {
for (i = 2; i < 16; i <<= 1)
{
uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i;
vh = *HiH;
vl = *HiL;
for (j = 1; j < i; j++) {
for (j = 1; j < i; j++)
{
HiH[j] = vh ^ ctx->HH[j];
HiL[j] = vl ^ ctx->HL[j];
}
}
return(0);
return (0);
}
/******************************************************************************
*
* GCM processing occurs four phases: SETKEY, START, UPDATE and FINISH.
@@ -245,18 +247,18 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none)
size_t add_len) // length of additional AEAD data (bytes)
{
int ret; // our error return if the AES encrypt fails
int ret; // our error return if the AES encrypt fails
uchar work_buf[16]; // XOR source built from provided IV if len != 16
const uchar *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
const uchar *p; // general purpose array pointer
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
// since the context might be reused under the same key
// we zero the working buffers for this next new process
@@ -265,42 +267,48 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
ctx->len = 0;
ctx->add_len = 0;
ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
ctx->mode = mode; // set the GCM encryption/decryption mode
ctx->aes_ctx.mode = AES_ENCRYPT; // GCM *always* runs AES in ENCRYPTION mode
if (iv_len == 12) { // GCM natively uses a 12-byte, 96-bit IV
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
ctx->y[15] = 1; // start "counting" from 1 (not 0)
if (iv_len == 12)
{ // GCM natively uses a 12-byte, 96-bit IV
memcpy(ctx->y, iv, iv_len); // copy the IV to the top of the 'y' buff
ctx->y[15] = 1; // start "counting" from 1 (not 0)
}
else // if we don't have a 12-byte IV, we GHASH whatever we've been given
else // if we don't have a 12-byte IV, we GHASH whatever we've been given
{
memset(work_buf, 0x00, 16); // clear the working buffer
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
memset(work_buf, 0x00, 16); // clear the working buffer
PUT_UINT32_BE(iv_len * 8, work_buf, 12); // place the IV into buffer
p = iv;
while (iv_len > 0) {
while (iv_len > 0)
{
use_len = (iv_len < 16) ? iv_len : 16;
for (i = 0; i < use_len; i++) ctx->y[i] ^= p[i];
for (i = 0; i < use_len; i++)
ctx->y[i] ^= p[i];
gcm_mult(ctx, ctx->y, ctx->y);
iv_len -= use_len;
p += use_len;
}
for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i];
for (i = 0; i < 16; i++)
ctx->y[i] ^= work_buf[i];
gcm_mult(ctx, ctx->y, ctx->y);
}
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
return(ret);
return (ret);
ctx->add_len = add_len;
p = add;
while (add_len > 0) {
while (add_len > 0)
{
use_len = (add_len < 16) ? add_len : 16;
for (i = 0; i < use_len; i++) ctx->buf[i] ^= p[i];
for (i = 0; i < use_len; i++)
ctx->buf[i] ^= p[i];
gcm_mult(ctx, ctx->buf, ctx->buf);
add_len -= use_len;
p += use_len;
}
return(0);
return (0);
}
/******************************************************************************
@@ -314,48 +322,53 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output) // pointer to destination data
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output) // pointer to destination data
{
int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
int ret; // our error return if the AES encrypt fails
uchar ectr[16]; // counter-mode cipher output for XORing
size_t use_len; // byte count to process, up to 16 bytes
size_t i; // local loop iterator
ctx->len += length; // bump the GCM context's running length count
while (length > 0) {
while (length > 0)
{
// clamp the length to process at 16 bytes
use_len = (length < 16) ? length : 16;
// increment the context's 128-bit IV||Counter 'y' vector
for (i = 16; i > 12; i--) if (++ctx->y[i - 1] != 0) break;
for (i = 16; i > 12; i--)
if (++ctx->y[i - 1] != 0)
break;
// encrypt the context's 'y' vector under the established key
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ectr)) != 0)
return(ret);
return (ret);
// encrypt or decrypt the input to the output
if (ctx->mode == AES_ENCRYPT)
{
for (i = 0; i < use_len; i++) {
for (i = 0; i < use_len; i++)
{
// XOR the cipher's ouptut vector (ectr) with our input
output[i] = (uchar)(ectr[i] ^ input[i]);
// now we mix in our data into the authentication hash.
// if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input
// if we're ENcrypting we XOR in the post-XOR (output)
// results, but if we're DEcrypting we XOR in the input
// data
ctx->buf[i] ^= output[i];
}
}
else
{
for (i = 0; i < use_len; i++) {
// but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we
for (i = 0; i < use_len; i++)
{
// but if we're DEcrypting we XOR in the input data first,
// i.e. before saving to ouput data, otherwise if the input
// and output buffer are the same (inplace decryption) we
// would not get the correct auth tag
ctx->buf[i] ^= input[i];
@@ -364,13 +377,13 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
output[i] = (uchar)(ectr[i] ^ input[i]);
}
}
gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
gcm_mult(ctx, ctx->buf, ctx->buf); // perform a GHASH operation
length -= use_len; // drop the remaining byte count to process
length -= use_len; // drop the remaining byte count to process
input += use_len; // bump our input pointer forward
output += use_len; // bump our output pointer forward
output += use_len; // bump our output pointer forward
}
return(0);
return (0);
}
/******************************************************************************
@@ -381,18 +394,20 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // pointer to buffer which receives the tag
size_t tag_len) // length, in bytes, of the tag-receiving buf
{
uchar work_buf[16];
uint64_t orig_len = ctx->len * 8;
uint64_t orig_add_len = ctx->add_len * 8;
size_t i;
if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len);
if (tag_len != 0)
memcpy(tag, ctx->base_ectr, tag_len);
if (orig_len || orig_add_len) {
if (orig_len || orig_add_len)
{
memset(work_buf, 0x00, 16);
PUT_UINT32_BE((orig_add_len >> 32), work_buf, 0);
@@ -400,14 +415,15 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
PUT_UINT32_BE((orig_len >> 32), work_buf, 8);
PUT_UINT32_BE((orig_len), work_buf, 12);
for (i = 0; i < 16; i++) ctx->buf[i] ^= work_buf[i];
for (i = 0; i < 16; i++)
ctx->buf[i] ^= work_buf[i];
gcm_mult(ctx, ctx->buf, ctx->buf);
for (i = 0; i < tag_len; i++) tag[i] ^= ctx->buf[i];
for (i = 0; i < tag_len; i++)
tag[i] ^= ctx->buf[i];
}
return(0);
return (0);
}
/******************************************************************************
*
* GCM_CRYPT_AND_TAG
@@ -426,29 +442,28 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len) // byte length of the tag to be generated
{ /*
assuming that the caller has already invoked gcm_setkey to
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len);
return(0);
return (0);
}
/******************************************************************************
*
* GCM_AUTH_DECRYPT
@@ -462,37 +477,38 @@ int gcm_crypt_and_tag(
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len) // byte length of the tag <= 16
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len) // byte length of the tag <= 16
{
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
/*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag
*/
gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len,
input, output, length, check_tag, tag_len);
input, output, length, check_tag, tag_len);
// now we verify the authentication tag in 'constant time'
for (diff = 0, i = 0; i < tag_len; i++)
diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
if (diff != 0)
{ // see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return (GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
}
return(0);
return (0);
}
/******************************************************************************

View File

@@ -1,73 +1,70 @@
/******************************************************************************
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
*
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
*
* This is a simple and straightforward implementation of AES-GCM authenticated
* encryption. The focus of this work was correctness & accuracy. It is written
* in straight 'C' without any particular focus upon optimization or speed. It
* should be endian (memory byte order) neutral since the few places that care
* are handled explicitly.
*
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
*
* It is intended for general purpose use, but was written in support of GRC's
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
*
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
* gcm/gcm-revised-spec.pdf
*
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
*
*******************************************************************************/
#pragma once
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
#include "aes.h" // gcm_context includes aes_context
#include "aes.h" // gcm_context includes aes_context
#if defined(_MSC_VER)
#include <basetsd.h>
typedef unsigned int size_t;// use the right type for length declarations
typedef unsigned int size_t; // use the right type for length declarations
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
#else
#include <stdint.h>
#endif
/******************************************************************************
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
******************************************************************************/
typedef struct {
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
typedef struct
{
int mode; // cipher direction: encrypt/decrypt
uint64_t len; // cipher data length processed so far
uint64_t add_len; // total add data length
uint64_t HL[16]; // precalculated lo-half HTable
uint64_t HH[16]; // precalculated hi-half HTable
uchar base_ectr[16]; // first counter-mode cipher output for tag
uchar y[16]; // the current cipher-input IV|Counter value
uchar buf[16]; // buf working value
aes_context aes_ctx; // cipher context used
} gcm_context;
/******************************************************************************
* GCM_CONTEXT : MUST be called once before ANY use of this library
******************************************************************************/
int gcm_initialize(void);
/******************************************************************************
* GCM_SETKEY : sets the GCM (and AES) keying material for use
******************************************************************************/
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
const uchar *key, // pointer to cipher key
const uint keysize // size in bytes (must be 16, 24, 32 for
// 128, 192 or 256-bit keys respectively)
); // returns 0 for success
/******************************************************************************
*
@@ -87,18 +84,17 @@ int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
*
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
uchar *tag, // pointer to the tag to be generated
size_t tag_len); // byte length of the tag to be generated
/******************************************************************************
*
@@ -113,17 +109,16 @@ int gcm_crypt_and_tag(
*
******************************************************************************/
int gcm_auth_decrypt(
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16
gcm_context *ctx, // gcm context with key already setup
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
size_t add_len, // byte length of the additional AEAD data
const uchar *input, // pointer to the cipher data source
uchar *output, // pointer to the cipher data destination
size_t length, // byte length of the cipher data
const uchar *tag, // pointer to the tag to be authenticated
size_t tag_len); // byte length of the tag <= 16
/******************************************************************************
*
@@ -133,13 +128,12 @@ int gcm_auth_decrypt(
* mode, and preprocesses the initialization vector and additional AEAD data.
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // ENCRYPT (1) or DECRYPT (0)
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // pointer to additional AEAD data (NULL if none)
size_t add_len); // length of additional AEAD data (bytes)
/******************************************************************************
*
@@ -152,11 +146,10 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
* have a partial block length of < 128 bits.)
*
******************************************************************************/
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
size_t length, // length, in bytes, of data to process
const uchar *input, // pointer to source data
uchar *output); // pointer to destination data
/******************************************************************************
*
@@ -166,10 +159,9 @@ int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
* It performs the final GHASH to produce the resulting authentication TAG.
*
******************************************************************************/
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
size_t tag_len); // length, in bytes, of the tag-receiving buf
/******************************************************************************
*

View File

@@ -15,54 +15,54 @@
#include <string.h>
#include <stdlib.h>
/*
* hkdf
*
* Description:
* This function will generate keying material using HKDF.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* salt[ ]: [in]
* The optional salt value (a non-secret random value);
* if not provided (salt == NULL), it is set internally
* to a string of HashLen(whichSha) zeros.
* salt_len: [in]
* The length of the salt value. (Ignored if salt == NULL.)
* ikm[ ]: [in]
* Input keying material.
* ikm_len: [in]
* The length of the input keying material.
* info[ ]: [in]
* The optional context and application specific information.
* If info == NULL or a zero-length string, it is ignored.
* info_len: [in]
* The length of the optional context and application specific
* information. (Ignored if info == NULL.)
* okm[ ]: [out]
* Where the HKDF is to be stored.
* okm_len: [in]
* The length of the buffer to hold okm.
* okm_len must be <= 255 * USHABlockSize(whichSha)
*
* Notes:
* Calls hkdfExtract() and hkdfExpand().
*
* Returns:
* sha Error Code.
*
*/
/*
* hkdf
*
* Description:
* This function will generate keying material using HKDF.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* salt[ ]: [in]
* The optional salt value (a non-secret random value);
* if not provided (salt == NULL), it is set internally
* to a string of HashLen(whichSha) zeros.
* salt_len: [in]
* The length of the salt value. (Ignored if salt == NULL.)
* ikm[ ]: [in]
* Input keying material.
* ikm_len: [in]
* The length of the input keying material.
* info[ ]: [in]
* The optional context and application specific information.
* If info == NULL or a zero-length string, it is ignored.
* info_len: [in]
* The length of the optional context and application specific
* information. (Ignored if info == NULL.)
* okm[ ]: [out]
* Where the HKDF is to be stored.
* okm_len: [in]
* The length of the buffer to hold okm.
* okm_len must be <= 255 * USHABlockSize(whichSha)
*
* Notes:
* Calls hkdfExtract() and hkdfExpand().
*
* Returns:
* sha Error Code.
*
*/
int hkdf(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
uint8_t prk[USHAMaxHashSize];
return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
info_len, okm, okm_len);
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
info_len, okm, okm_len);
}
/*
@@ -93,17 +93,19 @@ int hkdf(SHAversion whichSha,
*
*/
int hkdfExtract(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
uint8_t prk[USHAMaxHashSize])
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
uint8_t prk[USHAMaxHashSize])
{
unsigned char nullSalt[USHAMaxHashSize];
if (salt == 0) {
if (salt == 0)
{
salt = nullSalt;
salt_len = USHAHashSize(whichSha);
memset(nullSalt, '\0', salt_len);
}
else if (salt_len < 0) {
else if (salt_len < 0)
{
return shaBadParam;
}
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
@@ -143,42 +145,51 @@ int hkdfExtract(SHAversion whichSha,
*
*/
int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
size_t hash_len, N;
unsigned char T[USHAMaxHashSize];
size_t Tlen, where, i;
if (info == 0) {
if (info == 0)
{
info = (const unsigned char *)"";
info_len = 0;
}
else if (info_len < 0) {
else if (info_len < 0)
{
return shaBadParam;
}
if (okm_len <= 0) return shaBadParam;
if (!okm) return shaBadParam;
if (okm_len <= 0)
return shaBadParam;
if (!okm)
return shaBadParam;
hash_len = USHAHashSize(whichSha);
if (prk_len < hash_len) return shaBadParam;
if (prk_len < hash_len)
return shaBadParam;
N = okm_len / hash_len;
if ((okm_len % hash_len) != 0) N++;
if (N > 255) return shaBadParam;
if ((okm_len % hash_len) != 0)
N++;
if (N > 255)
return shaBadParam;
Tlen = 0;
where = 0;
for (i = 1; i <= N; i++) {
for (i = 1; i <= N; i++)
{
HMACContext context;
unsigned char c = i;
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
hmacInput(&context, T, Tlen) ||
hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) ||
hmacResult(&context, T);
if (ret != shaSuccess) return ret;
hmacInput(&context, T, Tlen) ||
hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) ||
hmacResult(&context, T);
if (ret != shaSuccess)
return ret;
memcpy(okm + where, T,
(i != N) ? hash_len : (okm_len - where));
(i != N) ? hash_len : (okm_len - where));
where += hash_len;
Tlen = hash_len;
}
@@ -210,14 +221,16 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
*
*/
int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, size_t salt_len)
const unsigned char *salt, size_t salt_len)
{
unsigned char nullSalt[USHAMaxHashSize];
if (!context) return shaNull;
if (!context)
return shaNull;
context->whichSha = whichSha;
context->hashSize = USHAHashSize(whichSha);
if (salt == 0) {
if (salt == 0)
{
salt = nullSalt;
salt_len = context->hashSize;
memset(nullSalt, '\0', salt_len);
@@ -247,11 +260,14 @@ int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
*
*/
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len)
size_t ikm_len)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacInput(&context->hmacContext, ikm, ikm_len);
}
@@ -276,11 +292,14 @@ int hkdfInput(HKDFContext *context, const unsigned char *ikm,
* sha Error Code.
*/
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count)
unsigned int ikm_bit_count)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count);
}
@@ -315,23 +334,27 @@ int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
*
*/
int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len)
{
uint8_t prkbuf[USHAMaxHashSize];
int ret;
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!okm) return context->Corrupted = shaBadParam;
if (!prk) prk = prkbuf;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
if (!okm)
return context->Corrupted = shaBadParam;
if (!prk)
prk = prkbuf;
ret = hmacResult(&context->hmacContext, prk) ||
hkdfExpand(context->whichSha, prk, context->hashSize, info,
info_len, okm, okm_len);
hkdfExpand(context->whichSha, prk, context->hashSize, info,
info_len, okm, okm_len);
context->Computed = 1;
return context->Corrupted = ret;
}

View File

@@ -14,44 +14,44 @@
#include "sha.h"
#include <stddef.h>
/*
* hmac
*
* Description:
* This function will compute an HMAC message digest.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* message_array[ ]: [in]
* An array of octets representing the message.
* Note: in RFC 2104, this parameter is known
* as 'text'.
* length: [in]
* The length of the message in message_array.
* key[ ]: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
* digest[ ]: [out]
* Where the digest is to be returned.
* NOTE: The length of the digest is determined by
* the value of whichSha.
*
* Returns:
* sha Error Code.
*
*/
/*
* hmac
*
* Description:
* This function will compute an HMAC message digest.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* message_array[ ]: [in]
* An array of octets representing the message.
* Note: in RFC 2104, this parameter is known
* as 'text'.
* length: [in]
* The length of the message in message_array.
* key[ ]: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
* digest[ ]: [out]
* Where the digest is to be returned.
* NOTE: The length of the digest is determined by
* the value of whichSha.
*
* Returns:
* sha Error Code.
*
*/
int hmac(SHAversion whichSha,
const unsigned char *message_array, size_t length,
const unsigned char *key, size_t key_len,
uint8_t digest[USHAMaxHashSize])
const unsigned char *message_array, size_t length,
const unsigned char *key, size_t key_len,
uint8_t digest[USHAMaxHashSize])
{
HMACContext context;
return hmacReset(&context, whichSha, key, key_len) ||
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
}
/*
@@ -76,7 +76,7 @@ int hmac(SHAversion whichSha,
*
*/
int hmacReset(HMACContext *context, enum SHAversion whichSha,
const unsigned char *key, size_t key_len)
const unsigned char *key, size_t key_len)
{
size_t i, blocksize, hashsize;
int ret;
@@ -87,7 +87,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* temporary buffer when keylen > blocksize */
unsigned char tempkey[USHAMaxHashSize];
if (!context) return shaNull;
if (!context)
return shaNull;
context->Computed = 0;
context->Corrupted = shaSuccess;
@@ -99,12 +100,14 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
* If key is longer than the hash blocksize,
* reset it to key = HASH(key).
*/
if (key_len > blocksize) {
if (key_len > blocksize)
{
USHAContext tcontext;
int err = USHAReset(&tcontext, whichSha) ||
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess) return err;
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess)
return err;
key = tempkey;
key_len = hashsize;
@@ -121,13 +124,15 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
* and text is the data being protected.
*/
/* store key into the pads, XOR'd with ipad and opad values */
for (i = 0; i < key_len; i++) {
/* store key into the pads, XOR'd with ipad and opad values */
for (i = 0; i < key_len; i++)
{
k_ipad[i] = key[i] ^ 0x36;
context->k_opad[i] = key[i] ^ 0x5c;
}
/* remaining pad bytes are '\0' XOR'd with ipad and opad values */
for (; i < blocksize; i++) {
for (; i < blocksize; i++)
{
k_ipad[i] = 0x36;
context->k_opad[i] = 0x5c;
}
@@ -135,8 +140,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* perform inner hash */
/* init context for 1st pass */
ret = USHAReset(&context->shaContext, whichSha) ||
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
return context->Corrupted = ret;
}
@@ -161,14 +166,17 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
*
*/
int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len)
size_t text_len)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then text of datagram */
return context->Corrupted =
USHAInput(&context->shaContext, text, text_len);
USHAInput(&context->shaContext, text, text_len);
}
/*
@@ -191,14 +199,17 @@ int hmacInput(HMACContext *context, const unsigned char *text,
* sha Error Code.
*/
int hmacFinalBits(HMACContext *context,
uint8_t bits, unsigned int bit_count)
uint8_t bits, unsigned int bit_count)
{
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* then final bits of datagram */
return context->Corrupted =
USHAFinalBits(&context->shaContext, bits, bit_count);
USHAFinalBits(&context->shaContext, bits, bit_count);
}
/*
@@ -223,9 +234,12 @@ int hmacFinalBits(HMACContext *context,
int hmacResult(HMACContext *context, uint8_t *digest)
{
int ret;
if (!context) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (!context)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
/* finish up 1st pass */
/* (Use digest here as a temporary buffer.) */
@@ -238,7 +252,7 @@ int hmacResult(HMACContext *context, uint8_t *digest)
/* start with outer pad */
USHAInput(&context->shaContext, context->k_opad,
context->blockSize) ||
context->blockSize) ||
/* then results of 1st hash */
USHAInput(&context->shaContext, digest, context->hashSize) ||

View File

@@ -10,16 +10,16 @@
*/
#ifndef USE_MODIFIED_MACROS
#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define SHA_Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
#define SHA_Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#else /* USE_MODIFIED_MACROS */
/*
* The following definitions are equivalent and potentially faster.
*/
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z))
#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
#endif /* USE_MODIFIED_MACROS */
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))
#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z))

View File

@@ -85,12 +85,13 @@
/*
* All SHA functions return one of these values.
*/
enum {
enum
{
shaSuccess = 0,
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after FinalBits or Result */
shaBadParam /* passed a bad parameter */
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError, /* called Input after FinalBits or Result */
shaBadParam /* passed a bad parameter */
};
#endif /* _SHA_enum_ */
@@ -98,41 +99,50 @@ enum {
* These constants hold size information for each of the SHA
* hashing operations
*/
enum {
SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64,
enum
{
SHA1_Message_Block_Size = 64,
SHA224_Message_Block_Size = 64,
SHA256_Message_Block_Size = 64,
USHA_Max_Message_Block_Size = SHA256_Message_Block_Size,
SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32,
SHA1HashSize = 20,
SHA224HashSize = 28,
SHA256HashSize = 32,
USHAMaxHashSize = SHA256HashSize,
SHA1HashSizeBits = 160, SHA224HashSizeBits = 224,
SHA256HashSizeBits = 256, USHAMaxHashSizeBits = SHA256HashSizeBits
SHA1HashSizeBits = 160,
SHA224HashSizeBits = 224,
SHA256HashSizeBits = 256,
USHAMaxHashSizeBits = SHA256HashSizeBits
};
/*
* These constants are used in the USHA (Unified SHA) functions.
*/
typedef enum SHAversion {
SHA224, SHA256
typedef enum SHAversion
{
SHA224,
SHA256
} SHAversion;
/*
* This structure will hold context information for the SHA-256
* hashing operation.
*/
typedef struct SHA256Context {
uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */
typedef struct SHA256Context
{
uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */
uint32_t Length_High; /* Message length in bits */
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
uint32_t Length_Low; /* Message length in bits */
int_least16_t Message_Block_Index; /* Message_Block array index */
/* 512-bit message blocks */
int_least16_t Message_Block_Index; /* Message_Block array index */
/* 512-bit message blocks */
uint8_t Message_Block[SHA256_Message_Block_Size];
int Computed; /* Is the hash computed? */
int Corrupted; /* Cumulative corruption code */
int Computed; /* Is the hash computed? */
int Corrupted; /* Cumulative corruption code */
} SHA256Context;
/*
@@ -145,10 +155,13 @@ typedef struct SHA256Context SHA224Context;
* This structure holds context information for all SHA
* hashing operations.
*/
typedef struct USHAContext {
int whichSha; /* which SHA is being used */
union {
SHA224Context sha224Context; SHA256Context sha256Context;
typedef struct USHAContext
{
int whichSha; /* which SHA is being used */
union
{
SHA224Context sha224Context;
SHA256Context sha256Context;
} ctx;
} USHAContext;
@@ -157,15 +170,16 @@ typedef struct USHAContext {
* This structure will hold context information for the HMAC
* keyed-hashing operation.
*/
typedef struct HMACContext {
int whichSha; /* which SHA is being used */
int hashSize; /* hash size of SHA being used */
int blockSize; /* block size of SHA being used */
USHAContext shaContext; /* SHA context */
typedef struct HMACContext
{
int whichSha; /* which SHA is being used */
int hashSize; /* hash size of SHA being used */
int blockSize; /* block size of SHA being used */
USHAContext shaContext; /* SHA context */
unsigned char k_opad[USHA_Max_Message_Block_Size];
/* outer padding - key XORd with opad */
int Computed; /* Is the MAC computed? */
int Corrupted; /* Cumulative corruption code */
/* outer padding - key XORd with opad */
int Computed; /* Is the MAC computed? */
int Corrupted; /* Cumulative corruption code */
} HMACContext;
@@ -173,47 +187,47 @@ typedef struct HMACContext {
* This structure will hold context information for the HKDF
* extract-and-expand Key Derivation Functions.
*/
typedef struct HKDFContext {
int whichSha; /* which SHA is being used */
typedef struct HKDFContext
{
int whichSha; /* which SHA is being used */
HMACContext hmacContext;
int hashSize; /* hash size of SHA being used */
int hashSize; /* hash size of SHA being used */
unsigned char prk[USHAMaxHashSize];
/* pseudo-random key - output of hkdfInput */
int Computed; /* Is the key material computed? */
int Corrupted; /* Cumulative corruption code */
/* pseudo-random key - output of hkdfInput */
int Computed; /* Is the key material computed? */
int Corrupted; /* Cumulative corruption code */
} HKDFContext;
/*
* Function Prototypes
*/
/* SHA-224 */
int SHA224Reset(SHA224Context *);
int SHA224Input(SHA224Context *, const uint8_t *bytes,
unsigned int bytecount);
unsigned int bytecount);
int SHA224FinalBits(SHA224Context *, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int SHA224Result(SHA224Context *,
uint8_t Message_Digest[SHA224HashSize]);
uint8_t Message_Digest[SHA224HashSize]);
/* SHA-256 */
int SHA256Reset(SHA256Context *);
int SHA256Input(SHA256Context *, const uint8_t *bytes,
unsigned int bytecount);
unsigned int bytecount);
int SHA256FinalBits(SHA256Context *, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int SHA256Result(SHA256Context *,
uint8_t Message_Digest[SHA256HashSize]);
uint8_t Message_Digest[SHA256HashSize]);
/* Unified SHA functions, chosen by whichSha */
int USHAReset(USHAContext *context, SHAversion whichSha);
int USHAInput(USHAContext *context,
const uint8_t *bytes, unsigned int bytecount);
const uint8_t *bytes, unsigned int bytecount);
int USHAFinalBits(USHAContext *context,
uint8_t bits, unsigned int bit_count);
uint8_t bits, unsigned int bit_count);
int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize]);
uint8_t Message_Digest[USHAMaxHashSize]);
int USHABlockSize(enum SHAversion whichSha);
int USHAHashSize(enum SHAversion whichSha);
@@ -222,12 +236,12 @@ int USHAHashSize(enum SHAversion whichSha);
* for all SHAs.
* This interface allows a fixed-length text input to be used.
*/
int hmac(SHAversion whichSha, /* which SHA algorithm to use */
const unsigned char *text, /* pointer to data stream */
size_t text_len, /* length of data stream */
const unsigned char *key, /* pointer to authentication key */
size_t key_len, /* length of authentication key */
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
int hmac(SHAversion whichSha, /* which SHA algorithm to use */
const unsigned char *text, /* pointer to data stream */
size_t text_len, /* length of data stream */
const unsigned char *key, /* pointer to authentication key */
size_t key_len, /* length of authentication key */
uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */
/*
* HMAC Keyed-Hashing for Message Authentication, RFC 2104,
@@ -235,31 +249,30 @@ int hmac(SHAversion whichSha, /* which SHA algorithm to use */
* This interface allows any length of text input to be used.
*/
int hmacReset(HMACContext *context, enum SHAversion whichSha,
const unsigned char *key, size_t key_len);
const unsigned char *key, size_t key_len);
int hmacInput(HMACContext *context, const unsigned char *text,
size_t text_len);
size_t text_len);
int hmacFinalBits(HMACContext *context, uint8_t bits,
unsigned int bit_count);
unsigned int bit_count);
int hmacResult(HMACContext *context,
uint8_t digest[USHAMaxHashSize]);
uint8_t digest[USHAMaxHashSize]);
/*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
* RFC 5869, for all SHAs.
*/
int hkdf(SHAversion whichSha,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[ ], size_t okm_len);
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
uint8_t okm[], size_t okm_len);
int hkdfExtract(SHAversion whichSha, const unsigned char *salt,
size_t salt_len, const unsigned char *ikm,
size_t ikm_len, uint8_t prk[USHAMaxHashSize]);
int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
size_t prk_len, const unsigned char *info,
size_t info_len, uint8_t okm[ ], size_t okm_len);
size_t salt_len, const unsigned char *ikm,
size_t ikm_len, uint8_t prk[USHAMaxHashSize]);
int hkdfExpand(SHAversion whichSha, const uint8_t prk[],
size_t prk_len, const unsigned char *info,
size_t info_len, uint8_t okm[], size_t okm_len);
/*
* HKDF HMAC-based Extract-and-Expand Key Derivation Function,
@@ -267,12 +280,12 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ],
* This interface allows any length of text input to be used.
*/
int hkdfReset(HKDFContext *context, enum SHAversion whichSha,
const unsigned char *salt, size_t salt_len);
const unsigned char *salt, size_t salt_len);
int hkdfInput(HKDFContext *context, const unsigned char *ikm,
size_t ikm_len);
size_t ikm_len);
int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits,
unsigned int ikm_bit_count);
unsigned int ikm_bit_count);
int hkdfResult(HKDFContext *context,
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[USHAMaxHashSize], size_t okm_len);
uint8_t prk[USHAMaxHashSize],
const unsigned char *info, size_t info_len,
uint8_t okm[USHAMaxHashSize], size_t okm_len);

View File

@@ -44,54 +44,53 @@
#include "sha-private.h"
/* Define the SHA shift, rotate left, and rotate right macros */
#define SHA256_SHR(bits,word) ((word) >> (bits))
#define SHA256_ROTL(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
#define SHA256_ROTR(bits,word) \
(((word) >> (bits)) | ((word) << (32-(bits))))
#define SHA256_SHR(bits, word) ((word) >> (bits))
#define SHA256_ROTL(bits, word) \
(((word) << (bits)) | ((word) >> (32 - (bits))))
#define SHA256_ROTR(bits, word) \
(((word) >> (bits)) | ((word) << (32 - (bits))))
/* Define the SHA SIGMA and sigma macros */
#define SHA256_SIGMA0(word) \
(SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word))
#define SHA256_SIGMA1(word) \
(SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word))
#define SHA256_sigma0(word) \
(SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word))
#define SHA256_sigma1(word) \
(SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word))
#define SHA256_SIGMA0(word) \
(SHA256_ROTR(2, word) ^ SHA256_ROTR(13, word) ^ SHA256_ROTR(22, word))
#define SHA256_SIGMA1(word) \
(SHA256_ROTR(6, word) ^ SHA256_ROTR(11, word) ^ SHA256_ROTR(25, word))
#define SHA256_sigma0(word) \
(SHA256_ROTR(7, word) ^ SHA256_ROTR(18, word) ^ SHA256_SHR(3, word))
#define SHA256_sigma1(word) \
(SHA256_ROTR(17, word) ^ SHA256_ROTR(19, word) ^ SHA256_SHR(10, word))
/*
* Add "length" to the length.
* Set Corrupted when overflow has occurred.
*/
static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) ? shaInputTooLong : \
(context)->Corrupted )
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) \
? shaInputTooLong \
: (context)->Corrupted)
/* Local Function Prototypes */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
static void SHA224_256ProcessMessageBlock(SHA256Context *context);
static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte);
uint8_t Pad_Byte);
static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte);
uint8_t Pad_Byte);
static int SHA224_256ResultN(SHA256Context *context,
uint8_t Message_Digest[ ], int HashSize);
uint8_t Message_Digest[], int HashSize);
/* Initial Hash Values: FIPS 180-3 section 5.3.2 */
static uint32_t SHA224_H0[SHA256HashSize/4] = {
static uint32_t SHA224_H0[SHA256HashSize / 4] = {
0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
};
0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4};
/* Initial Hash Values: FIPS 180-3 section 5.3.3 */
static uint32_t SHA256_H0[SHA256HashSize/4] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};
static uint32_t SHA256_H0[SHA256HashSize / 4] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19};
/*
* SHA224Reset
@@ -133,7 +132,7 @@ int SHA224Reset(SHA224Context *context)
*
*/
int SHA224Input(SHA224Context *context, const uint8_t *message_array,
unsigned int length)
unsigned int length)
{
return SHA256Input(context, message_array, length);
}
@@ -183,7 +182,7 @@ int SHA224FinalBits(SHA224Context *context,
* sha Error Code.
*/
int SHA224Result(SHA224Context *context,
uint8_t Message_Digest[SHA224HashSize])
uint8_t Message_Digest[SHA224HashSize])
{
return SHA224_256ResultN(context, Message_Digest, SHA224HashSize);
}
@@ -227,27 +226,32 @@ int SHA256Reset(SHA256Context *context)
* sha Error Code.
*/
int SHA256Input(SHA256Context *context, const uint8_t *message_array,
unsigned int length)
unsigned int length)
{
if (!context) return shaNull;
if (!length) return shaSuccess;
if (!message_array) return shaNull;
if (context->Computed) return context->Corrupted = shaStateError;
if (context->Corrupted) return context->Corrupted;
if (!context)
return shaNull;
if (!length)
return shaSuccess;
if (!message_array)
return shaNull;
if (context->Computed)
return context->Corrupted = shaStateError;
if (context->Corrupted)
return context->Corrupted;
while (length--) {
while (length--)
{
context->Message_Block[context->Message_Block_Index++] =
*message_array;
*message_array;
if ((SHA224_256AddLength(context, 8) == shaSuccess) &&
(context->Message_Block_Index == SHA256_Message_Block_Size))
(context->Message_Block_Index == SHA256_Message_Block_Size))
SHA224_256ProcessMessageBlock(context);
message_array++;
}
return context->Corrupted;
}
/*
@@ -276,24 +280,26 @@ int SHA256FinalBits(SHA256Context *context,
/* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80,
/* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0,
/* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8,
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE
};
/* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE};
static uint8_t markbit[8] = {
/* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40,
/* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10,
/* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04,
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01
};
/* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01};
if (!context) return shaNull;
if (!length) return shaSuccess;
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
if (length >= 8) return context->Corrupted = shaBadParam;
if (!context)
return shaNull;
if (!length)
return shaSuccess;
if (context->Corrupted)
return context->Corrupted;
if (context->Computed)
return context->Corrupted = shaStateError;
if (length >= 8)
return context->Corrupted = shaBadParam;
SHA224_256AddLength(context, length);
SHA224_256Finalize(context, (uint8_t)
((message_bits & masks[length]) | markbit[length]));
SHA224_256Finalize(context, (uint8_t)((message_bits & masks[length]) | markbit[length]));
return context->Corrupted;
}
@@ -341,10 +347,11 @@ int SHA256Result(SHA256Context *context,
*/
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
{
if (!context) return shaNull;
if (!context)
return shaNull;
context->Length_High = context->Length_Low = 0;
context->Message_Block_Index = 0;
context->Message_Block_Index = 0;
context->Intermediate_Hash[0] = H0[0];
context->Intermediate_Hash[1] = H0[1];
@@ -355,7 +362,7 @@ static int SHA224_256Reset(SHA256Context *context, uint32_t *H0)
context->Intermediate_Hash[6] = H0[6];
context->Intermediate_Hash[7] = H0[7];
context->Computed = 0;
context->Computed = 0;
context->Corrupted = shaSuccess;
return shaSuccess;
@@ -396,12 +403,11 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08,
0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f,
0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
int t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[64]; /* Word sequence */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
int t, t4; /* Loop counter */
uint32_t temp1, temp2; /* Temporary word value */
uint32_t W[64]; /* Word sequence */
uint32_t A, B, C, D, E, F, G, H; /* Word buffers */
/*
* Initialize the first 16 words in the array W
@@ -412,8 +418,8 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
(((uint32_t)context->Message_Block[t4 + 2]) << 8) |
(((uint32_t)context->Message_Block[t4 + 3]));
for (t = 16; t < 64; t++)
W[t] = SHA256_sigma1(W[t-2]) + W[t-7] +
SHA256_sigma0(W[t-15]) + W[t-16];
W[t] = SHA256_sigma1(W[t - 2]) + W[t - 7] +
SHA256_sigma0(W[t - 15]) + W[t - 16];
A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1];
@@ -424,9 +430,10 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
G = context->Intermediate_Hash[6];
H = context->Intermediate_Hash[7];
for (t = 0; t < 64; t++) {
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t];
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C);
for (t = 0; t < 64; t++)
{
temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E, F, G) + K[t] + W[t];
temp2 = SHA256_SIGMA0(A) + SHA_Maj(A, B, C);
H = G;
G = F;
F = E;
@@ -468,14 +475,14 @@ static void SHA224_256ProcessMessageBlock(SHA256Context *context)
* sha Error Code.
*/
static void SHA224_256Finalize(SHA256Context *context,
uint8_t Pad_Byte)
uint8_t Pad_Byte)
{
int i;
SHA224_256PadMessage(context, Pad_Byte);
/* message may be sensitive, so clear it out */
for (i = 0; i < SHA256_Message_Block_Size; ++i)
context->Message_Block[i] = 0;
context->Length_High = 0; /* and clear length */
context->Length_High = 0; /* and clear length */
context->Length_Low = 0;
context->Computed = 1;
}
@@ -505,7 +512,7 @@ static void SHA224_256Finalize(SHA256Context *context,
* Nothing.
*/
static void SHA224_256PadMessage(SHA256Context *context,
uint8_t Pad_Byte)
uint8_t Pad_Byte)
{
/*
* Check to see if the current message block is too small to hold
@@ -513,15 +520,17 @@ static void SHA224_256PadMessage(SHA256Context *context,
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) {
if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8))
{
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
while (context->Message_Block_Index < SHA256_Message_Block_Size)
context->Message_Block[context->Message_Block_Index++] = 0;
SHA224_256ProcessMessageBlock(context);
} else
}
else
context->Message_Block[context->Message_Block_Index++] = Pad_Byte;
while (context->Message_Block_Index < (SHA256_Message_Block_Size-8))
while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8))
context->Message_Block[context->Message_Block_Index++] = 0;
/*
@@ -561,21 +570,22 @@ static void SHA224_256PadMessage(SHA256Context *context,
* sha Error Code.
*/
static int SHA224_256ResultN(SHA256Context *context,
uint8_t Message_Digest[ ], int HashSize)
uint8_t Message_Digest[], int HashSize)
{
int i;
if (!context) return shaNull;
if (!Message_Digest) return shaNull;
if (context->Corrupted) return context->Corrupted;
if (!context)
return shaNull;
if (!Message_Digest)
return shaNull;
if (context->Corrupted)
return context->Corrupted;
if (!context->Computed)
SHA224_256Finalize(context, 0x80);
for (i = 0; i < HashSize; ++i)
Message_Digest[i] = (uint8_t)
(context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
Message_Digest[i] = (uint8_t)(context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03)));
return shaSuccess;
}

View File

@@ -30,12 +30,17 @@
*/
int USHAReset(USHAContext *context, enum SHAversion whichSha)
{
if (!context) return shaNull;
if (!context)
return shaNull;
context->whichSha = whichSha;
switch (whichSha) {
case SHA224: return SHA224Reset((SHA224Context*)&context->ctx);
case SHA256: return SHA256Reset((SHA256Context*)&context->ctx);
default: return shaBadParam;
switch (whichSha)
{
case SHA224:
return SHA224Reset((SHA224Context *)&context->ctx);
case SHA256:
return SHA256Reset((SHA256Context *)&context->ctx);
default:
return shaBadParam;
}
}
@@ -62,15 +67,18 @@ int USHAReset(USHAContext *context, enum SHAversion whichSha)
int USHAInput(USHAContext *context,
const uint8_t *bytes, unsigned int bytecount)
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224Input((SHA224Context*)&context->ctx, bytes,
bytecount);
case SHA256:
return SHA256Input((SHA256Context*)&context->ctx, bytes,
bytecount);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224Input((SHA224Context *)&context->ctx, bytes,
bytecount);
case SHA256:
return SHA256Input((SHA256Context *)&context->ctx, bytes,
bytecount);
default:
return shaBadParam;
}
}
@@ -96,15 +104,18 @@ int USHAInput(USHAContext *context,
int USHAFinalBits(USHAContext *context,
uint8_t bits, unsigned int bit_count)
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224FinalBits((SHA224Context*)&context->ctx, bits,
bit_count);
case SHA256:
return SHA256FinalBits((SHA256Context*)&context->ctx, bits,
bit_count);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224FinalBits((SHA224Context *)&context->ctx, bits,
bit_count);
case SHA256:
return SHA256FinalBits((SHA256Context *)&context->ctx, bits,
bit_count);
default:
return shaBadParam;
}
}
@@ -130,15 +141,18 @@ int USHAFinalBits(USHAContext *context,
int USHAResult(USHAContext *context,
uint8_t Message_Digest[USHAMaxHashSize])
{
if (!context) return shaNull;
switch (context->whichSha) {
case SHA224:
return SHA224Result((SHA224Context*)&context->ctx,
Message_Digest);
case SHA256:
return SHA256Result((SHA256Context*)&context->ctx,
Message_Digest);
default: return shaBadParam;
if (!context)
return shaNull;
switch (context->whichSha)
{
case SHA224:
return SHA224Result((SHA224Context *)&context->ctx,
Message_Digest);
case SHA256:
return SHA256Result((SHA256Context *)&context->ctx,
Message_Digest);
default:
return shaBadParam;
}
}
@@ -159,10 +173,13 @@ int USHAResult(USHAContext *context,
*/
int USHABlockSize(enum SHAversion whichSha)
{
switch (whichSha) {
case SHA224: return SHA224_Message_Block_Size;
default:
case SHA256: return SHA256_Message_Block_Size;
switch (whichSha)
{
case SHA224:
return SHA224_Message_Block_Size;
default:
case SHA256:
return SHA256_Message_Block_Size;
}
}
@@ -183,9 +200,12 @@ int USHABlockSize(enum SHAversion whichSha)
*/
int USHAHashSize(enum SHAversion whichSha)
{
switch (whichSha) {
case SHA224: return SHA224HashSize;
default:
case SHA256: return SHA256HashSize;
switch (whichSha)
{
case SHA224:
return SHA224HashSize;
default:
case SHA256:
return SHA256HashSize;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
#include <netinet/udp.h>
#ifndef IPV6_FREEBIND
#define IPV6_FREEBIND 78
#define IPV6_FREEBIND 78
#endif
#ifdef __CYGWIN__
@@ -30,7 +30,7 @@
#endif
#ifndef AF_DIVERT
#define AF_DIVERT 44 /* divert(4) */
#define AF_DIVERT 44 /* divert(4) */
#endif
#ifndef PF_DIVERT
#define PF_DIVERT AF_DIVERT
@@ -40,24 +40,24 @@
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define FOOL_NONE 0x00
#define FOOL_MD5SIG 0x01
#define FOOL_BADSUM 0x02
#define FOOL_TS 0x04
#define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40
#define FOOL_IPFRAG1 0x80
#define FOOL_DATANOACK 0x100
#define FOOL_NONE 0x00
#define FOOL_MD5SIG 0x01
#define FOOL_BADSUM 0x02
#define FOOL_TS 0x04
#define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40
#define FOOL_IPFRAG1 0x80
#define FOOL_DATANOACK 0x100
#define SCALE_NONE ((uint8_t)-1)
#define SCALE_NONE ((uint8_t) - 1)
#define VERDICT_PASS 0
#define VERDICT_MODIFY 1
#define VERDICT_DROP 2
#define VERDICT_MASK 3
#define VERDICT_NOCSUM 4
#define VERDICT_PASS 0
#define VERDICT_MODIFY 1
#define VERDICT_DROP 2
#define VERDICT_MASK 3
#define VERDICT_NOCSUM 4
// seq and wsize have network byte order
bool prepare_tcp_segment4(
@@ -100,7 +100,6 @@ bool prepare_tcp_segment(
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_udp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t ttl,
@@ -144,11 +143,11 @@ bool ip_frag(
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size);
void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
void extract_endpoints(const struct ip *ip, const struct ip6_hdr *ip6hdr, const struct tcphdr *tcphdr, const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
@@ -170,7 +169,7 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6);
#endif
// auto creates internal socket and uses it for subsequent calls
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len);
bool rawsend(const struct sockaddr *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len);
bool rawsend_rp(const struct rawpacket *rp);
// return trues if all packets were send successfully
bool rawsend_queue(struct rawpacket_tailhead *q);
@@ -189,7 +188,7 @@ void print_tcphdr(const struct tcphdr *tcphdr);
void print_udphdr(const struct udphdr *udphdr);
void str_ip(char *s, size_t s_len, const struct ip *ip);
void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto);
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr);
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr, const void *daddr);
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr);
void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr);
@@ -225,7 +224,12 @@ typedef struct
#define AUTOTTL_DEFAULT_MIN 3
#define AUTOTTL_DEFAULT_MAX 20
#define AUTOTTL_ENABLED(a) (!!(a).delta)
#define AUTOTTL_SET_DEFAULT(a) {(a).delta=AUTOTTL_DEFAULT_DELTA; (a).min=AUTOTTL_DEFAULT_MIN; (a).max=AUTOTTL_DEFAULT_MAX;}
#define AUTOTTL_SET_DEFAULT(a) \
{ \
(a).delta = AUTOTTL_DEFAULT_DELTA; \
(a).min = AUTOTTL_DEFAULT_MIN; \
(a).max = AUTOTTL_DEFAULT_MAX; \
}
uint8_t autottl_guess(uint8_t ttl, const autottl *attl);
void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *tcphdr, struct udphdr *udphdr, const struct sockaddr_in *target4, const struct sockaddr_in6 *target6);

File diff suppressed because it is too large Load Diff

View File

@@ -19,8 +19,9 @@
#define DPI_DESYNC_MAX_FAKE_LEN 9216
enum dpi_desync_mode {
DESYNC_NONE=0,
enum dpi_desync_mode
{
DESYNC_NONE = 0,
DESYNC_INVALID,
DESYNC_FAKE,
DESYNC_FAKE_KNOWN,

View File

@@ -5,7 +5,7 @@
#define ZCHUNK 16384
#define BUFMIN 128
#define BUFCHUNK (1024*128)
#define BUFCHUNK (1024 * 128)
int z_readfile(FILE *F, char **buf, size_t *size)
{
@@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
bufsize = *size = 0;
r = inflateInit2(&zs, 47);
if (r != Z_OK) return r;
if (r != Z_OK)
return r;
do
{
@@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
r = Z_ERRNO;
goto zerr;
}
if (!zs.avail_in) break;
if (!zs.avail_in)
break;
zs.next_in = in;
do
{
@@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size)
*buf = newbuf;
}
zs.avail_out = bufsize - *size;
zs.next_out = (unsigned char*)(*buf + *size);
zs.next_out = (unsigned char *)(*buf + *size);
r = inflate(&zs, Z_NO_FLUSH);
if (r != Z_OK && r != Z_STREAM_END) goto zerr;
if (r != Z_OK && r != Z_STREAM_END)
goto zerr;
*size = bufsize - zs.avail_out;
} while (r == Z_OK && zs.avail_in);
} while (r == Z_OK);
@@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
if (*size < bufsize)
{
// free extra space
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
if ((newbuf = realloc(*buf, *size)))
*buf = newbuf;
}
inflateEnd(&zs);
@@ -73,7 +77,7 @@ zerr:
return r;
}
bool is_gzip(FILE* F)
bool is_gzip(FILE *F)
{
unsigned char magic[2];
bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B;

View File

@@ -4,5 +4,5 @@
#include <zlib.h>
#include <stdbool.h>
int z_readfile(FILE *F,char **buf,size_t *size);
bool is_gzip(FILE* F);
int z_readfile(FILE *F, char **buf, size_t *size);
bool is_gzip(FILE *F);

View File

@@ -7,7 +7,6 @@
#include <ctype.h>
#include <sys/stat.h>
#include "params.h"
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
@@ -19,11 +18,15 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
size = limit;
bcut = true;
}
if (!size) return;
for (k = 0; k < size; k++) DLOG("%02X ", data[k]);
if (!size)
return;
for (k = 0; k < size; k++)
DLOG("%02X ", data[k]);
DLOG(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut) DLOG(" ...");
for (k = 0; k < size; k++)
DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut)
DLOG(" ...");
}
char *strncasestr(const char *s, const char *find, size_t slen)
@@ -38,9 +41,11 @@ char *strncasestr(const char *s, const char *find, size_t slen)
{
do
{
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
if (slen-- < 1 || (sc = *s++) == '\0')
return NULL;
} while (toupper(c) != toupper(sc));
if (len > slen) return NULL;
if (len > slen)
return NULL;
} while (strncasecmp(s, find, len) != 0);
s--;
}
@@ -52,7 +57,8 @@ bool load_file(const char *filename, void *buffer, size_t *buffer_size)
FILE *F;
F = fopen(filename, "rb");
if (!F) return false;
if (!F)
return false;
*buffer_size = fread(buffer, 1, *buffer_size, F);
if (ferror(F))
@@ -74,7 +80,8 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
FILE *F;
F = fopen(filename, "wb");
if (!F) return false;
if (!F)
return false;
fwrite(buffer, 1, buffer_size, F);
if (ferror(F))
@@ -88,25 +95,26 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
}
bool append_to_list_file(const char *filename, const char *s)
{
FILE *F = fopen(filename,"at");
if (!F) return false;
bool bOK = fprintf(F,"%s\n",s)>0;
FILE *F = fopen(filename, "at");
if (!F)
return false;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F);
return bOK;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
if (!len) return;
if (!len)
return;
*str = 0;
switch (sa->sa_family)
{
case AF_INET:
inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len);
break;
case AF_INET6:
inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len);
inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len);
break;
default:
snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family);
@@ -119,10 +127,10 @@ void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
switch (sa->sa_family)
{
case AF_INET:
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in*)sa)->sin_port));
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port));
break;
case AF_INET6:
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
break;
default:
snprintf(str, len, "%s", ip);
@@ -138,49 +146,55 @@ void print_sockaddr(const struct sockaddr *sa)
bool pton4_port(const char *s, struct sockaddr_in *sa)
{
char ip[16],*p;
char ip[16], *p;
size_t l;
unsigned int u;
p = strchr(s,':');
if (!p) return false;
l = p-s;
if (l<7 || l>15) return false;
memcpy(ip,s,l);
ip[l]=0;
p = strchr(s, ':');
if (!p)
return false;
l = p - s;
if (l < 7 || l > 15)
return false;
memcpy(ip, s, l);
ip[l] = 0;
p++;
sa->sin_family = AF_INET;
if (inet_pton(AF_INET,ip,&sa->sin_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
if (inet_pton(AF_INET, ip, &sa->sin_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
return false;
sa->sin_port = htons((uint16_t)u);
return true;
}
bool pton6_port(const char *s, struct sockaddr_in6 *sa)
{
char ip[40],*p;
char ip[40], *p;
size_t l;
unsigned int u;
if (*s++!='[') return false;
p = strchr(s,']');
if (!p || p[1]!=':') return false;
l = p-s;
if (l<2 || l>39) return false;
p+=2;
memcpy(ip,s,l);
ip[l]=0;
if (*s++ != '[')
return false;
p = strchr(s, ']');
if (!p || p[1] != ':')
return false;
l = p - s;
if (l < 2 || l > 39)
return false;
p += 2;
memcpy(ip, s, l);
ip[l] = 0;
sa->sin6_family = AF_INET6;
if (inet_pton(AF_INET6,ip,&sa->sin6_addr)!=1 || sscanf(p,"%u",&u)!=1 || !u || u>0xFFFF) return false;
if (inet_pton(AF_INET6, ip, &sa->sin6_addr) != 1 || sscanf(p, "%u", &u) != 1 || !u || u > 0xFFFF)
return false;
sa->sin6_port = htons((uint16_t)u);
sa->sin6_flowinfo = 0;
sa->sin6_scope_id = 0;
return true;
}
void dbgprint_socket_buffers(int fd)
{
if (params.debug)
@@ -190,7 +204,7 @@ void dbgprint_socket_buffers(int fd)
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz))
DLOG("fd=%d SO_RCVBUF=%d\n", fd, v);
sz = sizeof(int);
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz))
DLOG("fd=%d SO_SNDBUF=%d\n", fd, v);
}
@@ -216,14 +230,14 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
uint64_t pntoh64(const void *p)
{
return (uint64_t)*((const uint8_t *)(p)+0) << 56 |
(uint64_t)*((const uint8_t *)(p)+1) << 48 |
(uint64_t)*((const uint8_t *)(p)+2) << 40 |
(uint64_t)*((const uint8_t *)(p)+3) << 32 |
(uint64_t)*((const uint8_t *)(p)+4) << 24 |
(uint64_t)*((const uint8_t *)(p)+5) << 16 |
(uint64_t)*((const uint8_t *)(p)+6) << 8 |
(uint64_t)*((const uint8_t *)(p)+7) << 0;
return (uint64_t) * ((const uint8_t *)(p) + 0) << 56 |
(uint64_t) * ((const uint8_t *)(p) + 1) << 48 |
(uint64_t) * ((const uint8_t *)(p) + 2) << 40 |
(uint64_t) * ((const uint8_t *)(p) + 3) << 32 |
(uint64_t) * ((const uint8_t *)(p) + 4) << 24 |
(uint64_t) * ((const uint8_t *)(p) + 5) << 16 |
(uint64_t) * ((const uint8_t *)(p) + 6) << 8 |
(uint64_t) * ((const uint8_t *)(p) + 7) << 0;
}
void phton64(uint8_t *p, uint64_t v)
{
@@ -239,57 +253,60 @@ void phton64(uint8_t *p, uint64_t v)
bool seq_within(uint32_t s, uint32_t s1, uint32_t s2)
{
return (s2>=s1 && s>=s1 && s<=s2) || (s2<s1 && (s<=s2 || s>=s1));
return (s2 >= s1 && s >= s1 && s <= s2) || (s2 < s1 && (s <= s2 || s >= s1));
}
bool ipv6_addr_is_zero(const struct in6_addr *a)
{
return !memcmp(a,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",16);
return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
}
#define INVALID_HEX_DIGIT ((uint8_t)-1)
#define INVALID_HEX_DIGIT ((uint8_t) - 1)
static inline uint8_t parse_hex_digit(char c)
{
return (c>='0' && c<='9') ? c-'0' : (c>='a' && c<='f') ? c-'a'+0xA : (c>='A' && c<='F') ? c-'A'+0xA : INVALID_HEX_DIGIT;
return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 0xA
: (c >= 'A' && c <= 'F') ? c - 'A' + 0xA
: INVALID_HEX_DIGIT;
}
static inline bool parse_hex_byte(const char *s, uint8_t *pbyte)
{
uint8_t u,l;
uint8_t u, l;
u = parse_hex_digit(s[0]);
l = parse_hex_digit(s[1]);
if (u==INVALID_HEX_DIGIT || l==INVALID_HEX_DIGIT)
if (u == INVALID_HEX_DIGIT || l == INVALID_HEX_DIGIT)
{
*pbyte=0;
*pbyte = 0;
return false;
}
else
{
*pbyte=(u<<4) | l;
*pbyte = (u << 4) | l;
return true;
}
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
{
uint8_t *pe = pbuf+*size;
*size=0;
while(pbuf<pe && *s)
uint8_t *pe = pbuf + *size;
*size = 0;
while (pbuf < pe && *s)
{
if (!parse_hex_byte(s,pbuf))
if (!parse_hex_byte(s, pbuf))
return false;
pbuf++; s+=2; (*size)++;
pbuf++;
s += 2;
(*size)++;
}
return true;
}
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize)
void fill_pattern(uint8_t *buf, size_t bufsize, const void *pattern, size_t patsize)
{
size_t size;
while (bufsize)
{
size = bufsize>patsize ? patsize : bufsize;
memcpy(buf,pattern,size);
size = bufsize > patsize ? patsize : bufsize;
memcpy(buf, pattern, size);
buf += size;
bufsize -= size;
}
@@ -301,66 +318,72 @@ int fprint_localtime(FILE *F)
time_t now;
time(&now);
localtime_r(&now,&t);
localtime_r(&now, &t);
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
}
time_t file_mod_time(const char *filename)
{
struct stat st;
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
}
bool pf_in_range(uint16_t port, const port_filter *pf)
{
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg);
}
bool pf_parse(const char *s, port_filter *pf)
{
unsigned int v1,v2;
unsigned int v1, v2;
if (!s) return false;
if (*s=='~')
if (!s)
return false;
if (*s == '~')
{
pf->neg=true;
pf->neg = true;
s++;
}
else
pf->neg=false;
if (sscanf(s,"%u-%u",&v1,&v2)==2)
pf->neg = false;
if (sscanf(s, "%u-%u", &v1, &v2) == 2)
{
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false;
pf->from=(uint16_t)v1;
pf->to=(uint16_t)v2;
if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
return false;
pf->from = (uint16_t)v1;
pf->to = (uint16_t)v2;
}
else if (sscanf(s,"%u",&v1)==1)
else if (sscanf(s, "%u", &v1) == 1)
{
if (!v1 || v1>65535) return false;
pf->to=pf->from=(uint16_t)v1;
if (!v1 || v1 > 65535)
return false;
pf->to = pf->from = (uint16_t)v1;
}
else
return false;
return true;
}
void fill_random_bytes(uint8_t *p,size_t sz)
void fill_random_bytes(uint8_t *p, size_t sz)
{
size_t k,sz16 = sz>>1;
for(k=0;k<sz16;k++) ((uint16_t*)p)[k]=(uint16_t)random();
if (sz & 1) p[sz-1]=(uint8_t)random();
size_t k, sz16 = sz >> 1;
for (k = 0; k < sz16; k++)
((uint16_t *)p)[k] = (uint16_t)random();
if (sz & 1)
p[sz - 1] = (uint8_t)random();
}
void fill_random_az(uint8_t *p,size_t sz)
void fill_random_az(uint8_t *p, size_t sz)
{
size_t k;
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a'));
for (k = 0; k < sz; k++)
p[k] = 'a' + (random() % ('z' - 'a'));
}
void fill_random_az09(uint8_t *p,size_t sz)
void fill_random_az09(uint8_t *p, size_t sz)
{
size_t k;
uint8_t rnd;
for(k=0;k<sz;k++)
for (k = 0; k < sz; k++)
{
rnd = random() % (10 + 'z'-'a'+1);
p[k] = rnd<10 ? rnd+'0' : 'a'+rnd-10;
rnd = random() % (10 + 'z' - 'a' + 1);
p[k] = rnd < 10 ? rnd + '0' : 'a' + rnd - 10;
}
}

View File

@@ -10,9 +10,9 @@
#include <time.h>
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
char *strncasestr(const char *s,const char *find, size_t slen);
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size);
char *strncasestr(const char *s, const char *find, size_t slen);
bool load_file(const char *filename, void *buffer, size_t *buffer_size);
bool load_file_nonempty(const char *filename, void *buffer, size_t *buffer_size);
bool save_file(const char *filename, const void *buffer, size_t buffer_size);
bool append_to_list_file(const char *filename, const char *s);
@@ -32,19 +32,22 @@ void phton64(uint8_t *p, uint64_t v);
bool ipv6_addr_is_zero(const struct in6_addr *a);
static inline uint16_t pntoh16(const uint8_t *p) {
static inline uint16_t pntoh16(const uint8_t *p)
{
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
}
static inline void phton16(uint8_t *p, uint16_t v) {
static inline void phton16(uint8_t *p, uint16_t v)
{
p[0] = (uint8_t)(v >> 8);
p[1] = v & 0xFF;
}
static inline uint32_t pntoh32(const uint8_t *p) {
static inline uint32_t pntoh32(const uint8_t *p)
{
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize);
void fill_pattern(uint8_t *buf, size_t bufsize, const void *pattern, size_t patsize);
int fprint_localtime(FILE *F);
@@ -52,12 +55,12 @@ time_t file_mod_time(const char *filename);
typedef struct
{
uint16_t from,to;
uint16_t from, to;
bool neg;
} port_filter;
bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
void fill_random_bytes(uint8_t *p,size_t sz);
void fill_random_az(uint8_t *p,size_t sz);
void fill_random_az09(uint8_t *p,size_t sz);
void fill_random_bytes(uint8_t *p, size_t sz);
void fill_random_az(uint8_t *p, size_t sz);
void fill_random_az09(uint8_t *p, size_t sz);

View File

@@ -8,17 +8,19 @@
static bool addpool(strpool **hostlist, char **s, const char *end)
{
char *p;
// advance until eol lowering all chars
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
*p = tolower(*p);
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
{
StrPoolDestroy(hostlist);
*hostlist = NULL;
return false;
}
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
for (; p < end && (!*p || *p == '\r' || *p == '\n'); p++)
;
*s = p;
return true;
}
@@ -31,7 +33,7 @@ bool AppendHostList(strpool **hostlist, char *filename)
FILE *F;
int r;
DLOG_CONDUP("Loading hostlist %s\n",filename);
DLOG_CONDUP("Loading hostlist %s\n", filename);
if (!(F = fopen(filename, "rb")))
{
@@ -41,18 +43,19 @@ bool AppendHostList(strpool **hostlist, char *filename)
if (is_gzip(F))
{
r = z_readfile(F,&zbuf,&zsize);
r = z_readfile(F, &zbuf, &zsize);
fclose(F);
if (r==Z_OK)
if (r == Z_OK)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
while (p < e)
{
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,e))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, e))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
@@ -64,19 +67,20 @@ bool AppendHostList(strpool **hostlist, char *filename)
}
else
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
DLOG_ERR("zlib decompression failed : result %d\n", r);
return false;
}
}
else
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, 256, F))
{
p = s;
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
if (!addpool(hostlist,&p,p+strlen(p)))
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
continue;
if (!addpool(hostlist, &p, p + strlen(p)))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
fclose(F);
@@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
LIST_FOREACH(file, file_list, next)
{
if (!AppendHostList(hostlist, file->str)) return false;
if (!AppendHostList(hostlist, file->str))
return false;
}
return true;
}
@@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
}
bool SearchHostList(strpool *hostlist, const char *host)
{
if (hostlist)
@@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
{
bInHostList = StrPoolCheckStr(hostlist, p);
DLOG("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
if (bInHostList) return true;
if (bInHostList)
return true;
p = strchr(p, '.');
if (p) p++;
if (p)
p++;
}
}
return false;
@@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
// return : true = apply fooling, false = do not apply
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
{
if (excluded) *excluded = false;
if (excluded)
*excluded = false;
if (hostlist_exclude)
{
DLOG("Checking exclude hostlist\n");
if (SearchHostList(hostlist_exclude, host))
{
if (excluded) *excluded = true;
if (excluded)
*excluded = true;
return false;
}
}
@@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded)
if (*params.hostlist_auto_filename)
{
time_t t = file_mod_time(params.hostlist_auto_filename);
if (t!=params.hostlist_auto_mod_time)
if (t != params.hostlist_auto_mod_time)
{
DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n");
if (!LoadIncludeHostLists())

File diff suppressed because it is too large Load Diff

View File

@@ -9,26 +9,30 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q)
}
void rawpacket_free(struct rawpacket *rp)
{
if (rp) free(rp->packet);
if (rp)
free(rp->packet);
free(rp);
}
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
{
struct rawpacket *rp;
rp = TAILQ_FIRST(q);
if (rp) TAILQ_REMOVE(q, rp, next);
if (rp)
TAILQ_REMOVE(q, rp, next);
return rp;
}
void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
{
struct rawpacket *rp;
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
while ((rp = rawpacket_dequeue(q)))
rawpacket_free(rp);
}
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload)
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload)
{
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL;
if (!rp)
return NULL;
rp->packet = malloc(len);
if (!rp->packet)
@@ -36,30 +40,31 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
free(rp);
return NULL;
}
rp->dst = *dst;
rp->fwmark = fwmark;
if (ifout)
{
strncpy(rp->ifout,ifout,sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout)-1]=0;
strncpy(rp->ifout, ifout, sizeof(rp->ifout));
rp->ifout[sizeof(rp->ifout) - 1] = 0;
}
else
rp->ifout[0]=0;
memcpy(rp->packet,data,len);
rp->len=len;
rp->len_payload=len_payload;
rp->ifout[0] = 0;
memcpy(rp->packet, data, len);
rp->len = len;
rp->len_payload = len_payload;
TAILQ_INSERT_TAIL(q, rp, next);
return rp;
}
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q)
{
const struct rawpacket *rp;
unsigned int ct=0;
TAILQ_FOREACH(rp, q, next) ct++;
unsigned int ct = 0;
TAILQ_FOREACH(rp, q, next)
ct++;
return ct;
}
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)

View File

@@ -9,11 +9,12 @@
struct rawpacket
{
struct sockaddr_storage dst;
char ifout[IFNAMSIZ+1];
char ifout[IFNAMSIZ + 1];
uint32_t fwmark;
size_t len, len_payload;
uint8_t *packet;
TAILQ_ENTRY(rawpacket) next;
TAILQ_ENTRY(rawpacket)
next;
};
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
@@ -21,6 +22,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q);
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len,size_t len_payload);
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q, const struct sockaddr_storage *dst, uint32_t fwmark, const char *ifout, const void *data, size_t len, size_t len_payload);
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp);

View File

@@ -13,40 +13,39 @@ const char *progname = "nfqws";
#error UNKNOWN_SYSTEM_TIME
#endif
int DLOG_FILE(FILE *F, const char *format, va_list args)
{
return vfprintf(F, format, args);
}
int DLOG_CON(const char *format, int syslog_priority, va_list args)
{
return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args);
return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args);
}
int DLOG_FILENAME(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
r = DLOG_FILE(F, format, args);
fclose(F);
}
else
r=-1;
r = -1;
return r;
}
static char syslog_buf[1024];
static size_t syslog_buf_sz=0;
static size_t syslog_buf_sz = 0;
static void syslog_buffered(int priority, const char *format, va_list args)
{
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0)
{
syslog_buf_sz=strlen(syslog_buf);
syslog_buf_sz = strlen(syslog_buf);
// log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n'))
{
syslog(priority,"%s",syslog_buf);
syslog(priority, "%s", syslog_buf);
syslog_buf_sz = 0;
}
}
@@ -54,31 +53,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list args)
{
int r=0;
int r = 0;
va_list args2;
if (condup && !(params.debug && params.debug_target==LOG_TARGET_CONSOLE))
if (condup && !(params.debug && params.debug_target == LOG_TARGET_CONSOLE))
{
va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2);
va_copy(args2, args);
DLOG_CON(format, syslog_priority, args2);
}
if (params.debug)
{
switch(params.debug_target)
switch (params.debug_target)
{
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format,syslog_priority,args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile,format,args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority,format,args);
r = 1;
break;
default:
break;
case LOG_TARGET_CONSOLE:
r = DLOG_CON(format, syslog_priority, args);
break;
case LOG_TARGET_FILE:
r = DLOG_FILENAME(params.debug_logfile, format, args);
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority, format, args);
r = 1;
break;
default:
break;
}
}
return r;
@@ -116,11 +115,10 @@ int DLOG_PERROR(const char *s)
return DLOG_ERR("%s: %s\n", s, strerror(errno));
}
int LOG_APPEND(const char *filename, const char *format, va_list args)
{
int r;
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (F)
{
fprint_localtime(F);
@@ -130,7 +128,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
fclose(F);
}
else
r=-1;
r = -1;
return r;
}

View File

@@ -13,27 +13,32 @@
#include <stdio.h>
#include <time.h>
#define TLS_PARTIALS_ENABLE true
#define TLS_PARTIALS_ENABLE true
#define Q_RCVBUF (128*1024) // in bytes
#define Q_SNDBUF (64*1024) // in bytes
#define RAW_SNDBUF (64*1024) // in bytes
#define Q_RCVBUF (128 * 1024) // in bytes
#define Q_SNDBUF (64 * 1024) // in bytes
#define RAW_SNDBUF (64 * 1024) // in bytes
#define Q_MAXLEN 1024 // in packets
#define Q_MAXLEN 1024 // in packets
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32
#define UDPLEN_INCREMENT_DEFAULT 2
#define UDPLEN_INCREMENT_DEFAULT 2
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
enum log_target
{
LOG_TARGET_CONSOLE = 0,
LOG_TARGET_FILE,
LOG_TARGET_SYSLOG
};
struct params_s
{
@@ -41,8 +46,8 @@ struct params_s
char debug_logfile[PATH_MAX];
bool debug;
uint16_t wsize,wssize;
uint8_t wscale,wsscale;
uint16_t wsize, wssize;
uint8_t wscale, wsscale;
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int wssize_cutoff;
#ifdef __linux__
@@ -50,12 +55,12 @@ struct params_s
#elif defined(BSD)
uint16_t port; // divert port
#endif
char bind_fix4,bind_fix6;
char bind_fix4, bind_fix6;
bool hostcase, hostnospace, domcase;
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto;
unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
enum dpi_desync_mode desync_mode0, desync_mode, desync_mode2;
bool desync_retrans, desync_skip_nosni, desync_any_proto;
unsigned int desync_repeats, desync_split_pos, desync_seqovl, desync_ipfrag_pos_tcp, desync_ipfrag_pos_udp;
enum httpreqpos desync_split_http_req;
enum tlspos desync_split_tls;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
@@ -65,13 +70,13 @@ struct params_s
uint32_t desync_fooling_mode;
uint32_t desync_fwmark; // unused in BSD
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint8_t fake_http[1460],fake_tls[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460];
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
uint8_t fake_http[1460], fake_tls[1460], fake_unknown[1460], fake_syndata[1460], seqovl_pattern[1460];
uint8_t fake_unknown_udp[1472], udplen_pattern[1472], fake_quic[1472], fake_wg[1472], fake_dht[1472];
size_t fake_http_size, fake_tls_size, fake_quic_size, fake_wg_size, fake_dht_size, fake_unknown_size, fake_syndata_size, fake_unknown_udp_size;
int udplen_increment;
#ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter;
struct str_list_head ssid_filter, nlm_filter;
#else
bool droproot;
uid_t uid;

View File

@@ -5,33 +5,33 @@
#include <stdio.h>
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) \
{ \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype *)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
DESTROY_STR_POOL(strpool, pp)
}
void HostFailPoolDestroy(hostfail_pool **pp)
{
DESTROY_STR_POOL(hostfail_pool, pp)
}
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
void HostFailPoolDestroy(hostfail_pool **pp){
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
{
size_t slen = strlen(s);
ADD_STR_POOL(hostfail_pool, pp, s, slen)
@@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
elem->counter = 0;
return elem;
}
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
{
hostfail_pool *elem;
HASH_FIND_STR(p, s, elem);
@@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
}
}
}
static time_t host_fail_purge_prev=0;
static time_t host_fail_purge_prev = 0;
void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
{
time_t now = time(NULL);
@@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
hostfail_pool *elem, *tmp;
time_t now = time(NULL);
HASH_ITER(hh, p, elem, tmp)
printf("host=%s counter=%d time_left=%lld\n",elem->str,elem->counter,(long long int)elem->expire-now);
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
}
bool strlist_add(struct str_list_head *head, const char *filename)
{
struct str_list *entry = malloc(sizeof(struct str_list));
if (!entry) return false;
if (!entry)
return false;
entry->str = strdup(filename);
if (!entry->str)
{
@@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
}
static void strlist_entry_destroy(struct str_list *entry)
{
if (entry->str) free(entry->str);
if (entry->str)
free(entry->str);
free(entry);
}
void strlist_destroy(struct str_list_head *head)

View File

@@ -5,38 +5,41 @@
#include <sys/queue.h>
#include <time.h>
//#define HASH_BLOOM 20
// #define HASH_BLOOM 20
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
typedef struct strpool {
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct strpool
{
char *str; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} strpool;
void StrPoolDestroy(strpool **pp);
bool StrPoolAddStr(strpool **pp,const char *s);
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
bool StrPoolCheckStr(strpool *p,const char *s);
bool StrPoolAddStr(strpool **pp, const char *s);
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
bool StrPoolCheckStr(strpool *p, const char *s);
struct str_list {
char *str;
LIST_ENTRY(str_list) next;
struct str_list
{
char *str;
LIST_ENTRY(str_list)
next;
};
LIST_HEAD(str_list_head, str_list);
typedef struct hostfail_pool {
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
typedef struct hostfail_pool
{
char *str; /* key */
int counter; /* value */
time_t expire; /* when to expire record (unixtime) */
UT_hash_handle hh; /* makes this structure hashable */
} hostfail_pool;
void HostFailPoolDestroy(hostfail_pool **pp);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s);
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time);
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s);
void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem);
void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);

View File

@@ -7,7 +7,7 @@
#include <arpa/inet.h>
#include <string.h>
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL};
const char *HttpMethod(const uint8_t *data, size_t len)
{
const char **method;
@@ -22,24 +22,26 @@ const char *HttpMethod(const uint8_t *data, size_t len)
}
bool IsHttp(const uint8_t *data, size_t len)
{
return !!HttpMethod(data,len);
return !!HttpMethod(data, len);
}
// pHost points to "Host: ..."
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs)
{
if (!*pHost)
{
*pHost = memmem(buf, bs, "\nHost:", 6);
if (*pHost) (*pHost)++;
if (*pHost)
(*pHost)++;
}
return !!*pHost;
}
@@ -47,32 +49,37 @@ bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
bool IsHttpReply(const uint8_t *data, size_t len)
{
// HTTP/1.x 200\r\n
return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' &&
data[9]>='0' && data[9]<='9' &&
data[10]>='0' && data[10]<='9' &&
data[11]>='0' && data[11]<='9';
return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' &&
data[9] >= '0' && data[9] <= '9' &&
data[10] >= '0' && data[10] <= '9' &&
data[11] >= '0' && data[11] <= '9';
}
int HttpReplyCode(const uint8_t *data, size_t len)
{
return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0');
return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0');
}
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf)
{
const uint8_t *p, *s, *e = data + len;
p = (uint8_t*)strncasestr((char*)data, header, len);
if (!p) return false;
p = (uint8_t *)strncasestr((char *)data, header, len);
if (!p)
return false;
p += strlen(header);
while (p < e && (*p == ' ' || *p == '\t')) p++;
while (p < e && (*p == ' ' || *p == '\t'))
p++;
s = p;
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++;
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t'))
s++;
if (s > p)
{
size_t slen = s - p;
if (buf && len_buf)
{
if (slen >= len_buf) slen = len_buf - 1;
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
if (slen >= len_buf)
slen = len_buf - 1;
for (size_t i = 0; i < slen; i++)
buf[i] = tolower(p[i]);
buf[slen] = 0;
}
return true;
@@ -85,83 +92,97 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
}
const char *HttpFind2ndLevelDomain(const char *host)
{
const char *p=NULL;
const char *p = NULL;
if (*host)
{
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
if (*p=='.') for (p--; p>host && *p!='.'; p--);
if (*p=='.') p++;
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
;
if (*p == '.')
for (p--; p > host && *p != '.'; p--)
;
if (*p == '.')
p++;
}
return p;
}
// DPI redirects are global redirects to another domain
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
{
char loc[256],*redirect_host, *p;
char loc[256], *redirect_host, *p;
int code;
if (!host || !*host) return false;
code = HttpReplyCode(data,len);
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
if (!host || !*host)
return false;
code = HttpReplyCode(data, len);
if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc)))
return false;
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
if (!strncmp(loc,"http://",7))
redirect_host=loc+7;
else if (!strncmp(loc,"https://",8))
redirect_host=loc+8;
if (!strncmp(loc, "http://", 7))
redirect_host = loc + 7;
else if (!strncmp(loc, "https://", 8))
redirect_host = loc + 8;
else
return false;
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
for(p=redirect_host; *p && *p!='/' ; p++);
*p=0;
if (!*redirect_host) return false;
for (p = redirect_host; *p && *p != '/'; p++)
;
*p = 0;
if (!*redirect_host)
return false;
// somethinkg like : censor.net
// extract 2nd level domains
const char *dhost = HttpFind2ndLevelDomain(host);
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
return strcasecmp(dhost, drhost)!=0;
return strcasecmp(dhost, drhost) != 0;
}
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
{
const uint8_t *method, *host;
int i;
switch(tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method=http;
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
if (i<3 || *method!=' ') break;
return method-http-1;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos<sz ? hpos_pos : 0;
}
switch (tpos_type)
{
case httpreqpos_method:
// recognize some tpws pre-applied hacks
method = http;
if (sz < 10)
break;
if (*method == '\n' || *method == '\r')
method++;
if (*method == '\n' || *method == '\r')
method++;
for (i = 0; i < 7; i++)
if (*method >= 'A' && *method <= 'Z')
method++;
if (i < 3 || *method != ' ')
break;
return method - http - 1;
case httpreqpos_host:
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
{
host += 5;
if (*host == ' ')
host++;
return host - http;
}
break;
case httpreqpos_pos:
break;
default:
return 0;
}
return hpos_pos < sz ? hpos_pos : 0;
}
uint16_t TLSRecordDataLen(const uint8_t *data)
{
@@ -173,7 +194,7 @@ size_t TLSRecordLen(const uint8_t *data)
}
bool IsTLSRecordFull(const uint8_t *data, size_t len)
{
return TLSRecordLen(data)<=len;
return TLSRecordLen(data) <= len;
}
bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK)
{
@@ -186,14 +207,13 @@ size_t TLSHandshakeLen(const uint8_t *data)
}
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len)
{
return len>=4 && data[0]==0x01 && TLSHandshakeLen(data)>0;
return len >= 4 && data[0] == 0x01 && TLSHandshakeLen(data) > 0;
}
bool IsTLSHandshakeFull(const uint8_t *data, size_t len)
{
return (4+TLSHandshakeLen(data))<=len;
return (4 + TLSHandshakeLen(data)) <= len;
}
// bPartialIsOK=true - accept partial packets not containing the whole TLS message
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK)
{
@@ -212,40 +232,51 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
size_t l;
if (!bPartialIsOK && !IsTLSHandshakeFull(data,len)) return false;
if (!bPartialIsOK && !IsTLSHandshakeFull(data, len))
return false;
l = 1 + 3 + 2 + 32;
// SessionIDLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
l += data[l] + 1;
// CipherSuitesLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
l += pntoh16(data + l) + 2;
// CompressionMethodsLength
if (len < (l + 1)) return false;
if (len < (l + 1))
return false;
l += data[l] + 1;
// ExtensionsLength
if (len < (l + 2)) return false;
if (len < (l + 2))
return false;
data += l; len -= l;
data += l;
len -= l;
l = pntoh16(data);
data += 2; len -= 2;
data += 2;
len -= 2;
if (bPartialIsOK)
{
if (len < l) l = len;
if (len < l)
l = len;
}
else
{
if (len < l) return false;
if (len < l)
return false;
}
while (l >= 4)
{
uint16_t etype = pntoh16(data);
size_t elen = pntoh16(data + 2);
data += 4; l -= 4;
if (l < elen) break;
data += 4;
l -= 4;
if (l < elen)
break;
if (etype == type)
{
if (ext && len_ext)
@@ -255,7 +286,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
}
return true;
}
data += elen; l -= elen;
data += elen;
l -= elen;
}
return false;
@@ -267,9 +299,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
// u16 Version: TLS1.0
// u16 Length
size_t reclen;
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
reclen=TLSRecordLen(data);
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
if (!IsTLSClientHello(data, len, bPartialIsOK))
return false;
reclen = TLSRecordLen(data);
if (reclen < len)
len = reclen; // correct len if it has more data than the first tls record has
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
}
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
@@ -277,14 +311,19 @@ static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, s
// u16 data+0 - name list length
// u8 data+2 - server name type. 0=host_name
// u16 data+3 - server name length
if (elen < 5 || ext[2] != 0) return false;
if (elen < 5 || ext[2] != 0)
return false;
size_t slen = pntoh16(ext + 3);
ext += 5; elen -= 5;
if (slen < elen) return false;
ext += 5;
elen -= 5;
if (slen < elen)
return false;
if (host && len_host)
{
if (slen >= len_host) slen = len_host - 1;
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
if (slen >= len_host)
slen = len_host - 1;
for (size_t i = 0; i < slen; i++)
host[i] = tolower(ext[i]);
host[slen] = 0;
}
return true;
@@ -294,7 +333,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
const uint8_t *ext;
size_t elen;
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK))
return false;
return TLSExtractHostFromExt(ext, elen, host, len_host);
}
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
@@ -302,48 +342,52 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
const uint8_t *ext;
size_t elen;
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK))
return false;
return TLSExtractHostFromExt(ext, elen, host, len_host);
}
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
{
size_t elen;
const uint8_t *ext;
switch(tpos_type)
switch (tpos_type)
{
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
// fall through
case tlspos_pos:
return tpos_pos<sz ? tpos_pos : 0;
default:
return 0;
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls, sz, 0, &ext, &elen, false))
return (tpos_type == tlspos_sni) ? ext - tls + 6 : ext - tls + 1;
// fall through
case tlspos_pos:
return tpos_pos < sz ? tpos_pos : 0;
default:
return 0;
}
}
static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
{
switch (*tvb >> 6)
{
case 0: /* 0b00 => 1 byte length (6 bits Usable) */
if (value) *value = *tvb & 0x3F;
if (value)
*value = *tvb & 0x3F;
return 1;
case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
if (value) *value = pntoh16(tvb) & 0x3FFF;
if (value)
*value = pntoh16(tvb) & 0x3FFF;
return 2;
case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
if (value) *value = pntoh32(tvb) & 0x3FFFFFFF;
if (value)
*value = pntoh32(tvb) & 0x3FFFFFFF;
return 4;
case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
if (value) *value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
if (value)
*value = pntoh64(tvb) & 0x3FFFFFFFFFFFFFFF;
return 8;
}
// impossible case
if (*value) *value = 0;
if (*value)
*value = 0;
return 0;
}
static uint8_t tvb_get_size(uint8_t tvb)
@@ -355,15 +399,21 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
{
size_t offset = 1;
uint64_t coff, clen;
if (len < 3 || *data != 6) return false;
if ((offset+tvb_get_size(data[offset])) >= len) return false;
if (len < 3 || *data != 6)
return false;
if ((offset + tvb_get_size(data[offset])) >= len)
return false;
offset += tvb_get_varint(data + offset, &coff);
// offset must be 0 if it's a full segment, not just a chunk
if (coff || (offset+tvb_get_size(data[offset])) >= len) return false;
if (coff || (offset + tvb_get_size(data[offset])) >= len)
return false;
offset += tvb_get_varint(data + offset, &clen);
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data+offset,clen)) return false;
if (hello_offset) *hello_offset = offset;
if (hello_len) *hello_len = (size_t)clen;
if ((offset + clen) > len || !IsTLSHandshakeClientHello(data + offset, clen))
return false;
if (hello_offset)
*hello_offset = offset;
if (hello_len)
*hello_len = (size_t)clen;
return true;
}
@@ -371,22 +421,26 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
uint8_t QUICDraftVersion(uint32_t version)
{
/* IETF Draft versions */
if ((version >> 8) == 0xff0000) {
if ((version >> 8) == 0xff0000)
{
return (uint8_t)version;
}
/* Facebook mvfst, based on draft -22. */
if (version == 0xfaceb001) {
if (version == 0xfaceb001)
{
return 22;
}
/* Facebook mvfst, based on draft -27. */
if (version == 0xfaceb002 || version == 0xfaceb00e) {
if (version == 0xfaceb002 || version == 0xfaceb00e)
{
return 27;
}
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */
if (version == 0x51303530 ||
version == 0x54303530 ||
version == 0x54303531) {
version == 0x54303531)
{
return 27;
}
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
@@ -396,17 +450,20 @@ uint8_t QUICDraftVersion(uint32_t version)
used to select a proper salt (which depends on the version itself), but
we don't have a real version here! Let's hope that we need to handle
only latest drafts... */
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
{
return 29;
}
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */
if (version == 0x00000001) {
if (version == 0x00000001)
{
return 34;
}
/* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if (version == 0x709A50C4) {
if (version == 0x709A50C4)
{
return 100;
}
return 0;
@@ -418,7 +475,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
}
static bool is_quic_v2(uint32_t version)
{
return version == 0x6b3343cf;
return version == 0x6b3343cf;
}
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@@ -426,9 +483,11 @@ static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, co
uint8_t hkdflabel[64];
size_t label_size = strlen(label);
if (label_size > 255) return false;
if (label_size > 255)
return false;
size_t hkdflabel_size = 2 + 1 + label_size + 1;
if (hkdflabel_size > sizeof(hkdflabel)) return false;
if (hkdflabel_size > sizeof(hkdflabel))
return false;
phton16(hkdflabel, out_len);
hkdflabel[2] = (uint8_t)label_size;
@@ -454,69 +513,89 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in
*/
static const uint8_t handshake_salt_draft_22[20] = {
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a,
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a
};
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a};
static const uint8_t handshake_salt_draft_23[20] = {
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7,
0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
0xc3,
0xee,
0xf7,
0x12,
0xc7,
0x2e,
0xbb,
0x5a,
0x11,
0xa7,
0xd2,
0x43,
0x2b,
0xb4,
0x63,
0x65,
0xbe,
0xf9,
0xf5,
0x02,
};
static const uint8_t handshake_salt_draft_29[20] = {
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97,
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99
};
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99};
static const uint8_t handshake_salt_v1[20] = {
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a
};
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a};
static const uint8_t hanshake_salt_draft_q50[20] = {
0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94,
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45
};
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45};
static const uint8_t hanshake_salt_draft_t50[20] = {
0x7f, 0xf5, 0x79, 0xe5, 0xac, 0xd0, 0x72, 0x91, 0x55, 0x80,
0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10
};
0x30, 0x4c, 0x43, 0xa2, 0x36, 0x7c, 0x60, 0x48, 0x83, 0x10};
static const uint8_t hanshake_salt_draft_t51[20] = {
0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50,
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d
};
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d};
static const uint8_t handshake_salt_v2[20] = {
0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93,
0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9
};
0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9};
int err;
const uint8_t *salt;
uint8_t secret[USHAMaxHashSize];
uint8_t draft_version = QUICDraftVersion(version);
if (version == 0x51303530) {
if (version == 0x51303530)
{
salt = hanshake_salt_draft_q50;
}
else if (version == 0x54303530) {
else if (version == 0x54303530)
{
salt = hanshake_salt_draft_t50;
}
else if (version == 0x54303531) {
else if (version == 0x54303531)
{
salt = hanshake_salt_draft_t51;
}
else if (is_quic_draft_max(draft_version, 22)) {
else if (is_quic_draft_max(draft_version, 22))
{
salt = handshake_salt_draft_22;
}
else if (is_quic_draft_max(draft_version, 28)) {
else if (is_quic_draft_max(draft_version, 28))
{
salt = handshake_salt_draft_23;
}
else if (is_quic_draft_max(draft_version, 32)) {
else if (is_quic_draft_max(draft_version, 32))
{
salt = handshake_salt_draft_29;
}
else if (is_quic_draft_max(draft_version, 34)) {
else if (is_quic_draft_max(draft_version, 34))
{
salt = handshake_salt_v1;
}
else {
else
{
salt = handshake_salt_v2;
}
err = hkdfExtract(SHA256, salt, 20, cid->cid, cid->len, secret);
if (err) return false;
if (err)
return false;
if (client_initial_secret && !quic_hkdf_expand_label(secret, SHA256HashSize, "tls13 client in", client_initial_secret, SHA256HashSize))
return false;
@@ -525,16 +604,17 @@ static bool quic_derive_initial_secret(const quic_cid_t *cid, uint8_t *client_in
}
bool QUICIsLongHeader(const uint8_t *data, size_t len)
{
return len>=9 && !!(*data & 0x80);
return len >= 9 && !!(*data & 0x80);
}
uint32_t QUICExtractVersion(const uint8_t *data, size_t len)
{
// long header, fixed bit, type=initial
return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t*)(data + 1)) : 0;
return QUICIsLongHeader(data, len) ? ntohl(*(uint32_t *)(data + 1)) : 0;
}
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
{
if (!QUICIsLongHeader(data,len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6+data[5])>len) return false;
if (!QUICIsLongHeader(data, len) || !data[5] || data[5] > QUIC_MAX_CID_LENGTH || (6 + data[5]) > len)
return false;
cid->len = data[5];
memcpy(&cid->cid, data + 6, data[5]);
return true;
@@ -542,13 +622,16 @@ bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid)
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len)
{
uint32_t ver = QUICExtractVersion(data, data_len);
if (!ver) return false;
if (!ver)
return false;
quic_cid_t dcid;
if (!QUICExtractDCID(data, data_len, &dcid)) return false;
if (!QUICExtractDCID(data, data_len, &dcid))
return false;
uint8_t client_initial_secret[SHA256HashSize];
if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver)) return false;
if (!quic_derive_initial_secret(&dcid, client_initial_secret, ver))
return false;
uint8_t aeskey[16], aesiv[12], aeshp[16];
bool v1_label = !is_quic_v2(ver);
@@ -559,23 +642,28 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return false;
}
uint64_t payload_len,token_len;
uint64_t payload_len, token_len;
size_t pn_offset;
pn_offset = 1 + 4 + 1 + data[5];
if (pn_offset >= data_len) return false;
if (pn_offset >= data_len)
return false;
pn_offset += 1 + data[pn_offset];
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
return false;
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
pn_offset += token_len;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len)
return false;
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
if (payload_len < 20 || (pn_offset + payload_len) > data_len)
return false;
aes_init_keygen_tables();
uint8_t sample_enc[16];
aes_context ctx;
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) return false;
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc))
return false;
uint8_t mask[5];
memcpy(mask, sample_enc, sizeof(mask));
@@ -586,21 +674,25 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
uint8_t pkn_bytes[4];
memcpy(pkn_bytes, data + pn_offset, pkn_len);
uint32_t pkn = 0;
for (uint8_t i = 0; i < pkn_len; i++) pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
for (uint8_t i = 0; i < pkn_len; i++)
pkn |= (uint32_t)(pkn_bytes[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
size_t cryptlen = payload_len - pkn_len - 16;
if (cryptlen > *clean_len) return false;
if (cryptlen > *clean_len)
return false;
*clean_len = cryptlen;
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
uint8_t atag[16],header[256];
uint8_t atag[16], header[256];
size_t header_len = pn_offset + pkn_len;
if (header_len > sizeof(header)) return false; // not likely header will be so large
if (header_len > sizeof(header))
return false; // not likely header will be so large
memcpy(header, data, header_len);
header[0] = packet0;
for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
for (uint8_t i = 0; i < pkn_len; i++)
header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
return false;
@@ -609,48 +701,56 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len)
{
// Crypto frame can be split into multiple chunks
// chromium randomly splits it and pads with zero/one bytes to force support the standard
// mozilla does not split
if (*defrag_len<10) return false;
uint8_t *defrag_data = defrag+10;
size_t defrag_data_len = *defrag_len-10;
if (*defrag_len < 10)
return false;
uint8_t *defrag_data = defrag + 10;
size_t defrag_data_len = *defrag_len - 10;
uint8_t ft;
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false;
uint64_t offset, sz, szmax = 0, zeropos = 0, pos = 0;
bool found = false;
while(pos<clean_len)
while (pos < clean_len)
{
ft = clean[pos];
pos++;
if (ft>1) // 00 - padding, 01 - ping
if (ft > 1) // 00 - padding, 01 - ping
{
if (ft!=6) return false; // dont want to know all possible frame type formats
if (ft != 6)
return false; // don't want to know all possible frame type formats
if (pos>=clean_len) return false;
if (pos >= clean_len)
return false;
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
pos += tvb_get_varint(clean+pos, &offset);
if ((pos + tvb_get_size(clean[pos]) >= clean_len))
return false;
pos += tvb_get_varint(clean + pos, &offset);
if ((pos+tvb_get_size(clean[pos])>clean_len)) return false;
pos += tvb_get_varint(clean+pos, &sz);
if ((pos+sz)>clean_len) return false;
if ((pos + tvb_get_size(clean[pos]) > clean_len))
return false;
pos += tvb_get_varint(clean + pos, &sz);
if ((pos + sz) > clean_len)
return false;
if ((offset+sz)>defrag_data_len) return false;
if ((offset + sz) > defrag_data_len)
return false;
if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos);
if ((offset+sz) > zeropos)
zeropos=offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
if ((offset+sz) > szmax) szmax = offset+sz;
memset(defrag_data + zeropos, 0, offset - zeropos);
if ((offset + sz) > zeropos)
zeropos = offset + sz;
memcpy(defrag_data + offset, clean + pos, sz);
if ((offset + sz) > szmax)
szmax = offset + sz;
found=true;
pos+=sz;
found = true;
pos += sz;
}
}
if (found)
@@ -659,31 +759,38 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
defrag[1] = 0; // offset
// 2..9 - length 64 bit
// +10 - data start
phton64(defrag+2,szmax);
phton64(defrag + 2, szmax);
defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10);
*defrag_len = (size_t)(szmax + 10);
}
return found;
}
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello)
{
if (bIsCryptoHello) *bIsCryptoHello=false;
if (bDecryptOK) *bDecryptOK=false;
if (bIsCryptoHello)
*bIsCryptoHello = false;
if (bDecryptOK)
*bDecryptOK = false;
uint8_t clean[1500];
size_t clean_len = sizeof(clean);
if (!QUICDecryptInitial(data,data_len,clean,&clean_len)) return false;
if (!QUICDecryptInitial(data, data_len, clean, &clean_len))
return false;
if (bDecryptOK) *bDecryptOK=true;
if (bDecryptOK)
*bDecryptOK = true;
uint8_t defrag[1500];
size_t defrag_len = sizeof(defrag);
if (!QUICDefragCrypto(clean,clean_len,defrag,&defrag_len)) return false;
if (!QUICDefragCrypto(clean, clean_len, defrag, &defrag_len))
return false;
size_t hello_offset, hello_len;
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
if (bIsCryptoHello) *bIsCryptoHello=true;
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len))
return false;
if (bIsCryptoHello)
*bIsCryptoHello = true;
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
}
@@ -692,47 +799,53 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
{
// too small packets are not likely to be initials with client hello
// long header, fixed bit
if (len < 256 || (data[0] & 0xC0)!=0xC0) return false;
if (len < 256 || (data[0] & 0xC0) != 0xC0)
return false;
uint32_t ver = QUICExtractVersion(data,len);
if (QUICDraftVersion(ver) < 11) return false;
uint32_t ver = QUICExtractVersion(data, len);
if (QUICDraftVersion(ver) < 11)
return false;
// quic v1 : initial packets are 00b
// quic v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
// QUIC v1 : initial packets are 00b
// QUIC v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00))
return false;
uint64_t offset=5, sz;
uint64_t offset = 5, sz;
// DCID. must be present
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false;
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH)
return false;
offset += 1 + data[offset];
// SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
if (data[offset] > QUIC_MAX_CID_LENGTH)
return false;
offset += 1 + data[offset];
// token length
offset += tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset >= len) return false;
if (offset >= len)
return false;
// payload length
if ((offset + tvb_get_size(data[offset])) > len) return false;
if ((offset + tvb_get_size(data[offset])) > len)
return false;
tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset > len) return false;
if (offset > len)
return false;
// client hello cannot be too small. likely ACK
return sz>=96;
// ClientHello cannot be too small. likely ACK
return sz >= 96;
}
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
{
return len==148 && data[0]==1 && data[1]==0 && data[2]==0 && data[3]==0;
return len == 148 && data[0] == 1 && data[1] == 0 && data[2] == 0 && data[3] == 0;
}
bool IsDhtD1(const uint8_t *data, size_t len)
{
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
return len >= 7 && data[0] == 'd' && data[1] == '1' && data[len - 1] == 'e';
}

View File

@@ -10,8 +10,8 @@
extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(const uint8_t *data, size_t len);
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs);
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs);
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs);
// header must be passed like this : "\nHost:"
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf);
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
@@ -21,7 +21,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
enum httpreqpos
{
httpreqpos_none = 0,
httpreqpos_method,
httpreqpos_host,
httpreqpos_pos
};
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
uint16_t TLSRecordDataLen(const uint8_t *data);
@@ -35,16 +41,23 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
enum tlspos
{
tlspos_none = 0,
tlspos_sni,
tlspos_sniext,
tlspos_pos
};
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {
uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH];
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid
{
uint8_t len;
uint8_t cid[QUIC_MAX_CID_LENGTH];
} quic_cid_t;
bool IsQUICInitial(const uint8_t *data, size_t len);
@@ -55,5 +68,5 @@ uint8_t QUICDraftVersion(uint32_t version);
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len);
bool QUICDefragCrypto(const uint8_t *clean, size_t clean_len, uint8_t *defrag, size_t *defrag_len);
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);

186
nfq/sec.c
View File

@@ -25,128 +25,127 @@
// block most of the undesired syscalls to harden against code execution
static long blocked_syscalls[] = {
#ifdef SYS_execv
SYS_execv,
SYS_execv,
#endif
SYS_execve,
SYS_execve,
#ifdef SYS_execveat
SYS_execveat,
SYS_execveat,
#endif
#ifdef SYS_exec_with_loader
SYS_exec_with_loader,
SYS_exec_with_loader,
#endif
#ifdef SYS_clone
SYS_clone,
SYS_clone,
#endif
#ifdef SYS_clone2
SYS_clone2,
SYS_clone2,
#endif
#ifdef SYS_clone3
SYS_clone3,
SYS_clone3,
#endif
#ifdef SYS_osf_execve
SYS_osf_execve,
SYS_osf_execve,
#endif
#ifdef SYS_fork
SYS_fork,
SYS_fork,
#endif
#ifdef SYS_vfork
SYS_vfork,
SYS_vfork,
#endif
#ifdef SYS_uselib
SYS_uselib,
SYS_uselib,
#endif
#ifdef SYS_unlink
SYS_unlink,
SYS_unlink,
#endif
SYS_unlinkat,
SYS_unlinkat,
#ifdef SYS_chmod
SYS_chmod,
SYS_chmod,
#endif
SYS_fchmod,SYS_fchmodat,
SYS_fchmod, SYS_fchmodat,
#ifdef SYS_chown
SYS_chown,
SYS_chown,
#endif
#ifdef SYS_chown32
SYS_chown32,
SYS_chown32,
#endif
SYS_fchown,
SYS_fchown,
#ifdef SYS_fchown32
SYS_fchown32,
SYS_fchown32,
#endif
#ifdef SYS_lchown
SYS_lchown,
SYS_lchown,
#endif
#ifdef SYS_lchown32
SYS_lchown32,
SYS_lchown32,
#endif
SYS_fchownat,
SYS_fchownat,
#ifdef SYS_symlink
SYS_symlink,
SYS_symlink,
#endif
SYS_symlinkat,
SYS_symlinkat,
#ifdef SYS_link
SYS_link,
SYS_link,
#endif
SYS_linkat,
SYS_linkat,
#ifdef SYS_pkey_mprotect
SYS_pkey_mprotect,
SYS_pkey_mprotect,
#endif
SYS_mprotect,
SYS_truncate,
SYS_mprotect,
SYS_truncate,
#ifdef SYS_truncate64
SYS_truncate64,
SYS_truncate64,
#endif
SYS_ftruncate,
SYS_ftruncate,
#ifdef SYS_ftruncate64
SYS_ftruncate64,
SYS_ftruncate64,
#endif
#ifdef SYS_mknod
SYS_mknod,
SYS_mknod,
#endif
SYS_mknodat,
SYS_mknodat,
#ifdef SYS_mkdir
SYS_mkdir,
SYS_mkdir,
#endif
SYS_mkdirat,
SYS_mkdirat,
#ifdef SYS_rmdir
SYS_rmdir,
SYS_rmdir,
#endif
#ifdef SYS_rename
SYS_rename,
SYS_rename,
#endif
#ifdef SYS_renameat2
SYS_renameat2,
SYS_renameat2,
#endif
#ifdef SYS_renameat
SYS_renameat,
SYS_renameat,
#endif
#ifdef SYS_readdir
SYS_readdir,
SYS_readdir,
#endif
#ifdef SYS_getdents
SYS_getdents,
SYS_getdents,
#endif
#ifdef SYS_getdents64
SYS_getdents64,
SYS_getdents64,
#endif
#ifdef SYS_process_vm_readv
SYS_process_vm_readv,
SYS_process_vm_readv,
#endif
#ifdef SYS_process_vm_writev
SYS_process_vm_writev,
SYS_process_vm_writev,
#endif
#ifdef SYS_process_madvise
SYS_process_madvise,
SYS_process_madvise,
#endif
#ifdef SYS_tkill
SYS_tkill,
SYS_tkill,
#endif
#ifdef SYS_tgkill
SYS_tgkill,
SYS_tgkill,
#endif
SYS_kill, SYS_ptrace
};
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
SYS_kill, SYS_ptrace};
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
{
@@ -159,13 +158,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
static bool set_seccomp(void)
{
#ifdef __X32_SYSCALL_BIT
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
#else
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
#endif
struct sock_filter sockf[SECCOMP_PROG_SIZE];
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf };
int i,idx=0;
struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
int i, idx = 0;
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
#ifdef __X32_SYSCALL_BIT
@@ -178,19 +177,19 @@ static bool set_seccomp(void)
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
#endif
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for(i=0 ; i<BLOCKED_SYSCALL_COUNT ; i++)
/*
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
*/
for (i = 0; i < BLOCKED_SYSCALL_COUNT; i++)
{
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT-i, 0, blocked_syscalls[i]);
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT - i, 0, blocked_syscalls[i]);
}
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); // success case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
}
@@ -201,42 +200,41 @@ bool sec_harden(void)
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
return false;
}
#if ARCH_NR!=0
#if ARCH_NR != 0
if (!set_seccomp())
{
DLOG_PERROR("seccomp");
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
if (errno == EINVAL)
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
return false;
}
#endif
return true;
}
bool checkpcap(uint64_t caps)
{
if (!caps) return true; // no special caps reqd
if (!caps)
return true; // no special caps reqd
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
uint32_t c0 = (uint32_t)caps;
uint32_t c1 = (uint32_t)(caps>>32);
uint32_t c1 = (uint32_t)(caps >> 32);
return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1;
return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1;
}
bool setpcap(uint64_t caps)
{
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
struct __user_cap_data_struct cd[2];
cd[0].effective = cd[0].permitted = (uint32_t)caps;
cd[0].inheritable = 0;
cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32);
cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32);
cd[1].inheritable = 0;
return !capset(&ch,cd);
return !capset(&ch, cd);
}
int getmaxcap(void)
{
@@ -248,18 +246,17 @@ int getmaxcap(void)
fclose(F);
}
return maxcap;
}
bool dropcaps(void)
{
uint64_t caps = (1<<CAP_NET_ADMIN)|(1<<CAP_NET_RAW);
uint64_t caps = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP)))
if (setpcap(caps | (1 << CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
if (prctl(PR_CAPBSET_DROP, cap)<0)
if (prctl(PR_CAPBSET_DROP, cap) < 0)
{
DLOG_ERR("could not drop bound cap %d\n", cap);
DLOG_PERROR("cap_drop_bound");
@@ -291,7 +288,7 @@ bool can_drop_root(void)
{
#ifdef __linux__
// has some caps
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
return checkpcap((1 << CAP_SETUID) | (1 << CAP_SETGID) | (1 << CAP_SETPCAP));
#else
// effective root
return !geteuid();
@@ -308,7 +305,7 @@ bool droproot(uid_t uid, gid_t gid)
}
#endif
// drop all SGIDs
if (setgroups(0,NULL))
if (setgroups(0, NULL))
{
DLOG_PERROR("setgroups");
return false;
@@ -332,24 +329,23 @@ bool droproot(uid_t uid, gid_t gid)
void print_id(void)
{
int i,N;
gid_t g[128];
int i, N;
gid_t g[128];
DLOG_CONDUP("Running as UID=%u GID=",getuid());
N=getgroups(sizeof(g)/sizeof(*g),g);
if (N>0)
{
for(i=0;i<N;i++)
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n",getgid());
DLOG_CONDUP("Running as UID=%u GID=", getuid());
N = getgroups(sizeof(g) / sizeof(*g), g);
if (N > 0)
{
for (i = 0; i < N; i++)
DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
DLOG_CONDUP("\n");
}
else
DLOG_CONDUP("%u\n", getgid());
}
#endif
void daemonize(void)
{
int pid;

View File

@@ -20,67 +20,66 @@ bool dropcaps(void);
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
#define ARCH_NR AUDIT_ARCH_AARCH64
#elif defined(__amd64__)
# define ARCH_NR AUDIT_ARCH_X86_64
#define ARCH_NR AUDIT_ARCH_X86_64
#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_ARM
# else
# define ARCH_NR AUDIT_ARCH_ARMEB
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_ARM
#else
#define ARCH_NR AUDIT_ARCH_ARMEB
#endif
#elif defined(__i386__)
# define ARCH_NR AUDIT_ARCH_I386
#define ARCH_NR AUDIT_ARCH_I386
#elif defined(__mips__)
#if _MIPS_SIM == _MIPS_SIM_ABI32
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL
# else
# define ARCH_NR AUDIT_ARCH_MIPS
# endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_MIPSEL64
# else
# define ARCH_NR AUDIT_ARCH_MIPS64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL
#else
# error "Unsupported mips abi"
#define ARCH_NR AUDIT_ARCH_MIPS
#endif
#elif _MIPS_SIM == _MIPS_SIM_ABI64
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_MIPSEL64
#else
#define ARCH_NR AUDIT_ARCH_MIPS64
#endif
#else
#error "Unsupported MIPS ABI"
#endif
#elif defined(__PPC64__)
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define ARCH_NR AUDIT_ARCH_PPC64LE
# else
# define ARCH_NR AUDIT_ARCH_PPC64
# endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ARCH_NR AUDIT_ARCH_PPC64LE
#else
#define ARCH_NR AUDIT_ARCH_PPC64
#endif
#elif defined(__PPC__)
# define ARCH_NR AUDIT_ARCH_PPC
#define ARCH_NR AUDIT_ARCH_PPC
#elif __riscv && __riscv_xlen == 64
# define ARCH_NR AUDIT_ARCH_RISCV64
#define ARCH_NR AUDIT_ARCH_RISCV64
#else
# error "Platform does not support seccomp filter yet"
#error "Platform does not support seccomp filter yet"
#endif
#endif
#ifndef __CYGWIN__
bool sec_harden(void);
bool can_drop_root(void);

File diff suppressed because it is too large Load Diff

View File

@@ -18,8 +18,7 @@ bool service_run(int argc, char *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] = {
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
{NULL, NULL}
};
{NULL, NULL}};
service_argc = argc;
service_argv = argv;
@@ -76,5 +75,4 @@ void service_main(int argc __attribute__((unused)), char *argv[] __attribute__((
return;
}
#endif

View File

@@ -7,4 +7,3 @@
bool service_run();
#endif

File diff suppressed because it is too large Load Diff