int main(int argc, char **argv) { unsigned char *x; unsigned long long xlen; if (argv[0]) if (argv[1]) { if (str_equal(argv[1], "-h")) die_usage(0); } /* get password */ x = (unsigned char *)env_get("PASSWORD"); if (!x) { errno = 0; die_usage("$PASSWORD not set"); } xlen = str_len((char *)x); /* create salt */ randombytes(s, sizeof s); /* derive key */ if (sha512hmacpbkdf2(h, sizeof h, x, xlen, s, sizeof s, ROUNDS) == -1) die_fatal("unable to derive keys", 0); byte_zero(x, xlen); /* create nonce */ randombytes(n, sizeof n); uint64_pack(n, nanoseconds()); sha512(nk, (unsigned char *)MAGIC, MAGICBYTES); crypto_block_aes256vulnerable(n, n, nk); /* initialize */ crypto_init(&ctx, n, h, MAGIC); randombytes(h, sizeof h); sha512_init(&shactx); /* write header */ if (writeall(1, MAGIC, MAGICBYTES) == -1) die_fatal("unable to write output", 0); if (writeall(1, s, sizeof s) == -1) die_fatal("unable to write output", 0); randombytes(s, sizeof s); if (writeall(1, n, sizeof n) == -1) die_fatal("unable to write output", 0); for (;;) { inlen = readblock(in, BLOCK); if (inlen != BLOCK) break; if (sha512_block(&shactx, in, inlen) != 0) die_fatal("unable to compute hash", 0); if (crypto_block(&ctx, in, inlen) != 0) die_fatal("unable to encrypt stream", 0); if (writeall(1, in, inlen) == -1) die_fatal("unable to write output", 0); } if (sha512_last(&shactx, h, in, inlen) != 0) die_fatal("unable to compute hash", 0); byte_copy(in + inlen, CHECKSUMBYTES, h); inlen += CHECKSUMBYTES; if (crypto_last(&ctx, in, inlen) != 0) die_fatal("unable to encrypt stream", 0); if (writeall(1, in, inlen) == -1) die_fatal("unable to write output", 0); if (fsyncfd(1) == -1) die_fatal("unable to write output", 0); cleanup(); _exit(0); }
void ttymodes_packt (char *s, ttymodes const *t) { unsigned int i ; uint32_pack(s, (uint32)NCCS) ; s += 4 ; uint64_pack(s, (uint64)t->ti.c_iflag) ; s += 8 ; uint64_pack(s, (uint64)t->ti.c_oflag) ; s += 8 ; uint64_pack(s, (uint64)t->ti.c_cflag) ; s += 8 ; uint64_pack(s, (uint64)t->ti.c_lflag) ; s += 8 ; for (i = 0 ; i < NCCS ; i++) { uint64_pack(s, t->ti.c_cc[i]) ; s += 8 ; } }
int validate_crypto_write(unsigned char *buffer, UNUSED(uint64_t length)) { unsigned char *block; unsigned char *ciphertextpadded; unsigned char nonce[crypto_box_NONCEBYTES]; unsigned char lengthpacked[40]; unsigned char lengthbox[40] = {0}; uint64_t unpackedlen; uint64_t packetnonce; uint64_t ciphertextlen; uint64_t blocklen; /* unpack nonce and check it's validity */ packetnonce = uint64_unpack(buffer + 8); /* nonce is prefixed with 16-byte string "splonbox-client" */ memcpy(nonce, "splonebox-server", 16); memcpy(nonce + 16, buffer + 8, 8); memcpy(lengthbox + 16, buffer + 16, 24); if (crypto_box_open_afternm(lengthpacked, lengthbox, 40, nonce, cc.clientshortservershort)) { return (-1); } unpackedlen = uint64_unpack(lengthpacked + 32); ciphertextlen = unpackedlen - 24; blocklen = unpackedlen - 40; block = MALLOC_ARRAY(ciphertextlen, unsigned char); ciphertextpadded = CALLOC(ciphertextlen, unsigned char); if (block == NULL || ciphertextpadded == NULL) return (-1); memcpy(ciphertextpadded + 16, buffer + 40, blocklen); uint64_pack(nonce + 16, packetnonce + 2); if (crypto_box_open_afternm(block, ciphertextpadded, ciphertextlen, nonce, cc.clientshortservershort)) { FREE(block); FREE(ciphertextpadded); return (-1); } FREE(block); FREE(ciphertextpadded); return (0); }
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) nextaction = 0; if (blocknum < OUTGOING) if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes)) if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; if (earliestblocktime) { long long nextretry = earliestblocktime + rtt_timeout; if (nextretry < lastblocktime + nsecperblock) nextretry = lastblocktime + nsecperblock; if (nextretry < nextaction) nextaction = nextretry; } if (messagenum) if (!watchtochild) nextaction = 0; if (nextaction <= recent) timeout = 0; else timeout = (nextaction - recent) / 1000000 + 1; /* XXX */ if (childdied) timeout = 10; pollret = poll(p,q - p,timeout); if (pollret < 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 */ if (childdied && !pollret) { if (childdied++ > 999) goto finish; } /* 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); /* XXX */ if (!childdied){ if (waitpid(child,&childstatus, WNOHANG) > 0) { close(tochild[1]); tochild[1] = -1; childdied = 1; } } } if (!childdied) { do { r = waitpid(child,&childstatus,0); } while (r == -1 && errno == EINTR); } finish: if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } return WEXITSTATUS(childstatus); }
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); }
void tai_pack_little (char *s, struct tai const *t) { uint64_pack(s, tai_sec(t)) ; }
void functional_crypto(UNUSED(void **state)) { unsigned char nonce[crypto_box_NONCEBYTES]; unsigned char initiatenonce[crypto_box_NONCEBYTES]; unsigned char hellopacket[192] = {0}; unsigned char initiatepacket[256] = {0}; unsigned char messagepacket[120]; unsigned char messagepacketout[120] = {0}; unsigned char allzeroboxed[96] = {0}; unsigned char initiatebox[160] = {0}; unsigned char pubkeybox[96] = {0}; unsigned char lengthbox[40] = {0}; uint64_t plaintextlen; uint64_t readlen; outputstream write; connect_to_db(); wrap_crypto_write = false; assert_int_equal(0, filesystem_load(".keys/server-long-term.pub", serverlongtermpk, sizeof serverlongtermpk)); cc.nonce = (uint64_t) randommod(281474976710656LL); if (!ISODD(cc.nonce)) { cc.nonce++; } cc.receivednonce = 0; cc.state = TUNNEL_INITIAL; memcpy(nonce, "splonebox-client", 16); uint64_pack(nonce + 16, cc.nonce); /* pack hello packet */ memcpy(hellopacket, "oqQN2kaH", 8); /* pack compressed nonce */ memcpy(hellopacket + 104, nonce + 16, 8); /* generate client ephemeral keys */ if (crypto_box_keypair(clientlongtermpk, clientlongtermsk) != 0) return; /* generate client ephemeral keys */ if (crypto_box_keypair(clientshorttermpk, clientshorttermsk) != 0) return; memcpy(hellopacket + 8, clientshorttermpk, 32); assert_int_equal(0, crypto_box(allzeroboxed, allzeroboxed, 96, nonce, serverlongtermpk, clientshorttermsk)); memcpy(hellopacket + 112, allzeroboxed + 16, 80); crypto_init(); /* positiv test */ assert_int_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); /* wrong identifier */ memcpy(hellopacket, "deadbeef", 8); assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); memcpy(hellopacket, "oqQN2kaH", 8); /* wrong nonce */ cc.receivednonce = cc.nonce + 1; assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); cc.receivednonce = 0; /* wrong pubkey */ memset(hellopacket + 8, '0', 32); assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); memcpy(hellopacket + 8, clientshorttermpk, 32); assert_int_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); /* crypto_recv_initiate() test */ /* pack initiate packet */ memcpy(initiatepacket, "oqQN2kaI", 8); memcpy(initiatepacket + 8, cookie, 96); /* pack compressed nonce */ memcpy(initiatepacket + 104, nonce + 16, 8); memcpy(initiatebox + 32, clientlongtermpk, 32); randombytes(initiatebox + 64, 16); memcpy(initiatenonce, "splonePV", 8); memcpy(initiatenonce + 8, initiatebox + 64, 16); memcpy(pubkeybox + 32, clientshorttermpk, 32); memcpy(pubkeybox + 64, servershorttermpk, 32); assert_int_equal(0, crypto_box(pubkeybox, pubkeybox, 96, initiatenonce, serverlongtermpk, clientlongtermsk)); memcpy(initiatebox + 80, pubkeybox + 16, 80); assert_int_equal(0, crypto_box(initiatebox, initiatebox, 160, nonce, servershorttermpk, clientshorttermsk)); memcpy(initiatepacket + 112, initiatebox + 16, 144); /* without valid certificate */ assert_int_not_equal(0, crypto_recv_initiate(&cc, initiatepacket)); /* all plugins are allowed to connect */ db_authorized_set_whitelist_all(); assert_int_equal(0, crypto_recv_initiate(&cc, initiatepacket)); /* crypto_write() test */ assert_int_equal(0, crypto_write(&cc, (char*) allzeroboxed, sizeof(allzeroboxed), &write)); /* crypto_read() test */ /* pack message packet */ memcpy(messagepacket, "oqQN2kaM", 8); /* pack compressed nonce */ memcpy(nonce, "splonebox-client", 16); uint64_pack(nonce + 16, cc.nonce); memcpy(messagepacket + 8, nonce + 16, 8); uint64_pack(lengthbox + 32, 120); assert_int_equal(0, crypto_box(lengthbox, lengthbox, 40, nonce, servershorttermpk, clientshorttermsk)); memcpy(messagepacket + 16, lengthbox + 16, 24); uint64_pack(nonce + 16, cc.nonce + 2); memset(allzeroboxed, 0, 96); assert_int_equal(0, crypto_box_afternm(allzeroboxed, allzeroboxed, 96, nonce, cc.clientshortservershort)); memcpy(messagepacket + 40, allzeroboxed + 16, 80); assert_int_equal(0, crypto_verify_header(&cc, messagepacket, &readlen)); assert_int_equal(0, crypto_read(&cc, messagepacket, (char*)messagepacketout, readlen, &plaintextlen)); db_close(); }
static void uint64_pack_ntdate(char* dest,time_t date) { uint64_pack(dest,10000000ll * (date + 11644473600ll)); }