From c039b52fc3d7c225fe8b6f88f21df83ac26d5984 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 31 Dec 2017 09:06:42 +0100 Subject: libc: constant time implementation for encode(2) routines, fix base32 the string encoding functions touch secret key material in a bunch of places (devtls, devcap), so make sure we do not leak information by cache timing side channels, making the encoding and decoding routines constant time. we also expose the alphabets through encXchr()/decXchr() functions so caller can find the end of a encoded string before calling decode function (for libmp). the base32 encoding was broken in several ways. inputs lengths of len%5 == [2,3,4] had output truncated and it was using non-standard alphabet. documenting the alphabet change in the manpage. --- sys/src/libc/port/encodefmt.c | 13 ++++--- sys/src/libc/port/u16.c | 38 +++++++++++++------ sys/src/libc/port/u32.c | 80 +++++++++++++++++++++++++--------------- sys/src/libc/port/u64.c | 85 ++++++++++++++++++++++--------------------- 4 files changed, 129 insertions(+), 87 deletions(-) (limited to 'sys/src/libc') diff --git a/sys/src/libc/port/encodefmt.c b/sys/src/libc/port/encodefmt.c index 721a58c9f..92cc4154a 100644 --- a/sys/src/libc/port/encodefmt.c +++ b/sys/src/libc/port/encodefmt.c @@ -48,17 +48,14 @@ encodefmt(Fmt *f) // convert out = buf; switch(f->r){ - case '<': - rv = enc32(out, len, b, ilen); - break; case '[': rv = enc64(out, len, b, ilen); break; + case '<': + rv = enc32(out, len, b, ilen); + break; case 'H': rv = enc16(out, len, b, ilen); - if(rv >= 0 && (f->flags & FmtLong)) - for(p = buf; *p; p++) - *p = tolower(*p); break; default: rv = -1; @@ -67,6 +64,10 @@ encodefmt(Fmt *f) if(rv < 0) goto error; + if((f->flags & FmtLong) != 0 && f->r != '[') + for(p = buf; *p; p++) + *p = tolower(*p); + fmtstrcpy(f, buf); if(buf != obuf) free(buf); diff --git a/sys/src/libc/port/u16.c b/sys/src/libc/port/u16.c index 4e1637120..60ffa72c8 100644 --- a/sys/src/libc/port/u16.c +++ b/sys/src/libc/port/u16.c @@ -1,6 +1,28 @@ #include #include -static char t16e[] = "0123456789ABCDEF"; + +#define between(x,min,max) (((min-1-x) & (x-max-1))>>8) + +int +enc16chr(int o) +{ + int c; + + c = between(o, 0, 9) & ('0'+o); + c |= between(o, 10, 15) & ('A'+(o-10)); + return c; +} + +int +dec16chr(int c) +{ + int o; + + o = between(c, '0', '9') & (1+(c-'0')); + o |= between(c, 'A', 'F') & (1+10+(c-'A')); + o |= between(c, 'a', 'f') & (1+10+(c-'a')); + return o-1; +} int dec16(uchar *out, int lim, char *in, int n) @@ -10,14 +32,8 @@ dec16(uchar *out, int lim, char *in, int n) uchar *eout = out + lim; while(n-- > 0){ - c = *in++; - if('0' <= c && c <= '9') - c = c - '0'; - else if('a' <= c && c <= 'z') - c = c - 'a' + 10; - else if('A' <= c && c <= 'Z') - c = c - 'A' + 10; - else + c = dec16chr(*in++); + if(c < 0) continue; w = (w<<4) + c; i++; @@ -44,8 +60,8 @@ enc16(char *out, int lim, uchar *in, int n) c = *in++; if(out + 2 >= eout) goto exhausted; - *out++ = t16e[c>>4]; - *out++ = t16e[c&0xf]; + *out++ = enc16chr(c>>4); + *out++ = enc16chr(c&15); } exhausted: *out = 0; diff --git a/sys/src/libc/port/u32.c b/sys/src/libc/port/u32.c index 7423984a2..9ad9eb781 100644 --- a/sys/src/libc/port/u32.c +++ b/sys/src/libc/port/u32.c @@ -1,21 +1,44 @@ #include #include +#define between(x,min,max) (((min-1-x) & (x-max-1))>>8) + +int +enc32chr(int o) +{ + int c; + + c = between(o, 0, 25) & ('A'+o); + c |= between(o, 26, 31) & ('2'+(o-26)); + return c; +} + +int +dec32chr(int c) +{ + int o; + + o = between(c, 'A', 'Z') & (1+(c-'A')); + o |= between(c, 'a', 'z') & (1+(c-'a')); + o |= between(c, '2', '7') & (1+26+(c-'2')); + return o-1; +} + int dec32(uchar *dest, int ndest, char *src, int nsrc) { - char *s, *tab; uchar *start; - int i, u[8]; + int i, j, u[8]; if(ndest+1 < (5*nsrc+7)/8) return -1; start = dest; - tab = "23456789abcdefghijkmnpqrstuvwxyz"; while(nsrc>=8){ for(i=0; i<8; i++){ - s = strchr(tab,(int)src[i]); - u[i] = s ? s-tab : 0; + j = dec32chr(src[i]); + if(j < 0) + j = 0; + u[i] = j; } *dest++ = (u[0]<<3) | (0x7 & (u[1]>>2)); *dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4)); @@ -29,8 +52,10 @@ dec32(uchar *dest, int ndest, char *src, int nsrc) if(nsrc == 1 || nsrc == 3 || nsrc == 6) return -1; for(i=0; i>2)); if(nsrc == 2) @@ -50,60 +75,57 @@ out: int enc32(char *dest, int ndest, uchar *src, int nsrc) { - char *tab, *start; + char *start; int j; - if(ndest <= (8*nsrc+4)/5 ) + if(ndest <= (8*nsrc+4)/5) return -1; start = dest; - tab = "23456789abcdefghijkmnpqrstuvwxyz"; while(nsrc>=5){ j = (0x1f & (src[0]>>3)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1f & (src[1]>>1)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1f & (src[3]>>2)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1f & (src[4])); - *dest++ = tab[j]; + *dest++ = enc32chr(j); src += 5; nsrc -= 5; } if(nsrc){ j = (0x1f & (src[0]>>3)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1c & (src[0]<<2)); if(nsrc == 1) goto out; j |= (0x03 & (src[1]>>6)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1f & (src[1]>>1)); - if(nsrc == 2) - goto out; - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x10 & (src[1]<<4)); - if(nsrc == 3) + if(nsrc == 2) goto out; j |= (0x0f & (src[2]>>4)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1e & (src[2]<<1)); - if(nsrc == 4) + if(nsrc == 3) goto out; j |= (0x01 & (src[3]>>7)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x1f & (src[3]>>2)); - *dest++ = tab[j]; + *dest++ = enc32chr(j); j = (0x18 & (src[3]<<3)); out: - *dest++ = tab[j]; + *dest++ = enc32chr(j); } *dest = 0; return dest-start; diff --git a/sys/src/libc/port/u64.c b/sys/src/libc/port/u64.c index 432cec899..44f716fbe 100644 --- a/sys/src/libc/port/u64.c +++ b/sys/src/libc/port/u64.c @@ -1,29 +1,33 @@ #include #include -enum { - INVAL= 255 -}; +#define between(x,min,max) (((min-1-x) & (x-max-1))>>8) -static uchar t64d[256] = { - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, 62,INVAL,INVAL,INVAL, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL, - INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL -}; -static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +int +enc64chr(int o) +{ + int c; + + c = between(o, 0, 25) & ('A'+o); + c |= between(o, 26, 51) & ('a'+(o-26)); + c |= between(o, 52, 61) & ('0'+(o-52)); + c |= between(o, 62, 62) & ('+'); + c |= between(o, 63, 63) & ('/'); + return c; +} + +int +dec64chr(int c) +{ + int o; + + o = between(c, 'A', 'Z') & (1+(c-'A')); + o |= between(c, 'a', 'z') & (1+26+(c-'a')); + o |= between(c, '0', '9') & (1+52+(c-'0')); + o |= between(c, '+', '+') & (1+62); + o |= between(c, '/', '/') & (1+63); + return o-1; +} int dec64(uchar *out, int lim, char *in, int n) @@ -36,9 +40,8 @@ dec64(uchar *out, int lim, char *in, int n) b24 = 0; i = 0; while(n-- > 0){ - - c = t64d[*(uchar*)in++]; - if(c == INVAL) + c = dec64chr(*in++); + if(c < 0) continue; switch(i){ case 0: @@ -58,8 +61,8 @@ dec64(uchar *out, int lim, char *in, int n) *out++ = b24>>16; *out++ = b24>>8; *out++ = b24; - i = -1; - break; + i = 0; + continue; } i++; } @@ -89,34 +92,34 @@ enc64(char *out, int lim, uchar *in, int n) char *e = out + lim; for(i = n/3; i > 0; i--){ - b24 = (*in++)<<16; - b24 |= (*in++)<<8; + b24 = *in++<<16; + b24 |= *in++<<8; b24 |= *in++; if(out + 4 >= e) goto exhausted; - *out++ = t64e[(b24>>18)]; - *out++ = t64e[(b24>>12)&0x3f]; - *out++ = t64e[(b24>>6)&0x3f]; - *out++ = t64e[(b24)&0x3f]; + *out++ = enc64chr(b24>>18); + *out++ = enc64chr((b24>>12)&0x3f); + *out++ = enc64chr((b24>>6)&0x3f); + *out++ = enc64chr(b24&0x3f); } switch(n%3){ case 2: - b24 = (*in++)<<16; - b24 |= (*in)<<8; + b24 = *in++<<16; + b24 |= *in<<8; if(out + 4 >= e) goto exhausted; - *out++ = t64e[(b24>>18)]; - *out++ = t64e[(b24>>12)&0x3f]; - *out++ = t64e[(b24>>6)&0x3f]; + *out++ = enc64chr(b24>>18); + *out++ = enc64chr((b24>>12)&0x3f); + *out++ = enc64chr((b24>>6)&0x3f); *out++ = '='; break; case 1: - b24 = (*in)<<16; + b24 = *in<<16; if(out + 4 >= e) goto exhausted; - *out++ = t64e[(b24>>18)]; - *out++ = t64e[(b24>>12)&0x3f]; + *out++ = enc64chr(b24>>18); + *out++ = enc64chr((b24>>12)&0x3f); *out++ = '='; *out++ = '='; break; -- cgit v1.2.3