diff --git a/.gitignore b/.gitignore index 3d52af52..d3224335 100644 --- a/.gitignore +++ b/.gitignore @@ -38,9 +38,13 @@ m4/lt~obsolete.m4 man/*.html man/Makefile.in missing +src/libsodium/curvecp/curvecpclient +src/libsodium/curvecp/curvecpmakekey +src/libsodium/curvecp/curvecpmessage +src/libsodium/curvecp/curvecpprintkey +src/libsodium/curvecp/curvecpserver src/libsodium/include/sodium/version.h stamp-* -testing test/default/*.res test/default/*.trs test/default/auth @@ -76,3 +80,4 @@ test/default/stream test/default/stream2 test/default/stream3 test/default/stream4 +testing diff --git a/configure.ac b/configure.ac index 932c24ec..f01df625 100644 --- a/configure.ac +++ b/configure.ac @@ -227,6 +227,7 @@ AH_VERBATIM([NDEBUG], [/* Never ever ignore assertions */ AC_CONFIG_FILES([Makefile src/Makefile src/libsodium/Makefile + src/libsodium/curvecp/Makefile src/libsodium/include/Makefile src/libsodium/include/sodium/version.h test/default/Makefile diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index 2a87f149..636f6525 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -93,4 +93,5 @@ libsodium_la_CPPFLAGS = \ -I$(top_srcdir)/src/libsodium/include/sodium SUBDIRS = \ + curvecp \ include diff --git a/src/libsodium/curvecp/Makefile.am b/src/libsodium/curvecp/Makefile.am new file mode 100644 index 00000000..64dd1fea --- /dev/null +++ b/src/libsodium/curvecp/Makefile.am @@ -0,0 +1,97 @@ + +noinst_LTLIBRARIES = \ + libcurvecp.la + +libcurvecp_la_SOURCES = \ + blocking.c \ + blocking.h \ + byte.h \ + byte_copy.c \ + byte_isequal.c \ + byte_zero.c \ + crypto_block.c \ + crypto_block.h \ + die.c \ + die.h \ + e.c \ + e.h \ + hexparse.c \ + hexparse.h \ + load.c \ + load.h \ + nameparse.c \ + nameparse.h \ + nanoseconds.c \ + nanoseconds.h \ + open.h \ + open_cwd.c \ + open_lock.c \ + open_pipe.c \ + open_read.c \ + open_write.c \ + portparse.c \ + portparse.h \ + randommod.c \ + randommod.h \ + safenonce.c \ + safenonce.h \ + savesync.c \ + savesync.h \ + socket.h \ + socket_bind.c \ + socket_recv.c \ + socket_send.c \ + socket_udp.c \ + uint16_pack.c \ + uint16_pack.h \ + uint16_unpack.c \ + uint16_unpack.h \ + uint32_pack.c \ + uint32_pack.h \ + uint32_unpack.c \ + uint32_unpack.h \ + uint64_pack.c \ + uint64_pack.h \ + uint64_unpack.c \ + uint64_unpack.h \ + writeall.c \ + writeall.h + +libcurvecp_la_LIBADD = \ + $(top_srcdir)/src/libsodium/libsodium.la + +libcurvecp_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -no-undefined + +libcurvecp_la_CPPFLAGS = \ + $(LTDLINCL) \ + -I$(top_srcdir)/src/libsodium/include/sodium + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/libsodium/include/sodium + +LDADD = \ + libcurvecp.la + +bin_PROGRAMS = \ + curvecpprintkey \ + curvecpmakekey \ + curvecpclient \ + curvecpserver \ + curvecpmessage + +curvecpprintkey_SOURCES = \ + curvecpprintkey.c + +curvecpmakekey_SOURCES = \ + curvecpmakekey.c + +curvecpclient_SOURCES = \ + curvecpclient.c + +curvecpserver_SOURCES = \ + curvecpserver.c + +curvecpmessage_SOURCES = \ + curvecpmessage.c diff --git a/src/libsodium/curvecp/blocking.c b/src/libsodium/curvecp/blocking.c new file mode 100644 index 00000000..1594259c --- /dev/null +++ b/src/libsodium/curvecp/blocking.c @@ -0,0 +1,12 @@ +#include +#include "blocking.h" + +void blocking_enable(int fd) +{ + fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); +} + +void blocking_disable(int fd) +{ + fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); +} diff --git a/src/libsodium/curvecp/blocking.h b/src/libsodium/curvecp/blocking.h new file mode 100644 index 00000000..9ba08a5e --- /dev/null +++ b/src/libsodium/curvecp/blocking.h @@ -0,0 +1,7 @@ +#ifndef BLOCKING_H +#define BLOCKING_H + +extern void blocking_enable(int); +extern void blocking_disable(int); + +#endif diff --git a/src/libsodium/curvecp/byte.h b/src/libsodium/curvecp/byte.h new file mode 100644 index 00000000..5dbfbd96 --- /dev/null +++ b/src/libsodium/curvecp/byte.h @@ -0,0 +1,8 @@ +#ifndef BYTE_H +#define BYTE_H + +extern void byte_zero(void *,long long); +extern void byte_copy(void *,long long,const void *); +extern int byte_isequal(const void *,long long,const void *); + +#endif diff --git a/src/libsodium/curvecp/byte_copy.c b/src/libsodium/curvecp/byte_copy.c new file mode 100644 index 00000000..55f446a4 --- /dev/null +++ b/src/libsodium/curvecp/byte_copy.c @@ -0,0 +1,8 @@ +#include "byte.h" + +void byte_copy(void *yv,long long ylen,const void *xv) +{ + char *y = yv; + const char *x = xv; + while (ylen > 0) { *y++ = *x++; --ylen; } +} diff --git a/src/libsodium/curvecp/byte_isequal.c b/src/libsodium/curvecp/byte_isequal.c new file mode 100644 index 00000000..625d361e --- /dev/null +++ b/src/libsodium/curvecp/byte_isequal.c @@ -0,0 +1,10 @@ +#include "byte.h" + +int byte_isequal(const void *yv,long long ylen,const void *xv) +{ + const unsigned char *y = yv; + const unsigned char *x = xv; + unsigned char diff = 0; + while (ylen > 0) { diff |= (*y++ ^ *x++); --ylen; } + return (256 - (unsigned int) diff) >> 8; +} diff --git a/src/libsodium/curvecp/byte_zero.c b/src/libsodium/curvecp/byte_zero.c new file mode 100644 index 00000000..bdc1f799 --- /dev/null +++ b/src/libsodium/curvecp/byte_zero.c @@ -0,0 +1,7 @@ +#include "byte.h" + +void byte_zero(void *yv,long long ylen) +{ + char *y = yv; + while (ylen > 0) { *y++ = 0; --ylen; } +} diff --git a/src/libsodium/curvecp/crypto_block.c b/src/libsodium/curvecp/crypto_block.c new file mode 100644 index 00000000..5c7cf35e --- /dev/null +++ b/src/libsodium/curvecp/crypto_block.c @@ -0,0 +1,35 @@ +#include "crypto_block.h" +#include "crypto_uint64.h" +#include "uint64_unpack.h" +#include "uint64_pack.h" + +/* +TEA with double-size words. +XXX: Switch to crypto_block_aes256. +XXX: Build crypto_stream_aes256 on top of crypto_block_aes256. +*/ + +int crypto_block( + unsigned char *out, + const unsigned char *in, + const unsigned char *k +) +{ + crypto_uint64 v0 = uint64_unpack(in + 0); + crypto_uint64 v1 = uint64_unpack(in + 8); + crypto_uint64 k0 = uint64_unpack(k + 0); + crypto_uint64 k1 = uint64_unpack(k + 8); + crypto_uint64 k2 = uint64_unpack(k + 16); + crypto_uint64 k3 = uint64_unpack(k + 24); + crypto_uint64 sum = 0; + crypto_uint64 delta = 0x9e3779b97f4a7c15; + int i; + for (i = 0;i < 32;++i) { + sum += delta; + v0 += ((v1<<7) + k0) ^ (v1 + sum) ^ ((v1>>12) + k1); + v1 += ((v0<<16) + k2) ^ (v0 + sum) ^ ((v0>>8) + k3); + } + uint64_pack(out + 0,v0); + uint64_pack(out + 8,v1); + return 0; +} diff --git a/src/libsodium/curvecp/crypto_block.h b/src/libsodium/curvecp/crypto_block.h new file mode 100644 index 00000000..f13620c4 --- /dev/null +++ b/src/libsodium/curvecp/crypto_block.h @@ -0,0 +1,4 @@ +#define crypto_block_BYTES 16 +#define crypto_block_KEYBYTES 32 + +extern int crypto_block(unsigned char *,const unsigned char *,const unsigned char *); diff --git a/src/libsodium/curvecp/curvecpclient.c b/src/libsodium/curvecp/curvecpclient.c new file mode 100644 index 00000000..00793f00 --- /dev/null +++ b/src/libsodium/curvecp/curvecpclient.c @@ -0,0 +1,476 @@ +#include +#include +#include +#include +#include +#include +#include +#include "e.h" +#include "die.h" +#include "load.h" +#include "open.h" +#include "byte.h" +#include "socket.h" +#include "uint64_pack.h" +#include "uint64_unpack.h" +#include "nanoseconds.h" +#include "hexparse.h" +#include "nameparse.h" +#include "portparse.h" +#include "writeall.h" +#include "safenonce.h" +#include "randommod.h" + +long long recent = 0; + +#define NUMIP 8 +long long hellowait[NUMIP] = { + 1000000000 +, 1500000000 +, 2250000000 +, 3375000000 +, 5062500000 +, 7593750000 +, 11390625000 +, 17085937500 +} ; + +#include "crypto_box.h" +#include "randombytes.h" +#if crypto_box_PUBLICKEYBYTES != 32 +error! +#endif +#if crypto_box_NONCEBYTES != 24 +error! +#endif +#if crypto_box_BOXZEROBYTES != 16 +error! +#endif +#if crypto_box_ZEROBYTES != 32 +error! +#endif +#if crypto_box_BEFORENMBYTES != 32 +error! +#endif + +int flagverbose = 1; + +#define USAGE "\ +curvecpclient: how to use:\n\ +curvecpclient: -q (optional): no error messages\n\ +curvecpclient: -Q (optional): print error messages (default)\n\ +curvecpclient: -v (optional): print extra information\n\ +curvecpclient: -c keydir (optional): use this public-key directory\n\ +curvecpclient: sname: server's name\n\ +curvecpclient: pk: server's public key\n\ +curvecpclient: ip: server's IP address\n\ +curvecpclient: port: server's UDP port\n\ +curvecpclient: ext: server's extension\n\ +curvecpclient: prog: run this client\n\ +" + +void die_usage(const char *s) +{ + if (s) die_4(100,USAGE,"curvecpclient: fatal: ",s,"\n"); + die_1(100,USAGE); +} + +void die_fatal(const char *trouble,const char *d,const char *fn) +{ + /* XXX: clean up? OS can do it much more reliably */ + if (!flagverbose) die_0(111); + if (d) { + if (fn) die_9(111,"curvecpclient: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n"); + die_7(111,"curvecpclient: fatal: ",trouble," ",d,": ",e_str(errno),"\n"); + } + if (errno) die_5(111,"curvecpclient: fatal: ",trouble,": ",e_str(errno),"\n"); + die_3(111,"curvecpclient: fatal: ",trouble,"\n"); +} + +int multiipparse(unsigned char *y,const char *x) +{ + long long pos; + long long pos2; + long long ynum; + long long ypos; + long long j; + long long k; + long long d; + for (j = 0;j < 4 * NUMIP;++j) y[j] = 0; + ynum = 0; + while (ynum < 1000) { + ++ynum; + ypos = randommod(ynum); + for (k = 0;k < 4;++k) { + pos = ypos * 4 + k; + pos2 = (ynum - 1) * 4 + k; + if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos]; + d = 0; + for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0'); + if (j == 0) return 0; + x += j; + if (pos >= 0 && pos < 4 * NUMIP) y[pos] = d; + if (k < 3) { + if (*x != '.') return 0; + ++x; + } + } + if (!*x) break; + if (*x != ',') return 0; + ++x; + } + /* if fewer than 8 IP addresses, cycle through them: */ + pos = 0; + pos2 = ynum * 4; + while (pos2 < 4 * NUMIP) { + if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos]; + ++pos2; + ++pos; + } + return 1; +} + + +/* routing to the client: */ +unsigned char clientextension[16]; +long long clientextensionloadtime = 0; +int udpfd = -1; + +void clientextension_init(void) +{ + if (recent >= clientextensionloadtime) { + clientextensionloadtime = recent + 30000000000LL; + if (load("/etc/curvecpextension",clientextension,16) == -1) + if (errno == ENOENT || errno == ENAMETOOLONG) + byte_zero(clientextension,16); + } +} + + +/* client security: */ +char *keydir = 0; +unsigned char clientlongtermpk[32]; +unsigned char clientlongtermsk[32]; +unsigned char clientshorttermpk[32]; +unsigned char clientshorttermsk[32]; +crypto_uint64 clientshorttermnonce; +unsigned char vouch[64]; + +void clientshorttermnonce_update(void) +{ + ++clientshorttermnonce; + if (clientshorttermnonce) return; + errno = EPROTO; + die_fatal("nonce space expired",0,0); +} + +/* routing to the server: */ +unsigned char serverip[4 * NUMIP]; +unsigned char serverport[2]; +unsigned char serverextension[16]; + +/* server security: */ +unsigned char servername[256]; +unsigned char serverlongtermpk[32]; +unsigned char servershorttermpk[32]; +unsigned char servercookie[96]; + +/* shared secrets: */ +unsigned char clientshortserverlong[32]; +unsigned char clientshortservershort[32]; +unsigned char clientlongserverlong[32]; + +unsigned char allzero[128] = {0}; + +unsigned char nonce[24]; +unsigned char text[2048]; + +unsigned char packet[4096]; +unsigned char packetip[4]; +unsigned char packetport[2]; +crypto_uint64 packetnonce; +int flagreceivedmessage = 0; +crypto_uint64 receivednonce = 0; + +struct pollfd p[3]; + +int fdwd = -1; + +int tochild[2] = {-1,-1}; +int fromchild[2] = {-1,-1}; +pid_t child = -1; +int childstatus = 0; + +unsigned char childbuf[4096]; +long long childbuflen = 0; +unsigned char childmessage[2048]; +long long childmessagelen = 0; + +int main(int argc,char **argv) +{ + long long hellopackets; + long long r; + long long nextaction; + + signal(SIGPIPE,SIG_IGN); + + if (!argv[0]) die_usage(0); + for (;;) { + char *x; + if (!argv[1]) break; + if (argv[1][0] != '-') break; + x = *++argv; + if (x[0] == '-' && x[1] == 0) break; + if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; + while (*++x) { + if (*x == 'q') { flagverbose = 0; continue; } + if (*x == 'Q') { flagverbose = 1; continue; } + if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } + if (*x == 'c') { + if (x[1]) { keydir = x + 1; break; } + if (argv[1]) { keydir = *++argv; break; } + } + die_usage(0); + } + } + if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots"); + if (!hexparse(serverlongtermpk,32,*++argv)) die_usage("pk must be exactly 64 hex characters"); + if (!multiipparse(serverip,*++argv)) die_usage("ip must be a comma-separated series of IPv4 addresses"); + if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535"); + if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters"); + if (!*++argv) die_usage("missing prog"); + + for (;;) { + r = open_read("/dev/null"); + if (r == -1) die_fatal("unable to open /dev/null",0,0); + if (r > 9) { close(r); break; } + } + + if (keydir) { + fdwd = open_cwd(); + if (fdwd == -1) die_fatal("unable to open current working directory",0,0); + if (chdir(keydir) == -1) die_fatal("unable to change to directory",keydir,0); + if (load("publickey",clientlongtermpk,sizeof clientlongtermpk) == -1) die_fatal("unable to read public key from",keydir,0); + if (load(".expertsonly/secretkey",clientlongtermsk,sizeof clientlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0); + } else { + crypto_box_keypair(clientlongtermpk,clientlongtermsk); + } + + crypto_box_keypair(clientshorttermpk,clientshorttermsk); + clientshorttermnonce = randommod(281474976710656LL); + crypto_box_beforenm(clientshortserverlong,serverlongtermpk,clientshorttermsk); + crypto_box_beforenm(clientlongserverlong,serverlongtermpk,clientlongtermsk); + + udpfd = socket_udp(); + if (udpfd == -1) die_fatal("unable to create socket",0,0); + + for (hellopackets = 0;hellopackets < NUMIP;++hellopackets) { + recent = nanoseconds(); + + /* send a Hello packet: */ + + clientextension_init(); + + clientshorttermnonce_update(); + byte_copy(nonce,16,"CurveCP-client-H"); + uint64_pack(nonce + 16,clientshorttermnonce); + + byte_copy(packet,8,"QvnQ5XlH"); + byte_copy(packet + 8,16,serverextension); + byte_copy(packet + 24,16,clientextension); + byte_copy(packet + 40,32,clientshorttermpk); + byte_copy(packet + 72,64,allzero); + byte_copy(packet + 136,8,nonce + 16); + crypto_box_afternm(text,allzero,96,nonce,clientshortserverlong); + byte_copy(packet + 144,80,text + 16); + + socket_send(udpfd,packet,224,serverip + 4 * hellopackets,serverport); + + nextaction = recent + hellowait[hellopackets] + randommod(hellowait[hellopackets]); + + for (;;) { + long long timeout = nextaction - recent; + if (timeout <= 0) break; + p[0].fd = udpfd; + p[0].events = POLLIN; + if (poll(p,1,timeout / 1000000 + 1) < 0) p[0].revents = 0; + + do { /* try receiving a Cookie packet: */ + if (!p[0].revents) break; + r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport); + if (r != 200) break; + if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) & + byte_isequal(packetport,2,serverport) & + byte_isequal(packet,8,"RL3aNMXK") & + byte_isequal(packet + 8,16,clientextension) & + byte_isequal(packet + 24,16,serverextension) + )) break; + byte_copy(nonce,8,"CurveCPK"); + byte_copy(nonce + 8,16,packet + 40); + byte_zero(text,16); + byte_copy(text + 16,144,packet + 56); + if (crypto_box_open_afternm(text,text,160,nonce,clientshortserverlong)) break; + byte_copy(servershorttermpk,32,text + 32); + byte_copy(servercookie,96,text + 64); + byte_copy(serverip,4,serverip + 4 * hellopackets); + goto receivedcookie; + } while (0); + + recent = nanoseconds(); + } + } + + errno = ETIMEDOUT; die_fatal("no response from server",0,0); + + receivedcookie: + + crypto_box_beforenm(clientshortservershort,servershorttermpk,clientshorttermsk); + + byte_copy(nonce,8,"CurveCPV"); + if (keydir) { + if (safenonce(nonce + 8,0) == -1) die_fatal("nonce-generation disaster",0,0); + } else { + randombytes(nonce + 8,16); + } + + byte_zero(text,32); + byte_copy(text + 32,32,clientshorttermpk); + crypto_box_afternm(text,text,64,nonce,clientlongserverlong); + byte_copy(vouch,16,nonce + 8); + byte_copy(vouch + 16,48,text + 16); + + /* server is responding, so start child: */ + + if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0); + if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0); + + child = fork(); + if (child == -1) die_fatal("unable to fork",0,0); + if (child == 0) { + if (keydir) if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0); + close(8); + if (dup(tochild[0]) != 8) die_fatal("unable to dup",0,0); + close(9); + if (dup(fromchild[1]) != 9) die_fatal("unable to dup",0,0); + /* XXX: set up environment variables */ + signal(SIGPIPE,SIG_DFL); + execvp(*argv,argv); + die_fatal("unable to run",*argv,0); + } + + close(fromchild[1]); + close(tochild[0]); + + + for (;;) { + p[0].fd = udpfd; + p[0].events = POLLIN; + p[1].fd = fromchild[0]; + p[1].events = POLLIN; + + if (poll(p,2,-1) < 0) { + p[0].revents = 0; + p[1].revents = 0; + } + + do { /* try receiving a Message packet: */ + if (!p[0].revents) break; + r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport); + if (r < 80) break; + if (r > 1152) break; + if (r & 15) break; + packetnonce = uint64_unpack(packet + 40); + if (flagreceivedmessage && packetnonce <= receivednonce) break; + if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) & + byte_isequal(packetport,2,serverport) & + byte_isequal(packet,8,"RL3aNMXM") & + byte_isequal(packet + 8,16,clientextension) & + byte_isequal(packet + 24,16,serverextension) + )) break; + byte_copy(nonce,16,"CurveCP-server-M"); + byte_copy(nonce + 16,8,packet + 40); + byte_zero(text,16); + byte_copy(text + 16,r - 48,packet + 48); + if (crypto_box_open_afternm(text,text,r - 32,nonce,clientshortservershort)) break; + + if (!flagreceivedmessage) { + flagreceivedmessage = 1; + randombytes(clientlongtermpk,sizeof clientlongtermpk); + randombytes(vouch,sizeof vouch); + randombytes(servername,sizeof servername); + randombytes(servercookie,sizeof servercookie); + } + + receivednonce = packetnonce; + text[31] = (r - 64) >> 4; + /* child is responsible for reading all data immediately, so we won't block: */ + if (writeall(tochild[1],text + 31,r - 63) == -1) goto done; + } while (0); + + do { /* try receiving data from child: */ + long long i; + if (!p[1].revents) break; + r = read(fromchild[0],childbuf,sizeof childbuf); + if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; + if (r <= 0) goto done; + childbuflen = r; + for (i = 0;i < childbuflen;++i) { + if (childmessagelen < 0) goto done; + if (childmessagelen >= sizeof childmessage) goto done; + childmessage[childmessagelen++] = childbuf[i]; + if (childmessage[0] & 128) goto done; + if (childmessagelen == 1 + 16 * (unsigned long long) childmessage[0]) { + clientextension_init(); + clientshorttermnonce_update(); + uint64_pack(nonce + 16,clientshorttermnonce); + if (flagreceivedmessage) { + r = childmessagelen - 1; + if (r < 16) goto done; + if (r > 1088) goto done; + byte_copy(nonce,16,"CurveCP-client-M"); + byte_zero(text,32); + byte_copy(text + 32,r,childmessage + 1); + crypto_box_afternm(text,text,r + 32,nonce,clientshortservershort); + byte_copy(packet,8,"QvnQ5XlM"); + byte_copy(packet + 8,16,serverextension); + byte_copy(packet + 24,16,clientextension); + byte_copy(packet + 40,32,clientshorttermpk); + byte_copy(packet + 72,8,nonce + 16); + byte_copy(packet + 80,r + 16,text + 16); + socket_send(udpfd,packet,r + 96,serverip,serverport); + } else { + r = childmessagelen - 1; + if (r < 16) goto done; + if (r > 640) goto done; + byte_copy(nonce,16,"CurveCP-client-I"); + byte_zero(text,32); + byte_copy(text + 32,32,clientlongtermpk); + byte_copy(text + 64,64,vouch); + byte_copy(text + 128,256,servername); + byte_copy(text + 384,r,childmessage + 1); + crypto_box_afternm(text,text,r + 384,nonce,clientshortservershort); + byte_copy(packet,8,"QvnQ5XlI"); + byte_copy(packet + 8,16,serverextension); + byte_copy(packet + 24,16,clientextension); + byte_copy(packet + 40,32,clientshorttermpk); + byte_copy(packet + 72,96,servercookie); + byte_copy(packet + 168,8,nonce + 16); + byte_copy(packet + 176,r + 368,text + 16); + socket_send(udpfd,packet,r + 544,serverip,serverport); + } + childmessagelen = 0; + } + } + } while (0); + } + + + done: + + do { + r = waitpid(child,&childstatus,0); + } while (r == -1 && errno == EINTR); + + if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } + return WEXITSTATUS(childstatus); +} diff --git a/src/libsodium/curvecp/curvecpmakekey.c b/src/libsodium/curvecp/curvecpmakekey.c new file mode 100644 index 00000000..dfa181b0 --- /dev/null +++ b/src/libsodium/curvecp/curvecpmakekey.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include "die.h" +#include "e.h" +#include "savesync.h" +#include "randombytes.h" +#include "crypto_box.h" + +void die_usage(void) +{ + die_1(111,"curvecpmakekey: usage: curvecpmakekey keydir\n"); +} + +void die_fatal(const char *trouble,const char *d,const char *fn) +{ + if (fn) die_9(111,"curvecpmakekey: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n"); + die_7(111,"curvecpmakekey: fatal: ",trouble," ",d,": ",e_str(errno),"\n"); +} + +unsigned char pk[crypto_box_PUBLICKEYBYTES]; +unsigned char sk[crypto_box_SECRETKEYBYTES]; +unsigned char lock[1]; +unsigned char noncekey[32]; +unsigned char noncecounter[8]; + +void create(const char *d,const char *fn,const unsigned char *x,long long xlen) +{ + if (savesync(fn,x,xlen) == -1) die_fatal("unable to create",d,fn); +} + +int main(int argc,char **argv) +{ + char *d; + + if (!argv[0]) die_usage(); + if (!argv[1]) die_usage(); + d = argv[1]; + + umask(022); + if (mkdir(d,0755) == -1) die_fatal("unable to create directory",d,0); + if (chdir(d) == -1) die_fatal("unable to chdir to directory",d,0); + if (mkdir(".expertsonly",0700) == -1) die_fatal("unable to create directory",d,".expertsonly"); + + crypto_box_keypair(pk,sk); + create(d,"publickey",pk,sizeof pk); + + randombytes(noncekey,sizeof noncekey); + + umask(077); + create(d,".expertsonly/secretkey",sk,sizeof sk); + create(d,".expertsonly/lock",lock,sizeof lock); + create(d,".expertsonly/noncekey",noncekey,sizeof noncekey); + create(d,".expertsonly/noncecounter",noncecounter,sizeof noncecounter); + + return 0; +} diff --git a/src/libsodium/curvecp/curvecpmessage.c b/src/libsodium/curvecp/curvecpmessage.c new file mode 100644 index 00000000..df1e1664 --- /dev/null +++ b/src/libsodium/curvecp/curvecpmessage.c @@ -0,0 +1,654 @@ +#include +#include +#include +#include +#include +#include "open.h" +#include "blocking.h" +#include "e.h" +#include "die.h" +#include "randommod.h" +#include "byte.h" +#include "crypto_uint32.h" +#include "uint16_pack.h" +#include "uint32_pack.h" +#include "uint64_pack.h" +#include "uint16_unpack.h" +#include "uint32_unpack.h" +#include "uint64_unpack.h" +#include "nanoseconds.h" +#include "writeall.h" + +int flagverbose = 1; +int flagserver = 1; +int wantping = 0; /* 1: ping after a second; 2: ping immediately */ + +#define USAGE "\ +curvecpmessage: how to use:\n\ +curvecpmessage: -q (optional): no error messages\n\ +curvecpmessage: -Q (optional): print error messages (default)\n\ +curvecpmessage: -v (optional): print extra information\n\ +curvecpmessage: -c (optional): program is a client; server starts first\n\ +curvecpmessage: -C (optional): program is a client that starts first\n\ +curvecpmessage: -s (optional): program is a server (default)\n\ +curvecpmessage: prog: run this program\n\ +" + +void die_usage(const char *s) +{ + if (s) die_4(100,USAGE,"curvecpmessage: fatal: ",s,"\n"); + die_1(100,USAGE); +} + +void die_fatal(const char *trouble,const char *d,const char *fn) +{ + if (!flagverbose) die_0(111); + if (d) { + if (fn) die_9(111,"curvecpmessage: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n"); + die_7(111,"curvecpmessage: fatal: ",trouble," ",d,": ",e_str(errno),"\n"); + } + if (errno) die_5(111,"curvecpmessage: fatal: ",trouble,": ",e_str(errno),"\n"); + die_3(111,"curvecpmessage: fatal: ",trouble,"\n"); +} + +void die_badmessage(void) +{ + errno = EPROTO; + die_fatal("unable to read from file descriptor 8",0,0); +} + +void die_internalerror(void) +{ + errno = EPROTO; + die_fatal("internal error",0,0); +} + + +int tochild[2] = {-1,-1}; +int fromchild[2] = {-1,-1}; +pid_t child = -1; +int childstatus; + +struct pollfd p[3]; + +long long sendacked = 0; /* number of initial bytes sent and fully acknowledged */ +long long sendbytes = 0; /* number of additional bytes to send */ +unsigned char sendbuf[131072]; /* circular queue with the additional bytes; size must be power of 2 */ +long long sendprocessed = 0; /* within sendbytes, number of bytes absorbed into blocks */ + +crypto_uint16 sendeof = 0; /* 2048 for normal eof after sendbytes, 4096 for error after sendbytes */ +int sendeofprocessed = 0; +int sendeofacked = 0; + +long long totalblocktransmissions = 0; +long long totalblocks = 0; + +#define OUTGOING 128 /* must be power of 2 */ +long long blocknum = 0; /* number of outgoing blocks being tracked */ +long long blockfirst = 0; /* circular queue */ +long long blockpos[OUTGOING]; /* position of block's first byte within stream */ +long long blocklen[OUTGOING]; /* number of bytes in this block */ +crypto_uint16 blockeof[OUTGOING]; /* 0, 2048, 4096 */ +long long blocktransmissions[OUTGOING]; +long long blocktime[OUTGOING]; /* time of last message sending this block; 0 means acked */ +long long earliestblocktime = 0; /* if nonzero, minimum of active blocktime values */ +crypto_uint32 blockid[OUTGOING]; /* ID of last message sending this block */ + +#define INCOMING 64 /* must be power of 2 */ +long long messagenum = 0; /* number of messages in incoming queue */ +long long messagefirst = 0; /* position of first message; circular queue */ +unsigned char messagelen[INCOMING]; /* times 16 */ +unsigned char message[INCOMING][1088]; +unsigned char messagetodo[2048]; +long long messagetodolen = 0; + +long long receivebytes = 0; /* number of initial bytes fully received */ +long long receivewritten = 0; /* within receivebytes, number of bytes given to child */ +crypto_uint16 receiveeof = 0; /* 0, 2048, 4096 */ +long long receivetotalbytes = 0; /* total number of bytes in stream, if receiveeof */ +unsigned char receivebuf[131072]; /* circular queue beyond receivewritten; size must be power of 2 */ +unsigned char receivevalid[131072]; /* 1 for byte successfully received; XXX: use buddy structure to speed this up */ + +long long maxblocklen = 512; +crypto_uint32 nextmessageid = 1; + +unsigned char buf[4096]; + +long long lastblocktime = 0; +long long nsecperblock = 1000000000; +long long lastspeedadjustment = 0; +long long lastedge = 0; +long long lastdoubling = 0; + +long long rtt; +long long rtt_delta; +long long rtt_average = 0; +long long rtt_deviation = 0; +long long rtt_lowwater = 0; +long long rtt_highwater = 0; +long long rtt_timeout = 1000000000; +long long rtt_seenrecenthigh = 0; +long long rtt_seenrecentlow = 0; +long long rtt_seenolderhigh = 0; +long long rtt_seenolderlow = 0; +long long rtt_phase = 0; + +long long lastpanic = 0; + +void earliestblocktime_compute(void) /* XXX: use priority queue */ +{ + long long i; + long long pos; + earliestblocktime = 0; + for (i = 0;i < blocknum;++i) { + pos = (blockfirst + i) & (OUTGOING - 1); + if (blocktime[pos]) { + if (!earliestblocktime) + earliestblocktime = blocktime[pos]; + else + if (blocktime[pos] < earliestblocktime) + earliestblocktime = blocktime[pos]; + } + } +} + +void acknowledged(unsigned long long start,unsigned long long stop) +{ + long long i; + long long pos; + if (stop == start) return; + for (i = 0;i < blocknum;++i) { + pos = (blockfirst + i) & (OUTGOING - 1); + if (blockpos[pos] >= start && blockpos[pos] + blocklen[pos] <= stop) { + blocktime[pos] = 0; + totalblocktransmissions += blocktransmissions[pos]; + totalblocks += 1; + } + } + while (blocknum) { + pos = blockfirst & (OUTGOING - 1); + if (blocktime[pos]) break; + sendacked += blocklen[pos]; + sendbytes -= blocklen[pos]; + sendprocessed -= blocklen[pos]; + ++blockfirst; + --blocknum; + } + if (sendeof) + if (start == 0) + if (stop > sendacked + sendbytes) + if (!sendeofacked) { + sendeofacked = 1; + } + earliestblocktime_compute(); +} + +int main(int argc,char **argv) +{ + long long pos; + long long len; + long long u; + long long r; + long long i; + long long k; + long long recent; + long long nextaction; + long long timeout; + struct pollfd *q; + struct pollfd *watch8; + struct pollfd *watchtochild; + struct pollfd *watchfromchild; + + signal(SIGPIPE,SIG_IGN); + + if (!argv[0]) die_usage(0); + for (;;) { + char *x; + if (!argv[1]) break; + if (argv[1][0] != '-') break; + x = *++argv; + if (x[0] == '-' && x[1] == 0) break; + if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; + while (*++x) { + if (*x == 'q') { flagverbose = 0; continue; } + if (*x == 'Q') { flagverbose = 1; continue; } + if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } + if (*x == 'c') { flagserver = 0; wantping = 2; continue; } + if (*x == 'C') { flagserver = 0; wantping = 1; continue; } + if (*x == 's') { flagserver = 1; wantping = 0; continue; } + die_usage(0); + } + } + if (!*++argv) die_usage("missing prog"); + + for (;;) { + r = open_read("/dev/null"); + if (r == -1) die_fatal("unable to open /dev/null",0,0); + if (r > 9) { close(r); break; } + } + + if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0); + if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0); + + blocking_enable(tochild[0]); + blocking_enable(fromchild[1]); + + child = fork(); + if (child == -1) die_fatal("unable to fork",0,0); + if (child == 0) { + close(8); + close(9); + if (flagserver) { + close(0); + if (dup(tochild[0]) != 0) die_fatal("unable to dup",0,0); + close(1); + if (dup(fromchild[1]) != 1) die_fatal("unable to dup",0,0); + } else { + close(6); + if (dup(tochild[0]) != 6) die_fatal("unable to dup",0,0); + close(7); + if (dup(fromchild[1]) != 7) die_fatal("unable to dup",0,0); + } + signal(SIGPIPE,SIG_DFL); + execvp(*argv,argv); + die_fatal("unable to run",*argv,0); + } + + close(tochild[0]); + close(fromchild[1]); + + recent = nanoseconds(); + lastspeedadjustment = recent; + if (flagserver) maxblocklen = 1024; + + for (;;) { + if (sendeofacked) + if (receivewritten == receivetotalbytes) + if (receiveeof) + if (tochild[1] < 0) + break; /* XXX: to re-ack should enter a TIME-WAIT state here */ + + q = p; + + watch8 = q; + if (watch8) { q->fd = 8; q->events = POLLIN; ++q; } + + watchtochild = q; + if (tochild[1] < 0) watchtochild = 0; + if (receivewritten >= receivebytes) watchtochild = 0; + if (watchtochild) { q->fd = tochild[1]; q->events = POLLOUT; ++q; } + + watchfromchild = q; + if (sendeof) watchfromchild = 0; + if (sendbytes + 4096 > sizeof sendbuf) watchfromchild = 0; + if (watchfromchild) { q->fd = fromchild[0]; q->events = POLLIN; ++q; } + + nextaction = recent + 60000000000LL; + if (wantping == 1) nextaction = recent + 1000000000; + if (wantping == 2) + if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; + if (blocknum < OUTGOING) + if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes)) + if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; + if (earliestblocktime) + if (earliestblocktime + rtt_timeout > lastblocktime + nsecperblock) + if (earliestblocktime + rtt_timeout < nextaction) + nextaction = earliestblocktime + rtt_timeout; + + if (messagenum) + if (!watchtochild) + nextaction = 0; + + if (nextaction <= recent) + timeout = 0; + else + timeout = (nextaction - recent) / 1000000 + 1; + + if (poll(p,q - p,timeout) < 0) { + watch8 = 0; + watchtochild = 0; + watchfromchild = 0; + } else { + if (watch8) if (!watch8->revents) watch8 = 0; + if (watchtochild) if (!watchtochild->revents) watchtochild = 0; + if (watchfromchild) if (!watchfromchild->revents) watchfromchild = 0; + } + + /* XXX: keepalives */ + + do { /* try receiving data from child: */ + if (!watchfromchild) break; + if (sendeof) break; + if (sendbytes + 4096 > sizeof sendbuf) break; + + pos = (sendacked & (sizeof sendbuf - 1)) + sendbytes; + if (pos < sizeof sendbuf) { + r = read(fromchild[0],sendbuf + pos,sizeof sendbuf - pos); + } else { + r = read(fromchild[0],sendbuf + pos - sizeof sendbuf,sizeof sendbuf - sendbytes); + } + if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; + if (r < 0) { sendeof = 4096; break; } + if (r == 0) { sendeof = 2048; break; } + sendbytes += r; + if (sendbytes >= 1152921504606846976LL) die_internalerror(); + } while(0); + + recent = nanoseconds(); + + do { /* try re-sending an old block: */ + if (recent < lastblocktime + nsecperblock) break; + if (earliestblocktime == 0) break; + if (recent < earliestblocktime + rtt_timeout) break; + + for (i = 0;i < blocknum;++i) { + pos = (blockfirst + i) & (OUTGOING - 1); + if (blocktime[pos] == earliestblocktime) { + if (recent > lastpanic + 4 * rtt_timeout) { + nsecperblock *= 2; + lastpanic = recent; + lastedge = recent; + } + goto sendblock; + } + } + } while(0); + + do { /* try sending a new block: */ + if (recent < lastblocktime + nsecperblock) break; + if (blocknum >= OUTGOING) break; + if (!wantping) + if (sendeof ? sendeofprocessed : sendprocessed >= sendbytes) break; + /* XXX: if any Nagle-type processing is desired, do it here */ + + pos = (blockfirst + blocknum) & (OUTGOING - 1); + ++blocknum; + blockpos[pos] = sendacked + sendprocessed; + blocklen[pos] = sendbytes - sendprocessed; + if (blocklen[pos] > maxblocklen) blocklen[pos] = maxblocklen; + if ((blockpos[pos] & (sizeof sendbuf - 1)) + blocklen[pos] > sizeof sendbuf) + blocklen[pos] = sizeof sendbuf - (blockpos[pos] & (sizeof sendbuf - 1)); + /* XXX: or could have the full block in post-buffer space */ + sendprocessed += blocklen[pos]; + blockeof[pos] = 0; + if (sendprocessed == sendbytes) { + blockeof[pos] = sendeof; + if (sendeof) sendeofprocessed = 1; + } + blocktransmissions[pos] = 0; + + sendblock: + + blocktransmissions[pos] += 1; + blocktime[pos] = recent; + blockid[pos] = nextmessageid; + if (!++nextmessageid) ++nextmessageid; + + /* constraints: u multiple of 16; u >= 16; u <= 1088; u >= 48 + blocklen[pos] */ + u = 64 + blocklen[pos]; + if (u <= 192) u = 192; + else if (u <= 320) u = 320; + else if (u <= 576) u = 576; + else if (u <= 1088) u = 1088; + else die_internalerror(); + if (blocklen[pos] < 0 || blocklen[pos] > 1024) die_internalerror(); + + byte_zero(buf + 8,u); + buf[7] = u / 16; + uint32_pack(buf + 8,blockid[pos]); + /* XXX: include any acknowledgments that have piled up */ + uint16_pack(buf + 46,blockeof[pos] | (crypto_uint16) blocklen[pos]); + uint64_pack(buf + 48,blockpos[pos]); + byte_copy(buf + 8 + u - blocklen[pos],blocklen[pos],sendbuf + (blockpos[pos] & (sizeof sendbuf - 1))); + + if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); + lastblocktime = recent; + wantping = 0; + + earliestblocktime_compute(); + } while(0); + + do { /* try receiving messages: */ + if (!watch8) break; + r = read(8,buf,sizeof buf); + if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; + if (r == 0) die_badmessage(); + if (r < 0) die_fatal("unable to read from file descriptor 8",0,0); + for (k = 0;k < r;++k) { + messagetodo[messagetodolen++] = buf[k]; + u = 16 * (unsigned long long) messagetodo[0]; + if (u < 16) die_badmessage(); + if (u > 1088) die_badmessage(); + if (messagetodolen == 1 + u) { + if (messagenum < INCOMING) { + pos = (messagefirst + messagenum) & (INCOMING - 1); + messagelen[pos] = messagetodo[0]; + byte_copy(message[pos],u,messagetodo + 1); + ++messagenum; + } else { + ; /* drop tail */ + } + messagetodolen = 0; + } + } + } while(0); + + do { /* try processing a message: */ + if (!messagenum) break; + if (tochild[1] >= 0 && receivewritten < receivebytes) break; + + maxblocklen = 1024; + + pos = messagefirst & (INCOMING - 1); + len = 16 * (unsigned long long) messagelen[pos]; + do { /* handle this message if it's comprehensible: */ + unsigned long long D; + unsigned long long SF; + unsigned long long startbyte; + unsigned long long stopbyte; + crypto_uint32 id; + long long i; + + if (len < 48) break; + if (len > 1088) break; + + id = uint32_unpack(message[pos] + 4); + for (i = 0;i < blocknum;++i) { + k = (blockfirst + i) & (OUTGOING - 1); + if (blockid[k] == id) { + rtt = recent - blocktime[k]; + if (!rtt_average) { + nsecperblock = rtt; + rtt_average = rtt; + rtt_deviation = rtt / 2; + rtt_highwater = rtt; + rtt_lowwater = rtt; + } + + /* Jacobson's retransmission timeout calculation: */ + rtt_delta = rtt - rtt_average; + rtt_average += rtt_delta / 8; + if (rtt_delta < 0) rtt_delta = -rtt_delta; + rtt_delta -= rtt_deviation; + rtt_deviation += rtt_delta / 4; + rtt_timeout = rtt_average + 4 * rtt_deviation; + /* adjust for delayed acks with anti-spiking: */ + rtt_timeout += 8 * nsecperblock; + + /* recognizing top and bottom of congestion cycle: */ + rtt_delta = rtt - rtt_highwater; + rtt_highwater += rtt_delta / 1024; + rtt_delta = rtt - rtt_lowwater; + if (rtt_delta > 0) rtt_lowwater += rtt_delta / 8192; + else rtt_lowwater += rtt_delta / 256; + + if (rtt_average > rtt_highwater + 5000000) rtt_seenrecenthigh = 1; + else if (rtt_average < rtt_lowwater) rtt_seenrecentlow = 1; + + if (recent >= lastspeedadjustment + 16 * nsecperblock) { + if (recent - lastspeedadjustment > 10000000000LL) { + nsecperblock = 1000000000; /* slow restart */ + nsecperblock += randommod(nsecperblock / 8); + } + + lastspeedadjustment = recent; + + if (nsecperblock >= 131072) { + /* additive increase: adjust 1/N by a constant c */ + /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */ + /* approximation: adjust 1/N by cN every N nanoseconds */ + /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */ + if (nsecperblock < 16777216) { + /* N/(1+cN^2) approx N - cN^3 */ + u = nsecperblock / 131072; + nsecperblock -= u * u * u; + } else { + double d = nsecperblock; + nsecperblock = d/(1 + d*d / 2251799813685248.0); + } + } + + if (rtt_phase == 0) { + if (rtt_seenolderhigh) { + rtt_phase = 1; + lastedge = recent; + nsecperblock += randommod(nsecperblock / 4); + } + } else { + if (rtt_seenolderlow) { + rtt_phase = 0; + } + } + + rtt_seenolderhigh = rtt_seenrecenthigh; + rtt_seenolderlow = rtt_seenrecentlow; + rtt_seenrecenthigh = 0; + rtt_seenrecentlow = 0; + } + + do { + if (recent - lastedge < 60000000000LL) { + if (recent < lastdoubling + 4 * nsecperblock + 64 * rtt_timeout + 5000000000LL) break; + } else { + if (recent < lastdoubling + 4 * nsecperblock + 2 * rtt_timeout) break; + } + if (nsecperblock <= 65535) break; + + nsecperblock /= 2; + lastdoubling = recent; + if (lastedge) lastedge = recent; + } while(0); + } + } + + stopbyte = uint64_unpack(message[pos] + 8); + acknowledged(0,stopbyte); + startbyte = stopbyte + (unsigned long long) uint32_unpack(message[pos] + 16); + stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 20); + acknowledged(startbyte,stopbyte); + startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 22); + stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 24); + acknowledged(startbyte,stopbyte); + startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 26); + stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 28); + acknowledged(startbyte,stopbyte); + startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 30); + stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 32); + acknowledged(startbyte,stopbyte); + startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 34); + stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 36); + acknowledged(startbyte,stopbyte); + + D = uint16_unpack(message[pos] + 38); + SF = D & (2048 + 4096); + D -= SF; + if (D > 1024) break; + if (48 + D > len) break; + + startbyte = uint64_unpack(message[pos] + 40); + stopbyte = startbyte + D; + + if (stopbyte > receivewritten + sizeof receivebuf) { + break; + /* of course, flow control would avoid this case */ + } + + if (SF) { + receiveeof = SF; + receivetotalbytes = stopbyte; + } + + for (k = 0;k < D;++k) { + unsigned char ch = message[pos][len - D + k]; + unsigned long long where = startbyte + k; + if (where >= receivewritten && where < receivewritten + sizeof receivebuf) { + receivevalid[where & (sizeof receivebuf - 1)] = 1; + receivebuf[where & (sizeof receivebuf - 1)] = ch; + } + } + for (;;) { + if (receivebytes >= receivewritten + sizeof receivebuf) break; + if (!receivevalid[receivebytes & (sizeof receivebuf - 1)]) break; + ++receivebytes; + } + + if (!uint32_unpack(message[pos])) break; /* never acknowledge a pure acknowledgment */ + + /* XXX: delay acknowledgments */ + u = 192; + byte_zero(buf + 8,u); + buf[7] = u / 16; + byte_copy(buf + 12,4,message[pos]); + if (receiveeof && receivebytes == receivetotalbytes) { + uint64_pack(buf + 16,receivebytes + 1); + } else + uint64_pack(buf + 16,receivebytes); + /* XXX: incorporate selective acknowledgments */ + + if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); + } while(0); + + ++messagefirst; + --messagenum; + } while(0); + + do { /* try sending data to child: */ + if (!watchtochild) break; + if (tochild[1] < 0) { receivewritten = receivebytes; break; } + if (receivewritten >= receivebytes) break; + + pos = receivewritten & (sizeof receivebuf - 1); + len = receivebytes - receivewritten; + if (pos + len > sizeof receivebuf) len = sizeof receivebuf - pos; + r = write(tochild[1],receivebuf + pos,len); + if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; + if (r <= 0) { + close(tochild[1]); + tochild[1] = -1; + break; + } + byte_zero(receivevalid + pos,r); + receivewritten += r; + } while(0); + + do { /* try closing pipe to child: */ + if (!receiveeof) break; + if (receivewritten < receivetotalbytes) break; + if (tochild[1] < 0) break; + + if (receiveeof == 4096) + ; /* XXX: UNIX doesn't provide a way to signal an error through a pipe */ + close(tochild[1]); + tochild[1] = -1; + } while(0); + + } + + + do { + r = waitpid(child,&childstatus,0); + } while (r == -1 && errno == EINTR); + + if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } + return WEXITSTATUS(childstatus); +} diff --git a/src/libsodium/curvecp/curvecpprintkey.c b/src/libsodium/curvecp/curvecpprintkey.c new file mode 100644 index 00000000..8fd26bcf --- /dev/null +++ b/src/libsodium/curvecp/curvecpprintkey.c @@ -0,0 +1,46 @@ +#include +#include "die.h" +#include "e.h" +#include "load.h" +#include "writeall.h" +#include "crypto_box.h" + +unsigned char pk[crypto_box_PUBLICKEYBYTES]; +unsigned char out[crypto_box_PUBLICKEYBYTES * 2 + 1]; + +void die_usage(void) +{ + die_1(111,"curvecpprintkey: usage: curvecpprintkey keydir\n"); +} + +void die_fatal(const char *trouble,const char *d,const char *fn) +{ + if (d) { + if (fn) die_9(111,"curvecpmakekey: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n"); + die_7(111,"curvecpmakekey: fatal: ",trouble," ",d,": ",e_str(errno),"\n"); + } + die_5(111,"curvecpmakekey: fatal: ",trouble,": ",e_str(errno),"\n"); +} + +int main(int argc,char **argv) +{ + char *d; + long long j; + + if (!argv[0]) die_usage(); + if (!argv[1]) die_usage(); + d = argv[1]; + + if (chdir(d) == -1) die_fatal("unable to chdir to directory",d,0); + if (load("publickey",pk,sizeof pk) == -1) die_fatal("unable to read",d,"publickey"); + + for (j = 0;j < crypto_box_PUBLICKEYBYTES;++j) { + out[2 * j + 0] = "0123456789abcdef"[15 & (int) (pk[j] >> 4)]; + out[2 * j + 1] = "0123456789abcdef"[15 & (int) (pk[j] >> 0)]; + } + out[2 * j] = '\n'; + + if (writeall(1,out,sizeof out) == -1) die_fatal("unable to write output",0,0); + + return 0; +} diff --git a/src/libsodium/curvecp/curvecpserver.c b/src/libsodium/curvecp/curvecpserver.c new file mode 100644 index 00000000..82cc6670 --- /dev/null +++ b/src/libsodium/curvecp/curvecpserver.c @@ -0,0 +1,497 @@ +#include +#include +#include +#include +#include +#include +#include +#include "e.h" +#include "die.h" +#include "byte.h" +#include "open.h" +#include "load.h" +#include "socket.h" +#include "uint64_pack.h" +#include "uint64_unpack.h" +#include "writeall.h" +#include "nanoseconds.h" +#include "safenonce.h" +#include "nameparse.h" +#include "hexparse.h" +#include "portparse.h" +#include "randommod.h" + +#include "randombytes.h" +#include "crypto_box.h" +#include "crypto_secretbox.h" +#if crypto_box_PUBLICKEYBYTES != 32 +error! +#endif +#if crypto_box_NONCEBYTES != 24 +error! +#endif +#if crypto_box_BOXZEROBYTES != 16 +error! +#endif +#if crypto_box_ZEROBYTES != 32 +error! +#endif +#if crypto_box_BEFORENMBYTES != 32 +error! +#endif +#if crypto_secretbox_KEYBYTES != 32 +error! +#endif +#if crypto_secretbox_NONCEBYTES != 24 +error! +#endif +#if crypto_secretbox_BOXZEROBYTES != 16 +error! +#endif +#if crypto_secretbox_ZEROBYTES != 32 +error! +#endif + +int flagverbose; + +#define USAGE "\ +curvecpserver: how to use:\n\ +curvecpserver: -q (optional): no error messages\n\ +curvecpserver: -Q (optional): print error messages (default)\n\ +curvecpserver: -v (optional): print extra information\n\ +curvecpserver: -c n (optional): allow at most n clients at once (default 100)\n\ +curvecpserver: sname: server's name\n\ +curvecpserver: keydir: use this public-key directory\n\ +curvecpserver: ip: server's IP address\n\ +curvecpserver: port: server's UDP port\n\ +curvecpserver: ext: server's extension\n\ +curvecpserver: prog: run this server\n\ +" + +void die_usage(const char *s) +{ + if (s) die_4(100,USAGE,"curvecpserver: fatal: ",s,"\n"); + die_1(100,USAGE); +} + +void die_fatal(const char *trouble,const char *d,const char *fn) +{ + if (!flagverbose) die_0(111); + if (d) { + if (fn) die_9(111,"curvecpserver: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n"); + die_7(111,"curvecpserver: fatal: ",trouble," ",d,": ",e_str(errno),"\n"); + } + die_5(111,"curvecpserver: fatal: ",trouble,": ",e_str(errno),"\n"); +} + +int ipparse(unsigned char *y,const char *x) +{ + long long j; + long long k; + long long d; + + for (k = 0;k < 4;++k) y[k] = 0; + for (k = 0;k < 4;++k) { + d = 0; + for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0'); + if (j == 0) return 0; + x += j; + if (k >= 0 && k < 4) y[k] = d; + if (k < 3) { + if (*x != '.') return 0; + ++x; + } + } + if (*x) return 0; + return 1; +} + +int maxparse(long long *y,const char *x) +{ + long long d; + long long j; + + d = 0; + for (j = 0;j < 9 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0'); + if (x[j]) return 0; + if (d < 1) return 0; + if (d > 65535) return 0; + *y = d; + return 1; +} + +/* cookies: */ +long long nextminute; +unsigned char minutekey[32]; +unsigned char lastminutekey[32]; + +/* routing to the server: */ +unsigned char serverip[4]; +unsigned char serverport[2]; +unsigned char serverextension[16]; +int udpfd = -1; + +/* server security: */ +char *keydir = 0; +unsigned char servername[256]; +unsigned char serverlongtermsk[32]; +unsigned char servershorttermpk[32]; +unsigned char servershorttermsk[32]; + +/* routing to the client: */ +unsigned char clientextension[16]; + +/* client security: */ +unsigned char clientlongtermpk[32]; +unsigned char clientshorttermpk[32]; + +/* shared secrets: */ +unsigned char clientshortserverlong[32]; +unsigned char clientshortservershort[32]; +unsigned char clientlongserverlong[32]; + +unsigned char allzero[128] = {0}; + +unsigned char nonce[24]; +unsigned char text[2048]; + +unsigned char packetip[4]; +unsigned char packetport[2]; +unsigned char packet[4096]; +crypto_uint64 packetnonce; + +#define MESSAGELEN 1104 + +struct activeclient { + unsigned char clientshorttermpk[32]; + unsigned char clientshortservershort[32]; + crypto_uint64 receivednonce; + crypto_uint64 sentnonce; + long long messagelen; + pid_t child; + int tochild; + int fromchild; + unsigned char clientextension[16]; + unsigned char clientip[4]; + unsigned char clientport[2]; + unsigned char message[MESSAGELEN]; +} ; + +const char *strmaxactiveclients = "100"; +long long maxactiveclients = 0; +long long numactiveclients = 0; +struct activeclient *activeclients = 0; +struct pollfd *p; + +int fdwd = -1; + +int pi0[2]; +int pi1[2]; + +unsigned char childbuf[4096]; +long long childbuflen = 0; +unsigned char childmessage[2048]; +long long childmessagelen = 0; + +int main(int argc,char **argv) +{ + long long r; + long long i; + long long k; + + signal(SIGPIPE,SIG_IGN); + signal(SIGCHLD,SIG_IGN); + + if (!argv[0]) die_usage(0); + for (;;) { + char *x; + if (!argv[1]) break; + if (argv[1][0] != '-') break; + x = *++argv; + if (x[0] == '-' && x[1] == 0) break; + if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; + while (*++x) { + if (*x == 'q') { flagverbose = 0; continue; } + if (*x == 'Q') { flagverbose = 1; continue; } + if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } + if (*x == 'c') { + if (x[1]) { strmaxactiveclients = x + 1; break; } + if (argv[1]) { strmaxactiveclients = *++argv; break; } + } + die_usage(0); + } + } + if (!maxparse(&maxactiveclients,strmaxactiveclients)) die_usage("concurrency must be between 1 and 65535"); + if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots"); + keydir = *++argv; if (!keydir) die_usage("missing keydir"); + if (!ipparse(serverip,*++argv)) die_usage("ip must be an IPv4 address"); + if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535"); + if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters"); + if (!*++argv) die_usage("missing prog"); + + for (;;) { + r = open_read("/dev/null"); + if (r == -1) die_fatal("unable to open /dev/null",0,0); + if (r > 9) { close(r); break; } + } + + activeclients = malloc(maxactiveclients * sizeof(struct activeclient)); + if (!activeclients) die_fatal("unable to create activeclients array",0,0); + randombytes((void *) activeclients,maxactiveclients * sizeof(struct activeclient)); + for (i = 0;i < maxactiveclients;++i) { + activeclients[i].child = -1; + activeclients[i].tochild = -1; + activeclients[i].fromchild = -1; + activeclients[i].receivednonce = 0; + activeclients[i].sentnonce = randommod(281474976710656LL); + } + + p = malloc((1 + maxactiveclients) * sizeof(struct pollfd)); + if (!p) die_fatal("unable to create poll array",0,0); + + fdwd = open_cwd(); + if (fdwd == -1) die_fatal("unable to open current directory",0,0); + + if (chdir(keydir) == -1) die_fatal("unable to chdir to",keydir,0); + if (load(".expertsonly/secretkey",serverlongtermsk,sizeof serverlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0); + + udpfd = socket_udp(); + if (udpfd == -1) die_fatal("unable to create socket",0,0); + if (socket_bind(udpfd,serverip,serverport) == -1) die_fatal("unable to bind socket",0,0); + + randombytes(minutekey,sizeof minutekey); + randombytes(lastminutekey,sizeof lastminutekey); + nextminute = nanoseconds() + 60000000000ULL; + + for (;;) { + long long timeout = nextminute - nanoseconds(); + if (timeout <= 0) { + timeout = 60000000000ULL; + byte_copy(lastminutekey,sizeof lastminutekey,minutekey); + randombytes(minutekey,sizeof minutekey); + nextminute = nanoseconds() + timeout; + randombytes(packet,sizeof packet); + randombytes(packetip,sizeof packetip); + randombytes(packetport,sizeof packetport); + randombytes(clientshorttermpk,sizeof clientshorttermpk); + randombytes(clientshortserverlong,sizeof clientshortserverlong); + randombytes(nonce,sizeof nonce); + randombytes(text,sizeof text); + randombytes(childbuf,sizeof childbuf); + randombytes(childmessage,sizeof childmessage); + randombytes(servershorttermpk,sizeof servershorttermpk); + randombytes(servershorttermsk,sizeof servershorttermsk); + } + + for (i = 0;i < numactiveclients;++i) { + p[i].fd = activeclients[i].fromchild; + p[i].events = POLLIN; + } + p[numactiveclients].fd = udpfd; + p[numactiveclients].events = POLLIN; + if (poll(p,1 + numactiveclients,timeout / 1000000 + 1) < 0) continue; + + do { /* try receiving a packet: */ + if (!p[numactiveclients].revents) break; + r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport); + if (r < 80) break; + if (r > 1184) break; + if (r & 15) break; + if (!(byte_isequal(packet,7,"QvnQ5Xl") & byte_isequal(packet + 8,16,serverextension))) break; + byte_copy(clientextension,16,packet + 24); + if (packet[7] == 'H') { /* Hello packet: */ + if (r != 224) break; + byte_copy(clientshorttermpk,32,packet + 40); + crypto_box_beforenm(clientshortserverlong,clientshorttermpk,serverlongtermsk); + byte_copy(nonce,16,"CurveCP-client-H"); + byte_copy(nonce + 16,8,packet + 136); + byte_zero(text,16); + byte_copy(text + 16,80,packet + 144); + if (crypto_box_open_afternm(text,text,96,nonce,clientshortserverlong)) break; + + /* send Cookie packet: */ + + crypto_box_keypair(servershorttermpk,servershorttermsk); + byte_zero(text + 64,32); + byte_copy(text + 96,32,clientshorttermpk); + byte_copy(text + 128,32,servershorttermsk); + byte_copy(nonce,8,"minute-k"); + if (safenonce(nonce + 8,1) == -1) die_fatal("nonce-generation disaster",0,0); + crypto_secretbox(text + 64,text + 64,96,nonce,minutekey); + byte_copy(text + 64,16,nonce + 8); + + byte_zero(text,32); + byte_copy(text + 32,32,servershorttermpk); + byte_copy(nonce,8,"CurveCPK"); /* reusing the other 16 bytes */ + crypto_box_afternm(text,text,160,nonce,clientshortserverlong); + + byte_copy(packet,8,"RL3aNMXK"); + byte_copy(packet + 8,16,clientextension); + byte_copy(packet + 24,16,serverextension); + byte_copy(packet + 40,16,nonce + 8); + byte_copy(packet + 56,144,text + 16); + + socket_send(udpfd,packet,200,packetip,packetport); + } + if (packet[7] == 'I') { /* Initiate packet: */ + if (r < 560) break; + for (i = 0;i < numactiveclients;++i) /* XXX use better data structure */ + if (byte_isequal(activeclients[i].clientshorttermpk,32,packet + 40)) + break; + if (i < numactiveclients) { + packetnonce = uint64_unpack(packet + 168); + if (packetnonce <= activeclients[i].receivednonce) break; + byte_copy(nonce,16,"CurveCP-client-I"); + byte_copy(nonce + 16,8,packet + 168); + byte_zero(text,16); + byte_copy(text + 16,r - 176,packet + 176); + if (crypto_box_open_afternm(text,text,r - 160,nonce,activeclients[i].clientshortservershort)) break; + + /* XXX: update clientip, clientextension; but not if client has spoken recently */ + activeclients[i].receivednonce = packetnonce; + text[383] = (r - 544) >> 4; + if (writeall(activeclients[i].tochild,text + 383,r - 543) == -1) + ; /* child is gone; will see eof later */ + break; + } + if (i == maxactiveclients) break; + + byte_copy(nonce,8,"minute-k"); + byte_copy(nonce + 8,16,packet + 72); + byte_zero(text,16); + byte_copy(text + 16,80,packet + 88); + if (crypto_secretbox_open(text,text,96,nonce,minutekey)) { + byte_zero(text,16); + byte_copy(text + 16,80,packet + 88); + if (crypto_secretbox_open(text,text,96,nonce,lastminutekey)) break; + } + if (!byte_isequal(packet + 40,32,text + 32)) break; + byte_copy(servershorttermsk,32,text + 64); + byte_copy(clientshorttermpk,32,packet + 40); + crypto_box_beforenm(clientshortservershort,clientshorttermpk,servershorttermsk); + + byte_copy(nonce,16,"CurveCP-client-I"); + byte_copy(nonce + 16,8,packet + 168); + byte_zero(text,16); + byte_copy(text + 16,r - 176,packet + 176); + if (crypto_box_open_afternm(text,text,r - 160,nonce,clientshortservershort)) break; + + if (!byte_isequal(text + 128,256,servername)) break; + + /* XXX skip if client authentication is not desired: */ + byte_copy(clientlongtermpk,32,text + 32); + /* XXX impose policy limitations on clients: known, maxconn */ + /* XXX for known clients, retrieve shared secret from cache: */ + crypto_box_beforenm(clientlongserverlong,clientlongtermpk,serverlongtermsk); + byte_copy(nonce,8,"CurveCPV"); + byte_copy(nonce + 8,16,text + 64); + byte_zero(text + 64,16); + if (crypto_box_open_afternm(text + 64,text + 64,64,nonce,clientlongserverlong)) break; + if (!byte_isequal(text + 96,32,clientshorttermpk)) break; + + if (open_pipe(pi0) == -1) break; /* XXX: error message */ + if (open_pipe(pi1) == -1) { close(pi0[0]); close(pi0[1]); break; } /* XXX: error message */ + + activeclients[i].child = fork(); + if (activeclients[i].child == -1) { + close(pi0[0]); close(pi0[1]); + close(pi1[0]); close(pi1[1]); + break; /* XXX: error message */ + } + if (activeclients[i].child == 0) { + if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0); + close(8); + if (dup(pi0[0]) != 8) die_fatal("unable to dup",0,0); + close(9); + if (dup(pi1[1]) != 9) die_fatal("unable to dup",0,0); + /* XXX: set up environment variables */ + signal(SIGPIPE,SIG_DFL); + signal(SIGCHLD,SIG_DFL); + execvp(*argv,argv); + die_fatal("unable to run",*argv,0); + } + + activeclients[i].tochild = pi0[1]; close(pi0[0]); + activeclients[i].fromchild = pi1[0]; close(pi1[1]); + activeclients[i].messagelen = 0; + byte_copy(activeclients[i].clientshorttermpk,32,clientshorttermpk); + byte_copy(activeclients[i].clientshortservershort,32,clientshortservershort); + activeclients[i].receivednonce = uint64_unpack(packet + 168); + byte_copy(activeclients[i].clientextension,16,clientextension); + byte_copy(activeclients[i].clientip,4,packetip); + byte_copy(activeclients[i].clientport,2,packetport); + ++numactiveclients; + + text[383] = (r - 544) >> 4; + if (writeall(activeclients[i].tochild,text + 383,r - 543) == -1) + ; /* child is gone; will see eof later */ + } + if (packet[7] == 'M') { /* Message packet: */ + if (r < 112) break; + for (i = 0;i < numactiveclients;++i) /* XXX use better data structure */ + if (byte_isequal(activeclients[i].clientshorttermpk,32,packet + 40)) + break; + if (i < numactiveclients) { + packetnonce = uint64_unpack(packet + 72); + if (packetnonce <= activeclients[i].receivednonce) break; + byte_copy(nonce,16,"CurveCP-client-M"); + byte_copy(nonce + 16,8,packet + 72); + byte_zero(text,16); + byte_copy(text + 16,r - 80,packet + 80); + if (crypto_box_open_afternm(text,text,r - 64,nonce,activeclients[i].clientshortservershort)) break; + + /* XXX: update clientip, clientextension */ + activeclients[i].receivednonce = packetnonce; + text[31] = (r - 96) >> 4; + if (writeall(activeclients[i].tochild,text + 31,r - 95) == -1) + ; /* child is gone; will see eof later */ + break; + } + } + } while (0); + + for (i = numactiveclients - 1;i >= 0;--i) { + do { + if (!p[i].revents) break; + r = read(activeclients[i].fromchild,childbuf,sizeof childbuf); + if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; + if (r <= 0) goto endconnection; + childbuflen = r; + for (k = 0;k < childbuflen;++k) { + r = activeclients[i].messagelen; + if (r < 0) goto endconnection; + if (r >= MESSAGELEN) goto endconnection; + activeclients[i].message[r] = childbuf[k]; + if (r == 0) if (childbuf[k] & 128) goto endconnection; + activeclients[i].messagelen = r + 1; + if (r == 16 * (unsigned long long) activeclients[i].message[0]) { + if (r < 16) goto endconnection; + if (r > 1088) goto endconnection; + byte_copy(nonce,16,"CurveCP-server-M"); + uint64_pack(nonce + 16,++activeclients[i].sentnonce); + byte_zero(text,32); + byte_copy(text + 32,r,activeclients[i].message + 1); + crypto_box_afternm(text,text,r + 32,nonce,activeclients[i].clientshortservershort); + byte_copy(packet,8,"RL3aNMXM"); + byte_copy(packet + 8,16,clientextension); + byte_copy(packet + 24,16,serverextension); + byte_copy(packet + 40,8,nonce + 16); + byte_copy(packet + 48,r + 16,text + 16); + socket_send(udpfd,packet,r + 64,activeclients[i].clientip,activeclients[i].clientport); + activeclients[i].messagelen = 0; + } + } + break; + + endconnection: + + /* XXX: cache cookie if it's recent */ + close(activeclients[i].fromchild); activeclients[i].fromchild = -1; + close(activeclients[i].tochild); activeclients[i].tochild = -1; + --numactiveclients; + activeclients[i] = activeclients[numactiveclients]; + randombytes((void *) &activeclients[numactiveclients],sizeof(struct activeclient)); + } while (0); + } + } +} diff --git a/src/libsodium/curvecp/die.c b/src/libsodium/curvecp/die.c new file mode 100644 index 00000000..2220cf38 --- /dev/null +++ b/src/libsodium/curvecp/die.c @@ -0,0 +1,42 @@ +#include +#include "writeall.h" +#include "die.h" + +void die_9(int e + ,const char *s0 + ,const char *s1 + ,const char *s2 + ,const char *s3 + ,const char *s4 + ,const char *s5 + ,const char *s6 + ,const char *s7 + ,const char *s8 +) +{ + const char *s[9]; + const char *x; + char buf[1024]; + int buflen = 0; + int i; + + s[0] = s0; + s[1] = s1; + s[2] = s2; + s[3] = s3; + s[4] = s4; + s[5] = s5; + s[6] = s6; + s[7] = s7; + s[8] = s8; + for (i = 0;i < 9;++i) { + x = s[i]; + if (!x) continue; + while (*x) { + if (buflen == sizeof buf) { writeall(2,buf,buflen); buflen = 0; } + buf[buflen++] = *x++; + } + } + writeall(2,buf,buflen); + _exit(e); +} diff --git a/src/libsodium/curvecp/die.h b/src/libsodium/curvecp/die.h new file mode 100644 index 00000000..52ec7616 --- /dev/null +++ b/src/libsodium/curvecp/die.h @@ -0,0 +1,16 @@ +#ifndef DIE_H +#define DIE_H + +extern void die_9(int,const char *,const char *,const char *,const char *,const char *,const char *,const char *,const char *,const char *); + +#define die_8(x,a,b,c,d,e,f,g,h) die_9(x,a,b,c,d,e,f,g,h,0) +#define die_7(x,a,b,c,d,e,f,g) die_8(x,a,b,c,d,e,f,g,0) +#define die_6(x,a,b,c,d,e,f) die_7(x,a,b,c,d,e,f,0) +#define die_5(x,a,b,c,d,e) die_6(x,a,b,c,d,e,0) +#define die_4(x,a,b,c,d) die_5(x,a,b,c,d,0) +#define die_3(x,a,b,c) die_4(x,a,b,c,0) +#define die_2(x,a,b) die_3(x,a,b,0) +#define die_1(x,a) die_2(x,a,0) +#define die_0(x) die_1(x,0) + +#endif diff --git a/src/libsodium/curvecp/e.c b/src/libsodium/curvecp/e.c new file mode 100644 index 00000000..00ff7fd9 --- /dev/null +++ b/src/libsodium/curvecp/e.c @@ -0,0 +1,106 @@ +#include "e.h" + +#define X(e,s) if (i == e) return s; + +const char *e_str(int i) +{ + X(0,"no error"); + X(EINTR,"interrupted system call") + X(ENOMEM,"out of memory") + X(ENOENT,"file does not exist") + X(ETXTBSY,"text busy") + X(EIO,"input/output error") + X(EEXIST,"file already exists") + X(ETIMEDOUT,"timed out") + X(EINPROGRESS,"operation in progress") + X(EAGAIN,"temporary failure") + X(EWOULDBLOCK,"input/output would block") + X(EPIPE,"broken pipe") + X(EPERM,"permission denied") + X(EACCES,"access denied") + X(ENODEV,"device not configured") + X(EPROTO,"protocol error") + X(EISDIR,"is a directory") + X(ESRCH,"no such process") + X(E2BIG,"argument list too long") + X(ENOEXEC,"exec format error") + X(EBADF,"file descriptor not open") + X(ECHILD,"no child processes") + X(EDEADLK,"operation would cause deadlock") + X(EFAULT,"bad address") + X(ENOTBLK,"not a block device") + X(EBUSY,"device busy") + X(EXDEV,"cross-device link") + X(ENODEV,"device does not support operation") + X(ENOTDIR,"not a directory") + X(EINVAL,"invalid argument") + X(ENFILE,"system cannot open more files") + X(EMFILE,"process cannot open more files") + X(ENOTTY,"not a tty") + X(EFBIG,"file too big") + X(ENOSPC,"out of disk space") + X(ESPIPE,"unseekable descriptor") + X(EROFS,"read-only file system") + X(EMLINK,"too many links") + X(EDOM,"input out of range") + X(ERANGE,"output out of range") + X(EALREADY,"operation already in progress") + X(ENOTSOCK,"not a socket") + X(EDESTADDRREQ,"destination address required") + X(EMSGSIZE,"message too long") + X(EPROTOTYPE,"incorrect protocol type") + X(ENOPROTOOPT,"protocol not available") + X(EPROTONOSUPPORT,"protocol not supported") + X(ESOCKTNOSUPPORT,"socket type not supported") + X(EOPNOTSUPP,"operation not supported") + X(EPFNOSUPPORT,"protocol family not supported") + X(EAFNOSUPPORT,"address family not supported") + X(EADDRINUSE,"address already used") + X(EADDRNOTAVAIL,"address not available") + X(ENETDOWN,"network down") + X(ENETUNREACH,"network unreachable") + X(ENETRESET,"network reset") + X(ECONNABORTED,"connection aborted") + X(ECONNRESET,"connection reset") + X(ENOBUFS,"out of buffer space") + X(EISCONN,"already connected") + X(ENOTCONN,"not connected") + X(ESHUTDOWN,"socket shut down") + X(ETOOMANYREFS,"too many references") + X(ECONNREFUSED,"connection refused") + X(ELOOP,"symbolic link loop") + X(ENAMETOOLONG,"file name too long") + X(EHOSTDOWN,"host down") + X(EHOSTUNREACH,"host unreachable") + X(ENOTEMPTY,"directory not empty") + X(EPROCLIM,"too many processes") + X(EUSERS,"too many users") + X(EDQUOT,"disk quota exceeded") + X(ESTALE,"stale NFS file handle") + X(EREMOTE,"too many levels of remote in path") + X(EBADRPC,"RPC structure is bad") + X(ERPCMISMATCH,"RPC version mismatch") + X(EPROGUNAVAIL,"RPC program unavailable") + X(EPROGMISMATCH,"program version mismatch") + X(EPROCUNAVAIL,"bad procedure for program") + X(ENOLCK,"no locks available") + X(ENOSYS,"system call not available") + X(EFTYPE,"bad file type") + X(EAUTH,"authentication error") + X(ENEEDAUTH,"not authenticated") + X(ENOSTR,"not a stream device") + X(ETIME,"timer expired") + X(ENOSR,"out of stream resources") + X(ENOMSG,"no message of desired type") + X(EBADMSG,"bad message type") + X(EIDRM,"identifier removed") + X(ENONET,"machine not on network") + X(EREMOTE,"object not local") + X(ENOLINK,"link severed") + X(EADV,"advertise error") + X(ESRMNT,"srmount error") + X(ECOMM,"communication error") + X(EMULTIHOP,"multihop attempted") + X(EREMCHG,"remote address changed") + return "unknown error"; +} diff --git a/src/libsodium/curvecp/e.h b/src/libsodium/curvecp/e.h new file mode 100644 index 00000000..add0768b --- /dev/null +++ b/src/libsodium/curvecp/e.h @@ -0,0 +1,438 @@ +#ifndef E_H +#define E_H + +#include + +extern const char *e_str(int); + +#ifndef EPERM +#define EPERM (-5001) +#endif +#ifndef ENOENT +#define ENOENT (-5002) +#endif +#ifndef ESRCH +#define ESRCH (-5003) +#endif +#ifndef EINTR +#define EINTR (-5004) +#endif +#ifndef EIO +#define EIO (-5005) +#endif +#ifndef ENXIO +#define ENXIO (-5006) +#endif +#ifndef E2BIG +#define E2BIG (-5007) +#endif +#ifndef ENOEXEC +#define ENOEXEC (-5008) +#endif +#ifndef EBADF +#define EBADF (-5009) +#endif +#ifndef ECHILD +#define ECHILD (-5010) +#endif +#ifndef EAGAIN +#define EAGAIN (-5011) +#endif +#ifndef EWOULDBLOCK +#define EWOULDBLOCK (-7011) +#endif +#ifndef ENOMEM +#define ENOMEM (-5012) +#endif +#ifndef EACCES +#define EACCES (-5013) +#endif +#ifndef EFAULT +#define EFAULT (-5014) +#endif +#ifndef ENOTBLK +#define ENOTBLK (-5015) +#endif +#ifndef EBUSY +#define EBUSY (-5016) +#endif +#ifndef EEXIST +#define EEXIST (-5017) +#endif +#ifndef EXDEV +#define EXDEV (-5018) +#endif +#ifndef ENODEV +#define ENODEV (-5019) +#endif +#ifndef ENOTDIR +#define ENOTDIR (-5020) +#endif +#ifndef EISDIR +#define EISDIR (-5021) +#endif +#ifndef EINVAL +#define EINVAL (-5022) +#endif +#ifndef ENFILE +#define ENFILE (-5023) +#endif +#ifndef EMFILE +#define EMFILE (-5024) +#endif +#ifndef ENOTTY +#define ENOTTY (-5025) +#endif +#ifndef ETXTBSY +#define ETXTBSY (-5026) +#endif +#ifndef EFBIG +#define EFBIG (-5027) +#endif +#ifndef ENOSPC +#define ENOSPC (-5028) +#endif +#ifndef ESPIPE +#define ESPIPE (-5029) +#endif +#ifndef EROFS +#define EROFS (-5030) +#endif +#ifndef EMLINK +#define EMLINK (-5031) +#endif +#ifndef EPIPE +#define EPIPE (-5032) +#endif +#ifndef EDOM +#define EDOM (-5033) +#endif +#ifndef ERANGE +#define ERANGE (-5034) +#endif +#ifndef EDEADLK +#define EDEADLK (-5035) +#endif +#ifndef EDEADLOCK +#define EDEADLOCK (-7035) +#endif +#ifndef ENAMETOOLONG +#define ENAMETOOLONG (-5036) +#endif +#ifndef ENOLCK +#define ENOLCK (-5037) +#endif +#ifndef ENOSYS +#define ENOSYS (-5038) +#endif +#ifndef ENOTEMPTY +#define ENOTEMPTY (-5039) +#endif +#ifndef ELOOP +#define ELOOP (-5040) +#endif +#ifndef ENOMSG +#define ENOMSG (-5042) +#endif +#ifndef EIDRM +#define EIDRM (-5043) +#endif +#ifndef ECHRNG +#define ECHRNG (-5044) +#endif +#ifndef EL2NSYNC +#define EL2NSYNC (-5045) +#endif +#ifndef EL3HLT +#define EL3HLT (-5046) +#endif +#ifndef EL3RST +#define EL3RST (-5047) +#endif +#ifndef ELNRNG +#define ELNRNG (-5048) +#endif +#ifndef EUNATCH +#define EUNATCH (-5049) +#endif +#ifndef ENOCSI +#define ENOCSI (-5050) +#endif +#ifndef EL2HLT +#define EL2HLT (-5051) +#endif +#ifndef EBADE +#define EBADE (-5052) +#endif +#ifndef EBADR +#define EBADR (-5053) +#endif +#ifndef EXFULL +#define EXFULL (-5054) +#endif +#ifndef ENOANO +#define ENOANO (-5055) +#endif +#ifndef EBADRQC +#define EBADRQC (-5056) +#endif +#ifndef EBADSLT +#define EBADSLT (-5057) +#endif +#ifndef EBFONT +#define EBFONT (-5059) +#endif +#ifndef ENOSTR +#define ENOSTR (-5060) +#endif +#ifndef ENODATA +#define ENODATA (-5061) +#endif +#ifndef ETIME +#define ETIME (-5062) +#endif +#ifndef ENOSR +#define ENOSR (-5063) +#endif +#ifndef ENONET +#define ENONET (-5064) +#endif +#ifndef ENOPKG +#define ENOPKG (-5065) +#endif +#ifndef EREMOTE +#define EREMOTE (-5066) +#endif +#ifndef ENOLINK +#define ENOLINK (-5067) +#endif +#ifndef EADV +#define EADV (-5068) +#endif +#ifndef ESRMNT +#define ESRMNT (-5069) +#endif +#ifndef ECOMM +#define ECOMM (-5070) +#endif +#ifndef EPROTO +#define EPROTO (-5071) +#endif +#ifndef EMULTIHOP +#define EMULTIHOP (-5072) +#endif +#ifndef EDOTDOT +#define EDOTDOT (-5073) +#endif +#ifndef EBADMSG +#define EBADMSG (-5074) +#endif +#ifndef EOVERFLOW +#define EOVERFLOW (-5075) +#endif +#ifndef ENOTUNIQ +#define ENOTUNIQ (-5076) +#endif +#ifndef EBADFD +#define EBADFD (-5077) +#endif +#ifndef EREMCHG +#define EREMCHG (-5078) +#endif +#ifndef ELIBACC +#define ELIBACC (-5079) +#endif +#ifndef ELIBBAD +#define ELIBBAD (-5080) +#endif +#ifndef ELIBSCN +#define ELIBSCN (-5081) +#endif +#ifndef ELIBMAX +#define ELIBMAX (-5082) +#endif +#ifndef ELIBEXEC +#define ELIBEXEC (-5083) +#endif +#ifndef EILSEQ +#define EILSEQ (-5084) +#endif +#ifndef ERESTART +#define ERESTART (-5085) +#endif +#ifndef ESTRPIPE +#define ESTRPIPE (-5086) +#endif +#ifndef EUSERS +#define EUSERS (-5087) +#endif +#ifndef ENOTSOCK +#define ENOTSOCK (-5088) +#endif +#ifndef EDESTADDRREQ +#define EDESTADDRREQ (-5089) +#endif +#ifndef EMSGSIZE +#define EMSGSIZE (-5090) +#endif +#ifndef EPROTOTYPE +#define EPROTOTYPE (-5091) +#endif +#ifndef ENOPROTOOPT +#define ENOPROTOOPT (-5092) +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT (-5093) +#endif +#ifndef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT (-5094) +#endif +#ifndef EOPNOTSUPP +#define EOPNOTSUPP (-5095) +#endif +#ifndef EPFNOSUPPORT +#define EPFNOSUPPORT (-5096) +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT (-5097) +#endif +#ifndef EADDRINUSE +#define EADDRINUSE (-5098) +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL (-5099) +#endif +#ifndef ENETDOWN +#define ENETDOWN (-5100) +#endif +#ifndef ENETUNREACH +#define ENETUNREACH (-5101) +#endif +#ifndef ENETRESET +#define ENETRESET (-5102) +#endif +#ifndef ECONNABORTED +#define ECONNABORTED (-5103) +#endif +#ifndef ECONNRESET +#define ECONNRESET (-5104) +#endif +#ifndef ENOBUFS +#define ENOBUFS (-5105) +#endif +#ifndef EISCONN +#define EISCONN (-5106) +#endif +#ifndef ENOTCONN +#define ENOTCONN (-5107) +#endif +#ifndef ESHUTDOWN +#define ESHUTDOWN (-5108) +#endif +#ifndef ETOOMANYREFS +#define ETOOMANYREFS (-5109) +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT (-5110) +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED (-5111) +#endif +#ifndef EHOSTDOWN +#define EHOSTDOWN (-5112) +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH (-5113) +#endif +#ifndef EALREADY +#define EALREADY (-5114) +#endif +#ifndef EINPROGRESS +#define EINPROGRESS (-5115) +#endif +#ifndef ESTALE +#define ESTALE (-5116) +#endif +#ifndef EUCLEAN +#define EUCLEAN (-5117) +#endif +#ifndef ENOTNAM +#define ENOTNAM (-5118) +#endif +#ifndef ENAVAIL +#define ENAVAIL (-5119) +#endif +#ifndef EISNAM +#define EISNAM (-5120) +#endif +#ifndef EREMOTEIO +#define EREMOTEIO (-5121) +#endif +#ifndef EDQUOT +#define EDQUOT (-5122) +#endif +#ifndef ENOMEDIUM +#define ENOMEDIUM (-5123) +#endif +#ifndef EMEDIUMTYPE +#define EMEDIUMTYPE (-5124) +#endif +#ifndef ECANCELED +#define ECANCELED (-5125) +#endif +#ifndef ENOKEY +#define ENOKEY (-5126) +#endif +#ifndef EKEYEXPIRED +#define EKEYEXPIRED (-5127) +#endif +#ifndef EKEYREVOKED +#define EKEYREVOKED (-5128) +#endif +#ifndef EKEYREJECTED +#define EKEYREJECTED (-5129) +#endif +#ifndef EOWNERDEAD +#define EOWNERDEAD (-5130) +#endif +#ifndef ENOTRECOVERABLE +#define ENOTRECOVERABLE (-5131) +#endif +#ifndef ERFKILL +#define ERFKILL (-5132) +#endif +#ifndef EPROCLIM +#define EPROCLIM (-6067) +#endif +#ifndef EBADRPC +#define EBADRPC (-6072) +#endif +#ifndef ERPCMISMATCH +#define ERPCMISMATCH (-6073) +#endif +#ifndef EPROGUNAVAIL +#define EPROGUNAVAIL (-6074) +#endif +#ifndef EPROGMISMATCH +#define EPROGMISMATCH (-6075) +#endif +#ifndef EPROCUNAVAIL +#define EPROCUNAVAIL (-6076) +#endif +#ifndef EFTYPE +#define EFTYPE (-6079) +#endif +#ifndef EAUTH +#define EAUTH (-6080) +#endif +#ifndef ENEEDAUTH +#define ENEEDAUTH (-6081) +#endif +#ifndef ENOATTR +#define ENOATTR (-6087) +#endif +#ifndef ENOTCAPABLE +#define ENOTCAPABLE (-6093) +#endif + +#endif diff --git a/src/libsodium/curvecp/hexparse.c b/src/libsodium/curvecp/hexparse.c new file mode 100644 index 00000000..43bfe044 --- /dev/null +++ b/src/libsodium/curvecp/hexparse.c @@ -0,0 +1,25 @@ +#include "hexparse.h" + +static int hexdigit(char x) +{ + if (x >= '0' && x <= '9') return x - '0'; + if (x >= 'a' && x <= 'f') return 10 + (x - 'a'); + if (x >= 'A' && x <= 'F') return 10 + (x - 'A'); + return -1; +} + +int hexparse(unsigned char *y,long long len,const char *x) +{ + if (!x) return 0; + while (len > 0) { + int digit0; + int digit1; + digit0 = hexdigit(x[0]); if (digit0 == -1) return 0; + digit1 = hexdigit(x[1]); if (digit1 == -1) return 0; + *y++ = digit1 + 16 * digit0; + --len; + x += 2; + } + if (x[0]) return 0; + return 1; +} diff --git a/src/libsodium/curvecp/hexparse.h b/src/libsodium/curvecp/hexparse.h new file mode 100644 index 00000000..4e88e187 --- /dev/null +++ b/src/libsodium/curvecp/hexparse.h @@ -0,0 +1,6 @@ +#ifndef HEXPARSE_H +#define HEXPARSE_H + +extern int hexparse(unsigned char *,long long,const char *); + +#endif diff --git a/src/libsodium/curvecp/load.c b/src/libsodium/curvecp/load.c new file mode 100644 index 00000000..0cd4e43d --- /dev/null +++ b/src/libsodium/curvecp/load.c @@ -0,0 +1,33 @@ +#include +#include "open.h" +#include "e.h" +#include "load.h" + +static int readall(int fd,void *x,long long xlen) +{ + long long r; + while (xlen > 0) { + r = xlen; + if (r > 1048576) r = 1048576; + r = read(fd,x,r); + if (r == 0) errno = EPROTO; + if (r <= 0) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue; + return -1; + } + x += r; + xlen -= r; + } + return 0; +} + +int load(const char *fn,void *x,long long xlen) +{ + int fd; + int r; + fd = open_read(fn); + if (fd == -1) return -1; + r = readall(fd,x,xlen); + close(fd); + return r; +} diff --git a/src/libsodium/curvecp/load.h b/src/libsodium/curvecp/load.h new file mode 100644 index 00000000..9ff1ab2c --- /dev/null +++ b/src/libsodium/curvecp/load.h @@ -0,0 +1,6 @@ +#ifndef LOAD_H +#define LOAD_H + +extern int load(const char *,void *,long long); + +#endif diff --git a/src/libsodium/curvecp/nameparse.c b/src/libsodium/curvecp/nameparse.c new file mode 100644 index 00000000..f6386d73 --- /dev/null +++ b/src/libsodium/curvecp/nameparse.c @@ -0,0 +1,19 @@ +#include "nameparse.h" + +int nameparse(unsigned char *s,const char *x) +{ + long long pos; + long long j; + if (!x) return 0; + for (pos = 0;pos < 256;++pos) s[pos] = 0; + pos = 0; + while (*x) { + if (*x == '.') { ++x; continue; } + for (j = 0;x[j];++j) if (x[j] == '.') break; + if (j > 63) return 0; + if (pos < 0 || pos >= 256) return 0; s[pos++] = j; + while (j > 0) { if (pos < 0 || pos >= 256) return 0; s[pos++] = *x++; --j; } + } + if (pos < 0 || pos >= 256) return 0; s[pos++] = 0; + return 1; +} diff --git a/src/libsodium/curvecp/nameparse.h b/src/libsodium/curvecp/nameparse.h new file mode 100644 index 00000000..97c56e8b --- /dev/null +++ b/src/libsodium/curvecp/nameparse.h @@ -0,0 +1,6 @@ +#ifndef NAMEPARSE_H +#define NAMEPARSE_H + +extern int nameparse(unsigned char *,const char *); + +#endif diff --git a/src/libsodium/curvecp/nanoseconds.c b/src/libsodium/curvecp/nanoseconds.c new file mode 100644 index 00000000..de5309d5 --- /dev/null +++ b/src/libsodium/curvecp/nanoseconds.c @@ -0,0 +1,19 @@ +#include +#include +#include "nanoseconds.h" + +/* XXX: Y2036 problems; should upgrade to a 128-bit type for this */ +/* XXX: nanosecond granularity limits users to 1 terabyte per second */ + +long long nanoseconds(void) +{ +#ifdef CLOCK_REALTIME + struct timespec t; + if (clock_gettime(CLOCK_REALTIME,&t) != 0) return -1; + return t.tv_sec * 1000000000LL + t.tv_nsec; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000000LL + tv.tv_usec * 1000LL; +#endif +} diff --git a/src/libsodium/curvecp/nanoseconds.h b/src/libsodium/curvecp/nanoseconds.h new file mode 100644 index 00000000..eb72ec0f --- /dev/null +++ b/src/libsodium/curvecp/nanoseconds.h @@ -0,0 +1,6 @@ +#ifndef NANOSECONDS_H +#define NANOSECONDS_H + +extern long long nanoseconds(void); + +#endif diff --git a/src/libsodium/curvecp/open.h b/src/libsodium/curvecp/open.h new file mode 100644 index 00000000..a6ef9ec4 --- /dev/null +++ b/src/libsodium/curvecp/open.h @@ -0,0 +1,10 @@ +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(const char *); +extern int open_write(const char *); +extern int open_lock(const char *); +extern int open_cwd(void); +extern int open_pipe(int *); + +#endif diff --git a/src/libsodium/curvecp/open_cwd.c b/src/libsodium/curvecp/open_cwd.c new file mode 100644 index 00000000..65d53bcd --- /dev/null +++ b/src/libsodium/curvecp/open_cwd.c @@ -0,0 +1,6 @@ +#include "open.h" + +int open_cwd(void) +{ + return open_read("."); +} diff --git a/src/libsodium/curvecp/open_lock.c b/src/libsodium/curvecp/open_lock.c new file mode 100644 index 00000000..898f3b60 --- /dev/null +++ b/src/libsodium/curvecp/open_lock.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include "open.h" + +int open_lock(const char *fn) +{ +#ifdef O_CLOEXEC + int fd = open(fn,O_RDWR | O_CLOEXEC); + if (fd == -1) return -1; +#else + int fd = open(fn,O_RDWR); + if (fd == -1) return -1; + fcntl(fd,F_SETFD,1); +#endif + if (lockf(fd,F_LOCK,0) == -1) { close(fd); return -1; } + return fd; +} diff --git a/src/libsodium/curvecp/open_pipe.c b/src/libsodium/curvecp/open_pipe.c new file mode 100644 index 00000000..2fc2b1af --- /dev/null +++ b/src/libsodium/curvecp/open_pipe.c @@ -0,0 +1,15 @@ +#include +#include +#include "open.h" +#include "blocking.h" + +int open_pipe(int *fd) +{ + int i; + if (pipe(fd) == -1) return -1; + for (i = 0;i < 2;++i) { + fcntl(fd[i],F_SETFD,1); + blocking_disable(fd[i]); + } + return 0; +} diff --git a/src/libsodium/curvecp/open_read.c b/src/libsodium/curvecp/open_read.c new file mode 100644 index 00000000..cea667b5 --- /dev/null +++ b/src/libsodium/curvecp/open_read.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include "open.h" + +int open_read(const char *fn) +{ +#ifdef O_CLOEXEC + return open(fn,O_RDONLY | O_NONBLOCK | O_CLOEXEC); +#else + int fd = open(fn,O_RDONLY | O_NONBLOCK); + if (fd == -1) return -1; + fcntl(fd,F_SETFD,1); + return fd; +#endif +} diff --git a/src/libsodium/curvecp/open_write.c b/src/libsodium/curvecp/open_write.c new file mode 100644 index 00000000..e23752d1 --- /dev/null +++ b/src/libsodium/curvecp/open_write.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include "open.h" + +int open_write(const char *fn) +{ +#ifdef O_CLOEXEC + return open(fn,O_CREAT | O_WRONLY | O_NONBLOCK | O_CLOEXEC,0644); +#else + int fd = open(fn,O_CREAT | O_WRONLY | O_NONBLOCK,0644); + if (fd == -1) return -1; + fcntl(fd,F_SETFD,1); + return fd; +#endif +} diff --git a/src/libsodium/curvecp/portparse.c b/src/libsodium/curvecp/portparse.c new file mode 100644 index 00000000..37e4caca --- /dev/null +++ b/src/libsodium/curvecp/portparse.c @@ -0,0 +1,14 @@ +#include "portparse.h" + +int portparse(unsigned char *y,const char *x) +{ + long long d = 0; + long long j; + for (j = 0;j < 5 && x[j] >= '0' && x[j] <= '9';++j) + d = d * 10 + (x[j] - '0'); + if (j == 0) return 0; + if (x[j]) return 0; + y[0] = d >> 8; + y[1] = d; + return 1; +} diff --git a/src/libsodium/curvecp/portparse.h b/src/libsodium/curvecp/portparse.h new file mode 100644 index 00000000..99a17748 --- /dev/null +++ b/src/libsodium/curvecp/portparse.h @@ -0,0 +1,6 @@ +#ifndef PORTPARSE_H +#define PORTPARSE_H + +extern int portparse(unsigned char *,const char *); + +#endif diff --git a/src/libsodium/curvecp/randommod.c b/src/libsodium/curvecp/randommod.c new file mode 100644 index 00000000..575a627b --- /dev/null +++ b/src/libsodium/curvecp/randommod.c @@ -0,0 +1,14 @@ +#include "randombytes.h" + +/* XXX: current implementation is limited to n<2^55 */ + +long long randommod(long long n) +{ + long long result = 0; + long long j; + unsigned char r[32]; + if (n <= 1) return 0; + randombytes(r,32); + for (j = 0;j < 32;++j) result = (result * 256 + (unsigned long long) r[j]) % n; + return result; +} diff --git a/src/libsodium/curvecp/randommod.h b/src/libsodium/curvecp/randommod.h new file mode 100644 index 00000000..2b8405d6 --- /dev/null +++ b/src/libsodium/curvecp/randommod.h @@ -0,0 +1,6 @@ +#ifndef RANDOMMOD_H +#define RANDOMMOD_H + +extern long long randommod(long long); + +#endif diff --git a/src/libsodium/curvecp/safenonce.c b/src/libsodium/curvecp/safenonce.c new file mode 100644 index 00000000..cfcabcd2 --- /dev/null +++ b/src/libsodium/curvecp/safenonce.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include "crypto_uint64.h" +#include "uint64_pack.h" +#include "uint64_unpack.h" +#include "savesync.h" +#include "open.h" +#include "load.h" +#include "randombytes.h" +#include "safenonce.h" + +#include "crypto_block.h" +#if crypto_block_BYTES != 16 +error! +#endif +#if crypto_block_KEYBYTES != 32 +error! +#endif + +/* +Output: 128-bit nonce y[0],...,y[15]. +Reads and writes existing 8-byte file ".expertsonly/noncecounter", +locked via existing 1-byte file ".expertsonly/lock". +Also reads existing 32-byte file ".expertsonly/noncekey". +Not thread-safe. + +Invariants: +This process is free to use counters that are >=counterlow and =counterhigh. + +XXX: should rewrite file in background, rather than briefly pausing +*/ + +static crypto_uint64 counterlow = 0; +static crypto_uint64 counterhigh = 0; + +static unsigned char flagkeyloaded = 0; +static unsigned char noncekey[32]; +static unsigned char data[16]; + +int safenonce(unsigned char *y,int flaglongterm) +{ + if (!flagkeyloaded) { + int fdlock; + fdlock = open_lock(".expertsonly/lock"); + if (fdlock == -1) return -1; + if (load(".expertsonly/noncekey",noncekey,sizeof noncekey) == -1) { close(fdlock); return -1; } + close(fdlock); + flagkeyloaded = 1; + } + + if (counterlow >= counterhigh) { + int fdlock; + fdlock = open_lock(".expertsonly/lock"); + if (fdlock == -1) return -1; + if (load(".expertsonly/noncecounter",data,8) == -1) { close(fdlock); return -1; } + counterlow = uint64_unpack(data); + if (flaglongterm) + counterhigh = counterlow + 1048576; + else + counterhigh = counterlow + 1; + uint64_pack(data,counterhigh); + if (savesync(".expertsonly/noncecounter",data,8) == -1) { close(fdlock); return -1; } + close(fdlock); + } + + randombytes(data + 8,8); + uint64_pack(data,counterlow++); + crypto_block(y,data,noncekey); + + return 0; +} diff --git a/src/libsodium/curvecp/safenonce.h b/src/libsodium/curvecp/safenonce.h new file mode 100644 index 00000000..c01271aa --- /dev/null +++ b/src/libsodium/curvecp/safenonce.h @@ -0,0 +1,6 @@ +#ifndef SAFENONCE_H +#define SAFENONCE_H + +extern int safenonce(unsigned char *,int); + +#endif diff --git a/src/libsodium/curvecp/savesync.c b/src/libsodium/curvecp/savesync.c new file mode 100644 index 00000000..73074a4b --- /dev/null +++ b/src/libsodium/curvecp/savesync.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include "open.h" +#include "savesync.h" +#include "writeall.h" + +static int writesync(int fd,const void *x,long long xlen) +{ + if (writeall(fd,x,xlen) == -1) return -1; + return fsync(fd); +} + +int savesync(const char *fn,const void *x,long long xlen) +{ + int fd; + int r; + fd = open_write(fn); + if (fd == -1) return -1; + r = writesync(fd,x,xlen); + close(fd); + return r; +} diff --git a/src/libsodium/curvecp/savesync.h b/src/libsodium/curvecp/savesync.h new file mode 100644 index 00000000..4c0cd3d2 --- /dev/null +++ b/src/libsodium/curvecp/savesync.h @@ -0,0 +1,6 @@ +#ifndef SAVESYNC_H +#define SAVESYNC_H + +extern int savesync(const char *,const void *,long long); + +#endif diff --git a/src/libsodium/curvecp/socket.h b/src/libsodium/curvecp/socket.h new file mode 100644 index 00000000..9fab01c7 --- /dev/null +++ b/src/libsodium/curvecp/socket.h @@ -0,0 +1,9 @@ +#ifndef SOCKET_H +#define SOCKET_H + +extern int socket_udp(void); +extern int socket_bind(int,const unsigned char *,const unsigned char *); +extern int socket_send(int,const unsigned char *,long long,const unsigned char *,const unsigned char *); +extern long long socket_recv(int,unsigned char *,long long,unsigned char *,unsigned char *); + +#endif diff --git a/src/libsodium/curvecp/socket_bind.c b/src/libsodium/curvecp/socket_bind.c new file mode 100644 index 00000000..9e36925d --- /dev/null +++ b/src/libsodium/curvecp/socket_bind.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include "socket.h" +#include "byte.h" + +int socket_bind(int fd,const unsigned char *ip,const unsigned char *port) +{ + struct sockaddr_in sa; + byte_zero(&sa,sizeof sa); + byte_copy(&sa.sin_addr,4,ip); + byte_copy(&sa.sin_port,2,port); + return bind(fd,(struct sockaddr *) &sa,sizeof sa); +} diff --git a/src/libsodium/curvecp/socket_recv.c b/src/libsodium/curvecp/socket_recv.c new file mode 100644 index 00000000..2255771e --- /dev/null +++ b/src/libsodium/curvecp/socket_recv.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include "e.h" +#include "socket.h" +#include "byte.h" + +long long socket_recv(int fd,unsigned char *x,long long xlen,unsigned char *ip,unsigned char *port) +{ + struct sockaddr_in sa; + socklen_t salen; + int r; + + if (xlen < 0) { errno = EPROTO; return -1; } + if (xlen > 1048576) xlen = 1048576; + + byte_zero(&sa,sizeof sa); + salen = sizeof sa; + r = recvfrom(fd,x,xlen,0,(struct sockaddr *) &sa,&salen); + byte_copy(ip,4,&sa.sin_addr); + byte_copy(port,2,&sa.sin_port); + return r; +} diff --git a/src/libsodium/curvecp/socket_send.c b/src/libsodium/curvecp/socket_send.c new file mode 100644 index 00000000..8efea6b3 --- /dev/null +++ b/src/libsodium/curvecp/socket_send.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include "e.h" +#include "socket.h" +#include "byte.h" + +int socket_send(int fd,const unsigned char *x,long long xlen,const unsigned char *ip,const unsigned char *port) +{ + struct sockaddr_in sa; + + if (xlen < 0 || xlen > 1048576) { errno = EPROTO; return -1; } + + byte_zero(&sa,sizeof sa); + sa.sin_family = AF_INET; + byte_copy(&sa.sin_addr,4,ip); + byte_copy(&sa.sin_port,2,port); + return sendto(fd,x,xlen,0,(struct sockaddr *) &sa,sizeof sa); +} diff --git a/src/libsodium/curvecp/socket_udp.c b/src/libsodium/curvecp/socket_udp.c new file mode 100644 index 00000000..f64762f1 --- /dev/null +++ b/src/libsodium/curvecp/socket_udp.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include "socket.h" +#include "blocking.h" + +static void enable_bsd_fragmentation(int fd) +{ +#ifdef IP_DONTFRAG + const int x = 0; + setsockopt(fd,SOL_IP,IP_DONTFRAG,&x,sizeof x); +#endif +} + +static void enable_linux_fragmentation(int fd) +{ +#ifdef IP_MTU_DISCOVER +#ifdef IP_PMTUDISC_DONT + const int x = IP_PMTUDISC_DONT; + setsockopt(fd,SOL_IP,IP_MTU_DISCOVER,&x,sizeof x); +#endif +#endif +} + +int socket_udp(void) +{ + int fd = socket(PF_INET,SOCK_DGRAM,0); + if (fd == -1) return -1; + fcntl(fd,F_SETFD,1); + blocking_disable(fd); + enable_bsd_fragmentation(fd); + enable_linux_fragmentation(fd); + return fd; +} diff --git a/src/libsodium/curvecp/uint16_pack.c b/src/libsodium/curvecp/uint16_pack.c new file mode 100644 index 00000000..f3761035 --- /dev/null +++ b/src/libsodium/curvecp/uint16_pack.c @@ -0,0 +1,7 @@ +#include "uint16_pack.h" + +void uint16_pack(unsigned char *y,crypto_uint16 x) +{ + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; +} diff --git a/src/libsodium/curvecp/uint16_pack.h b/src/libsodium/curvecp/uint16_pack.h new file mode 100644 index 00000000..6c5b65e1 --- /dev/null +++ b/src/libsodium/curvecp/uint16_pack.h @@ -0,0 +1,8 @@ +#ifndef UINT16_PACK_H +#define UINT16_PACK_H + +#include "crypto_uint16.h" + +extern void uint16_pack(unsigned char *,crypto_uint16); + +#endif diff --git a/src/libsodium/curvecp/uint16_unpack.c b/src/libsodium/curvecp/uint16_unpack.c new file mode 100644 index 00000000..b4e74ee4 --- /dev/null +++ b/src/libsodium/curvecp/uint16_unpack.c @@ -0,0 +1,9 @@ +#include "uint16_unpack.h" + +crypto_uint16 uint16_unpack(const unsigned char *x) +{ + crypto_uint16 result; + result = x[1]; + result <<= 8; result |= x[0]; + return result; +} diff --git a/src/libsodium/curvecp/uint16_unpack.h b/src/libsodium/curvecp/uint16_unpack.h new file mode 100644 index 00000000..3e3aedfc --- /dev/null +++ b/src/libsodium/curvecp/uint16_unpack.h @@ -0,0 +1,8 @@ +#ifndef UINT16_UNPACK_H +#define UINT16_UNPACK_H + +#include "crypto_uint16.h" + +extern crypto_uint16 uint16_unpack(const unsigned char *); + +#endif diff --git a/src/libsodium/curvecp/uint32_pack.c b/src/libsodium/curvecp/uint32_pack.c new file mode 100644 index 00000000..d54fe542 --- /dev/null +++ b/src/libsodium/curvecp/uint32_pack.c @@ -0,0 +1,9 @@ +#include "uint32_pack.h" + +void uint32_pack(unsigned char *y,crypto_uint32 x) +{ + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; +} diff --git a/src/libsodium/curvecp/uint32_pack.h b/src/libsodium/curvecp/uint32_pack.h new file mode 100644 index 00000000..efdf7919 --- /dev/null +++ b/src/libsodium/curvecp/uint32_pack.h @@ -0,0 +1,8 @@ +#ifndef UINT32_PACK_H +#define UINT32_PACK_H + +#include "crypto_uint32.h" + +extern void uint32_pack(unsigned char *,crypto_uint32); + +#endif diff --git a/src/libsodium/curvecp/uint32_unpack.c b/src/libsodium/curvecp/uint32_unpack.c new file mode 100644 index 00000000..adde6987 --- /dev/null +++ b/src/libsodium/curvecp/uint32_unpack.c @@ -0,0 +1,11 @@ +#include "uint32_unpack.h" + +crypto_uint32 uint32_unpack(const unsigned char *x) +{ + crypto_uint32 result; + result = x[3]; + result <<= 8; result |= x[2]; + result <<= 8; result |= x[1]; + result <<= 8; result |= x[0]; + return result; +} diff --git a/src/libsodium/curvecp/uint32_unpack.h b/src/libsodium/curvecp/uint32_unpack.h new file mode 100644 index 00000000..dd65f365 --- /dev/null +++ b/src/libsodium/curvecp/uint32_unpack.h @@ -0,0 +1,8 @@ +#ifndef UINT32_UNPACK_H +#define UINT32_UNPACK_H + +#include "crypto_uint32.h" + +extern crypto_uint32 uint32_unpack(const unsigned char *); + +#endif diff --git a/src/libsodium/curvecp/uint64_pack.c b/src/libsodium/curvecp/uint64_pack.c new file mode 100644 index 00000000..898a80a3 --- /dev/null +++ b/src/libsodium/curvecp/uint64_pack.c @@ -0,0 +1,13 @@ +#include "uint64_pack.h" + +void uint64_pack(unsigned char *y,crypto_uint64 x) +{ + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; + *y++ = x; x >>= 8; +} diff --git a/src/libsodium/curvecp/uint64_pack.h b/src/libsodium/curvecp/uint64_pack.h new file mode 100644 index 00000000..be8330fd --- /dev/null +++ b/src/libsodium/curvecp/uint64_pack.h @@ -0,0 +1,8 @@ +#ifndef UINT64_PACK_H +#define UINT64_PACK_H + +#include "crypto_uint64.h" + +extern void uint64_pack(unsigned char *,crypto_uint64); + +#endif diff --git a/src/libsodium/curvecp/uint64_unpack.c b/src/libsodium/curvecp/uint64_unpack.c new file mode 100644 index 00000000..2d69bf72 --- /dev/null +++ b/src/libsodium/curvecp/uint64_unpack.c @@ -0,0 +1,15 @@ +#include "uint64_unpack.h" + +crypto_uint64 uint64_unpack(const unsigned char *x) +{ + crypto_uint64 result; + result = x[7]; + result <<= 8; result |= x[6]; + result <<= 8; result |= x[5]; + result <<= 8; result |= x[4]; + result <<= 8; result |= x[3]; + result <<= 8; result |= x[2]; + result <<= 8; result |= x[1]; + result <<= 8; result |= x[0]; + return result; +} diff --git a/src/libsodium/curvecp/uint64_unpack.h b/src/libsodium/curvecp/uint64_unpack.h new file mode 100644 index 00000000..f40e7a8a --- /dev/null +++ b/src/libsodium/curvecp/uint64_unpack.h @@ -0,0 +1,8 @@ +#ifndef UINT64_UNPACK_H +#define UINT64_UNPACK_H + +#include "crypto_uint64.h" + +extern crypto_uint64 uint64_unpack(const unsigned char *); + +#endif diff --git a/src/libsodium/curvecp/writeall.c b/src/libsodium/curvecp/writeall.c new file mode 100644 index 00000000..58f93011 --- /dev/null +++ b/src/libsodium/curvecp/writeall.c @@ -0,0 +1,27 @@ +#include +#include +#include "e.h" +#include "writeall.h" + +int writeall(int fd,const void *x,long long xlen) +{ + long long w; + while (xlen > 0) { + w = xlen; + if (w > 1048576) w = 1048576; + w = write(fd,x,w); + if (w < 0) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + struct pollfd p; + p.fd = fd; + p.events = POLLOUT | POLLERR; + poll(&p,1,-1); + continue; + } + return -1; + } + x += w; + xlen -= w; + } + return 0; +} diff --git a/src/libsodium/curvecp/writeall.h b/src/libsodium/curvecp/writeall.h new file mode 100644 index 00000000..92341236 --- /dev/null +++ b/src/libsodium/curvecp/writeall.h @@ -0,0 +1,6 @@ +#ifndef WRITEALL_H +#define WRITEALL_H + +extern int writeall(int,const void *,long long); + +#endif