summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-03-23 04:27:49 +0100
committercinap_lenrek <cinap_lenrek@gmx.de>2013-03-23 04:27:49 +0100
commite7131e931351c0f0d8248e55d8c1310b77cb9bc8 (patch)
tree893b37424879a805802727dcc5e5c713927228bf
parent7ae6508d7e804263662fe4595018f3782b483ce3 (diff)
add experimental wpa2/ccmp support
-rw-r--r--sys/src/9/pc/wifi.c334
-rw-r--r--sys/src/cmd/aux/wpa.c38
2 files changed, 291 insertions, 81 deletions
diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c
index 5f3ba83c7..8b3748f71 100644
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -503,6 +503,7 @@ hextob(char *s, char **sp, uchar *b, int n)
static char *ciphers[] = {
[0] "clear",
[TKIP] "tkip",
+ [CCMP] "ccmp",
};
static int
@@ -682,13 +683,25 @@ static void micfinish(MICstate *s, uchar mic[8]);
static uchar pad4[4] = { 0x00, 0x00, 0x00, 0x00, };
+static int setupCCMP(Wkey *k, Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[30], AESstate *as);
+
+void aesCCMencrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s);
+int aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s);
+
static Block*
wifiencrypt(Wifi *, Wnode *wn, Block *b)
{
+ uchar auth[32], seed[16];
u16int tk[8], p1k[5];
- uchar seed[16];
uvlong tsc;
ulong crc;
+ AESstate as;
RC4state rs;
MICstate ms;
Wifipkt *w;
@@ -699,8 +712,6 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b)
k = &wn->txkey[kid];
if(k->cipher == 0)
goto pass;
- if(k->cipher != TKIP || k->len != 32)
- goto drop;
n = wifihdrlen((Wifipkt*)b->rp);
@@ -712,37 +723,63 @@ wifiencrypt(Wifi *, Wnode *wn, Block *b)
b->rp += n;
tsc = ++k->tsc;
- b->rp[0] = tsc>>8;
- b->rp[1] = (b->rp[0] | 0x20) & 0x7f;
- b->rp[2] = tsc;
- b->rp[3] = kid<<6 | 0x20;
- b->rp[4] = tsc>>16;
- b->rp[5] = tsc>>24;
- b->rp[6] = tsc>>32;
- b->rp[7] = tsc>>40;
- b->rp += 8;
-
- micsetup(&ms, k->key+24);
- micupdate(&ms, dstaddr(w), Eaddrlen);
- micupdate(&ms, srcaddr(w), Eaddrlen);
- micupdate(&ms, pad4, 4);
- micupdate(&ms, b->rp, BLEN(b));
- micfinish(&ms, b->wp);
- b->wp += 8;
-
- crc = ethercrc(b->rp, BLEN(b));
- crc = ~crc;
- b->wp[0] = crc;
- b->wp[1] = crc>>8;
- b->wp[2] = crc>>16;
- b->wp[3] = crc>>24;
- b->wp += 4;
-
- tkipk2tk(k->key, tk);
- tkipphase1(tsc >> 16, w->a2, tk, p1k);
- tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
- setupRC4state(&rs, seed, sizeof(seed));
- rc4(&rs, b->rp, BLEN(b));
+
+ switch(k->cipher){
+ case TKIP:
+ b->rp[0] = tsc>>8;
+ b->rp[1] = (b->rp[0] | 0x20) & 0x7f;
+ b->rp[2] = tsc;
+ b->rp[3] = kid<<6 | 0x20;
+ b->rp[4] = tsc>>16;
+ b->rp[5] = tsc>>24;
+ b->rp[6] = tsc>>32;
+ b->rp[7] = tsc>>40;
+ b->rp += 8;
+
+ if(k->len != 32)
+ goto drop;
+ micsetup(&ms, k->key+24);
+ micupdate(&ms, dstaddr(w), Eaddrlen);
+ micupdate(&ms, srcaddr(w), Eaddrlen);
+ micupdate(&ms, pad4, 4);
+ micupdate(&ms, b->rp, BLEN(b));
+ micfinish(&ms, b->wp);
+ b->wp += 8;
+
+ crc = ethercrc(b->rp, BLEN(b));
+ crc = ~crc;
+ b->wp[0] = crc;
+ b->wp[1] = crc>>8;
+ b->wp[2] = crc>>16;
+ b->wp[3] = crc>>24;
+ b->wp += 4;
+
+ tkipk2tk(k->key, tk);
+ tkipphase1(tsc >> 16, w->a2, tk, p1k);
+ tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
+ setupRC4state(&rs, seed, sizeof(seed));
+ rc4(&rs, b->rp, BLEN(b));
+ break;
+ case CCMP:
+ b->rp[0] = tsc;
+ b->rp[1] = tsc>>8;
+ b->rp[2] = 0;
+ b->rp[3] = kid<<6 | 0x20;
+ b->rp[4] = tsc>>16;
+ b->rp[5] = tsc>>24;
+ b->rp[6] = tsc>>32;
+ b->rp[7] = tsc>>40;
+ b->rp += 8;
+
+ if(k->len != 16)
+ goto drop;
+ aesCCMencrypt(2, 8, seed, auth, setupCCMP(k, w, tsc, seed, auth, &as),
+ b->rp, BLEN(b), &as);
+ b->wp += 8;
+ break;
+ default:
+ goto drop;
+ }
b->rp = (uchar*)w;
w->fc[1] |= 0x40;
@@ -757,9 +794,10 @@ drop:
static Block*
wifidecrypt(Wifi *, Wnode *wn, Block *b)
{
- uchar seed[16], mic[8];
+ uchar auth[32], seed[16], mic[8];
u16int tk[8], p1k[5];
RC4state rs;
+ AESstate as;
MICstate ms;
uvlong tsc;
ulong crc;
@@ -773,8 +811,7 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b)
n = wifihdrlen(w);
b->rp += n;
-
- if(BLEN(b) < 8+8+4)
+ if(BLEN(b) < 8+8)
goto drop;
kid = b->rp[3]>>6;
@@ -784,44 +821,60 @@ wifidecrypt(Wifi *, Wnode *wn, Block *b)
kid = 4; /* use peerwise key for non-unicast */
k = &wn->rxkey[kid];
- if(k->cipher != TKIP || k->len != 32)
- goto drop;
-
- tsc = (uvlong)b->rp[7]<<40 |
- (uvlong)b->rp[6]<<32 |
- (uvlong)b->rp[5]<<24 |
- (uvlong)b->rp[4]<<16 |
- (uvlong)b->rp[0]<<8 |
- (uvlong)b->rp[2];
- b->rp += 8;
-
- if(tsc <= k->tsc)
- goto drop;
-
- tkipk2tk(k->key, tk);
- tkipphase1(tsc >> 16, w->a2, tk, p1k);
- tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
- setupRC4state(&rs, seed, sizeof(seed));
- rc4(&rs, b->rp, BLEN(b));
-
- b->wp -= 4;
- crc = (ulong)b->wp[0] |
- (ulong)b->wp[1]<<8 |
- (ulong)b->wp[2]<<16 |
- (ulong)b->wp[3]<<24;
- crc = ~crc;
- if(ethercrc(b->rp, BLEN(b)) != crc)
- goto drop;
+ switch(k->cipher){
+ case TKIP:
+ tsc = (uvlong)b->rp[7]<<40 |
+ (uvlong)b->rp[6]<<32 |
+ (uvlong)b->rp[5]<<24 |
+ (uvlong)b->rp[4]<<16 |
+ (uvlong)b->rp[0]<<8 |
+ (uvlong)b->rp[2];
+ b->rp += 8;
+ if(tsc <= k->tsc || BLEN(b) < 8+4 || k->len != 32)
+ goto drop;
+ tkipk2tk(k->key, tk);
+ tkipphase1(tsc >> 16, w->a2, tk, p1k);
+ tkipphase2(tsc & 0xFFFF, p1k, tk, seed);
+ setupRC4state(&rs, seed, sizeof(seed));
+ rc4(&rs, b->rp, BLEN(b));
+
+ b->wp -= 4;
+ crc = (ulong)b->wp[0] |
+ (ulong)b->wp[1]<<8 |
+ (ulong)b->wp[2]<<16 |
+ (ulong)b->wp[3]<<24;
+ crc = ~crc;
+ if(ethercrc(b->rp, BLEN(b)) != crc)
+ goto drop;
- b->wp -= 8;
- micsetup(&ms, k->key+16);
- micupdate(&ms, dstaddr(w), Eaddrlen);
- micupdate(&ms, srcaddr(w), Eaddrlen);
- micupdate(&ms, pad4, 4);
- micupdate(&ms, b->rp, BLEN(b));
- micfinish(&ms, mic);
- if(memcmp(b->wp, mic, 8) != 0)
+ b->wp -= 8;
+ micsetup(&ms, k->key+16);
+ micupdate(&ms, dstaddr(w), Eaddrlen);
+ micupdate(&ms, srcaddr(w), Eaddrlen);
+ micupdate(&ms, pad4, 4);
+ micupdate(&ms, b->rp, BLEN(b));
+ micfinish(&ms, mic);
+ if(memcmp(b->wp, mic, 8) != 0)
+ goto drop;
+ break;
+ case CCMP:
+ tsc = (uvlong)b->rp[7]<<40 |
+ (uvlong)b->rp[6]<<32 |
+ (uvlong)b->rp[5]<<24 |
+ (uvlong)b->rp[4]<<16 |
+ (uvlong)b->rp[1]<<8 |
+ (uvlong)b->rp[0];
+ b->rp += 8;
+ if(tsc <= k->tsc || k->len != 16)
+ goto drop;
+ b->wp -= 8;
+ if(aesCCMdecrypt(2, 8, seed, auth, setupCCMP(k, w, tsc, seed, auth, &as),
+ b->rp, BLEN(b), &as) != 0)
+ goto drop;
+ break;
+ default:
goto drop;
+ }
k->tsc = tsc;
b->rp -= n;
@@ -1053,3 +1106,138 @@ micfinish(MICstate *s, uchar mic[8])
mic[6] = s->r>>16;
mic[7] = s->r>>24;
}
+
+static uchar*
+putbe(uchar *p, int L, uint v)
+{
+ while(--L >= 0)
+ *p++ = (v >> L*8) & 0xFF;
+ return p;
+}
+
+static void
+xblock(int L, int M, uchar *N, uchar *a, int la, int lm, uchar t[16], AESstate *s)
+{
+ uchar l[8], *p, *x, *e;
+
+ assert(M >= 4 && M <= 16);
+ assert(L >= 2 && L <= 4);
+
+ t[0] = ((la > 0)<<6) | ((M-2)/2)<<3 | (L-1); /* flags */
+ memmove(&t[1], N, 15-L);
+ putbe(&t[16-L], L, lm);
+ aes_encrypt(s->ekey, s->rounds, t, t);
+
+ if(la > 0){
+ assert(la < 0xFF00);
+ for(p = l, e = putbe(l, 2, la), x = t; p < e; x++, p++)
+ *x ^= *p;
+ for(e = a + la; a < e; x = t){
+ for(; a < e && x < &t[16]; x++, a++)
+ *x ^= *a;
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ }
+}
+
+static uchar*
+sblock(int L, uchar *N, uint i, uchar b[16], AESstate *s)
+{
+ b[0] = L-1; /* flags */
+ memmove(&b[1], N, 15-L);
+ putbe(&b[16-L], L, i);
+ aes_encrypt(s->ekey, s->rounds, b, b);
+ return b;
+};
+
+void
+aesCCMencrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s)
+{
+ uchar t[16], b[16], *p, *x;
+ uint i;
+
+ xblock(L, M, N, a, la, lm, t, s);
+
+ for(i = 1; lm >= 16; i++, lm -= 16){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[16]; x++, m++, p++){
+ *x ^= *m;
+ *m ^= *p;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ if(lm > 0){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
+ *x ^= *m;
+ *m ^= *p;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+
+ for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
+ *x ^= *p;
+
+ memmove(m, t, M);
+}
+
+int
+aesCCMdecrypt(int L, int M, uchar *N /* N[15-L] */,
+ uchar *a /* a[la] */, int la,
+ uchar *m /* m[lm+M] */, int lm,
+ AESstate *s)
+{
+ uchar t[16], b[16], *p, *x;
+ uint i;
+
+ xblock(L, M, N, a, la, lm, t, s);
+
+ for(i = 1; lm >= 16; i++, lm -= 16){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[16]; x++, m++, p++){
+ *m ^= *p;
+ *x ^= *m;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+ if(lm > 0){
+ for(p = sblock(L, N, i, b, s), x = t; p < &b[lm]; x++, m++, p++){
+ *m ^= *p;
+ *x ^= *m;
+ }
+ aes_encrypt(s->ekey, s->rounds, t, t);
+ }
+
+ for(p = sblock(L, N, 0, b, s), x = t; p < &b[M]; x++, p++)
+ *x ^= *p;
+
+ return memcmp(m, t, M) != 0;
+}
+
+static int
+setupCCMP(Wkey *k, Wifipkt *w, uvlong tsc, uchar nonce[13], uchar auth[32], AESstate *as)
+{
+ uchar *p;
+
+ setupAESstate(as, k->key, k->len, nil);
+
+ nonce[0] = ((w->fc[0] & 0x0c) == 0x00) << 4;
+ memmove(&nonce[1], w->a2, Eaddrlen);
+ nonce[7] = tsc >> 40;
+ nonce[8] = tsc >> 32;
+ nonce[9] = tsc >> 24;
+ nonce[10] = tsc >> 16;
+ nonce[11] = tsc >> 8;
+ nonce[12] = tsc;
+
+ p = auth;
+ *p++ = (w->fc[0] & (((w->fc[0] & 0x0c) == 0x08) ? 0x0f : 0xff));
+ *p++ = (w->fc[1] & ~0x38) | 0x40;
+ memmove(p, w->a1, Eaddrlen); p += Eaddrlen;
+ memmove(p, w->a2, Eaddrlen); p += Eaddrlen;
+ memmove(p, w->a3, Eaddrlen); p += Eaddrlen;
+ *p++ = w->seq[0] & 0x0f;
+ *p++ = 0;
+
+ return p - auth;
+}
diff --git a/sys/src/cmd/aux/wpa.c b/sys/src/cmd/aux/wpa.c
index 05310b6c1..a65e2723a 100644
--- a/sys/src/cmd/aux/wpa.c
+++ b/sys/src/cmd/aux/wpa.c
@@ -44,6 +44,19 @@ struct Keydescr
uchar data[];
};
+typedef struct Cipher Cipher;
+struct Cipher
+{
+ char *name;
+ int keylen;
+};
+
+Cipher tkip = { "tkip", 32 };
+Cipher ccmp = { "ccmp", 16 };
+
+Cipher *peercipher;
+Cipher *groupcipher;
+
int prompt;
int debug;
int fd, cfd;
@@ -57,9 +70,9 @@ uchar rsnie[] = {
0x30, /* RSN */
0x14, /* length */
0x01, 0x00, /* version 1 */
- 0x00, 0x0F, 0xAC, 0x02, /* group cipher suite TKIP */
+ 0x00, 0x0F, 0xAC, 0x04, /* group cipher suite CCMP */
0x01, 0x00, /* peerwise cipher suite count 1 */
- 0x00, 0x0F, 0xAC, 0x02, /* peerwise cipher suite TKIP */
+ 0x00, 0x0F, 0xAC, 0x04, /* peerwise cipher suite CCMP */
0x01, 0x00, /* authentication suite count 1 */
0x00, 0x0F, 0xAC, 0x02, /* authentication suite PSK */
0x00, 0x00, /* capabilities */
@@ -324,7 +337,7 @@ reply(uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar
void
usage(void)
{
- fprint(2, "%s: [-dp] [-s essid] dev\n", argv0);
+ fprint(2, "%s: [-dp12] [-s essid] dev\n", argv0);
exits("usage");
}
@@ -344,6 +357,8 @@ main(int argc, char *argv[])
/* default is WPA */
rsne = wpaie;
rsnelen = sizeof(wpaie);
+ peercipher = &tkip;
+ groupcipher = &tkip;
ARGBEGIN {
case 'd':
@@ -358,10 +373,14 @@ main(int argc, char *argv[])
case '1':
rsne = wpaie;
rsnelen = sizeof(wpaie);
+ peercipher = &tkip;
+ groupcipher = &tkip;
break;
case '2':
rsne = rsnie;
rsnelen = sizeof(rsnie);
+ peercipher = &ccmp;
+ groupcipher = &ccmp;
break;
default:
usage();
@@ -554,7 +573,8 @@ main(int argc, char *argv[])
if((flags & (Fptk|Fack)) == (Fptk|Fack)){
/* install peerwise receive key */
- if(fprint(cfd, "rxkey %.*H tkip:%.*H@%llux", Eaddrlen, amac, 32, ptk+32, rsc) < 0)
+ if(fprint(cfd, "rxkey %.*H %s:%.*H@%llux", Eaddrlen, amac,
+ peercipher->name, peercipher->keylen, ptk+32, rsc) < 0)
sysfatal("write rxkey: %r");
/* pick random 16bit tsc value for transmit */
@@ -568,7 +588,8 @@ main(int argc, char *argv[])
sleep(100);
/* install peerwise transmit key */
- if(fprint(cfd, "txkey %.*H tkip:%.*H@%llux", Eaddrlen, amac, 32, ptk+32, rsc) < 0)
+ if(fprint(cfd, "txkey %.*H %s:%.*H@%llux", Eaddrlen, amac,
+ peercipher->name, peercipher->keylen, ptk+32, rsc) < 0)
sysfatal("write txkey: %r");
/* reset rsc for group key */
@@ -593,10 +614,11 @@ main(int argc, char *argv[])
} else
continue;
- if(gtklen > 0 && gtkkid != -1){
+ if(gtklen >= groupcipher->keylen && gtkkid != -1){
/* install group key */
- if(fprint(cfd, "rxkey%d %.*H tkip:%.*H@%llux",
- gtkkid, Eaddrlen, amac, gtklen, gtk, rsc) < 0)
+ if(fprint(cfd, "rxkey%d %.*H %s:%.*H@%llux",
+ gtkkid, Eaddrlen, amac,
+ groupcipher->name, groupcipher->keylen, gtk, rsc) < 0)
sysfatal("write rxkey%d: %r", gtkkid);
}
}