summaryrefslogtreecommitdiff
path: root/nacl/curvecp
diff options
context:
space:
mode:
authorirungentoo <irungentoo@gmail.com>2013-07-02 09:53:34 -0400
committerirungentoo <irungentoo@gmail.com>2013-07-02 09:53:34 -0400
commite2967396ac73cb7410787886cdaf072a184ffc49 (patch)
tree527a74d25a4a0705fc641994fd35bfab22662034 /nacl/curvecp
parent8928c817df345f29aa0b194743595aa11bd6a8ba (diff)
Added NaCl crypto library.
Diffstat (limited to 'nacl/curvecp')
-rw-r--r--nacl/curvecp/LIBS31
-rw-r--r--nacl/curvecp/README10
-rw-r--r--nacl/curvecp/SOURCES36
-rw-r--r--nacl/curvecp/TARGETS5
-rw-r--r--nacl/curvecp/blocking.c12
-rw-r--r--nacl/curvecp/blocking.h7
-rw-r--r--nacl/curvecp/byte.h8
-rw-r--r--nacl/curvecp/byte_copy.c8
-rw-r--r--nacl/curvecp/byte_isequal.c10
-rw-r--r--nacl/curvecp/byte_zero.c7
-rw-r--r--nacl/curvecp/crypto_block.c35
-rw-r--r--nacl/curvecp/crypto_block.h4
-rw-r--r--nacl/curvecp/curvecpclient.c476
-rw-r--r--nacl/curvecp/curvecpmakekey.c57
-rw-r--r--nacl/curvecp/curvecpmessage.c654
-rw-r--r--nacl/curvecp/curvecpprintkey.c46
-rw-r--r--nacl/curvecp/curvecpserver.c497
-rw-r--r--nacl/curvecp/die.c42
-rw-r--r--nacl/curvecp/die.h16
-rw-r--r--nacl/curvecp/e.c106
-rw-r--r--nacl/curvecp/e.h438
-rw-r--r--nacl/curvecp/hexparse.c25
-rw-r--r--nacl/curvecp/hexparse.h6
-rw-r--r--nacl/curvecp/load.c33
-rw-r--r--nacl/curvecp/load.h6
-rw-r--r--nacl/curvecp/nameparse.c19
-rw-r--r--nacl/curvecp/nameparse.h6
-rw-r--r--nacl/curvecp/nanoseconds.c12
-rw-r--r--nacl/curvecp/nanoseconds.h6
-rw-r--r--nacl/curvecp/open.h10
-rw-r--r--nacl/curvecp/open_cwd.c6
-rw-r--r--nacl/curvecp/open_lock.c19
-rw-r--r--nacl/curvecp/open_pipe.c15
-rw-r--r--nacl/curvecp/open_read.c17
-rw-r--r--nacl/curvecp/open_write.c17
-rw-r--r--nacl/curvecp/portparse.c14
-rw-r--r--nacl/curvecp/portparse.h6
-rw-r--r--nacl/curvecp/randommod.c14
-rw-r--r--nacl/curvecp/randommod.h6
-rw-r--r--nacl/curvecp/safenonce.c74
-rw-r--r--nacl/curvecp/safenonce.h6
-rw-r--r--nacl/curvecp/savesync.c24
-rw-r--r--nacl/curvecp/savesync.h6
-rw-r--r--nacl/curvecp/socket.h9
-rw-r--r--nacl/curvecp/socket_bind.c15
-rw-r--r--nacl/curvecp/socket_recv.c23
-rw-r--r--nacl/curvecp/socket_send.c19
-rw-r--r--nacl/curvecp/socket_udp.c36
-rw-r--r--nacl/curvecp/uint16_pack.c7
-rw-r--r--nacl/curvecp/uint16_pack.h8
-rw-r--r--nacl/curvecp/uint16_unpack.c9
-rw-r--r--nacl/curvecp/uint16_unpack.h8
-rw-r--r--nacl/curvecp/uint32_pack.c9
-rw-r--r--nacl/curvecp/uint32_pack.h8
-rw-r--r--nacl/curvecp/uint32_unpack.c11
-rw-r--r--nacl/curvecp/uint32_unpack.h8
-rw-r--r--nacl/curvecp/uint64_pack.c13
-rw-r--r--nacl/curvecp/uint64_pack.h8
-rw-r--r--nacl/curvecp/uint64_unpack.c15
-rw-r--r--nacl/curvecp/uint64_unpack.h8
-rw-r--r--nacl/curvecp/writeall.c27
-rw-r--r--nacl/curvecp/writeall.h6
62 files changed, 3099 insertions, 0 deletions
diff --git a/nacl/curvecp/LIBS b/nacl/curvecp/LIBS
new file mode 100644
index 00000000..2928c658
--- /dev/null
+++ b/nacl/curvecp/LIBS
@@ -0,0 +1,31 @@
1blocking.o
2byte_copy.o
3byte_isequal.o
4byte_zero.o
5crypto_block.o
6die.o
7e.o
8hexparse.o
9load.o
10nameparse.o
11nanoseconds.o
12open_cwd.o
13open_lock.o
14open_pipe.o
15open_read.o
16open_write.o
17portparse.o
18randommod.o
19safenonce.o
20savesync.o
21socket_bind.o
22socket_recv.o
23socket_send.o
24socket_udp.o
25uint16_pack.o
26uint16_unpack.o
27uint32_pack.o
28uint32_unpack.o
29uint64_pack.o
30uint64_unpack.o
31writeall.o
diff --git a/nacl/curvecp/README b/nacl/curvecp/README
new file mode 100644
index 00000000..1048c894
--- /dev/null
+++ b/nacl/curvecp/README
@@ -0,0 +1,10 @@
1Example of use (with nacl-20110221/build/*/bin in $PATH):
2 curvecpmakekey serverkey
3 curvecpprintkey serverkey > serverkey.hex
4 curvecpserver this.machine.name serverkey \
5 127.0.0.1 10000 31415926535897932384626433832795 \
6 curvecpmessage cat /usr/share/dict/words &
7 curvecpclient this.machine.name `cat serverkey.hex` \
8 127.0.0.1 10000 31415926535897932384626433832795 \
9 curvecpmessage -c sh -c 'nacl-sha512 <&6'
10 nacl-sha512 < /usr/share/dict/words
diff --git a/nacl/curvecp/SOURCES b/nacl/curvecp/SOURCES
new file mode 100644
index 00000000..3fc29751
--- /dev/null
+++ b/nacl/curvecp/SOURCES
@@ -0,0 +1,36 @@
1blocking
2byte_copy
3byte_isequal
4byte_zero
5crypto_block
6die
7e
8hexparse
9load
10nameparse
11nanoseconds
12open_cwd
13open_lock
14open_pipe
15open_read
16open_write
17portparse
18randommod
19safenonce
20savesync
21socket_bind
22socket_recv
23socket_send
24socket_udp
25uint16_pack
26uint16_unpack
27uint32_pack
28uint32_unpack
29uint64_pack
30uint64_unpack
31writeall
32curvecpprintkey
33curvecpmakekey
34curvecpclient
35curvecpserver
36curvecpmessage
diff --git a/nacl/curvecp/TARGETS b/nacl/curvecp/TARGETS
new file mode 100644
index 00000000..ab04272c
--- /dev/null
+++ b/nacl/curvecp/TARGETS
@@ -0,0 +1,5 @@
1curvecpprintkey
2curvecpmakekey
3curvecpclient
4curvecpserver
5curvecpmessage
diff --git a/nacl/curvecp/blocking.c b/nacl/curvecp/blocking.c
new file mode 100644
index 00000000..1594259c
--- /dev/null
+++ b/nacl/curvecp/blocking.c
@@ -0,0 +1,12 @@
1#include <fcntl.h>
2#include "blocking.h"
3
4void blocking_enable(int fd)
5{
6 fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK);
7}
8
9void blocking_disable(int fd)
10{
11 fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK);
12}
diff --git a/nacl/curvecp/blocking.h b/nacl/curvecp/blocking.h
new file mode 100644
index 00000000..9ba08a5e
--- /dev/null
+++ b/nacl/curvecp/blocking.h
@@ -0,0 +1,7 @@
1#ifndef BLOCKING_H
2#define BLOCKING_H
3
4extern void blocking_enable(int);
5extern void blocking_disable(int);
6
7#endif
diff --git a/nacl/curvecp/byte.h b/nacl/curvecp/byte.h
new file mode 100644
index 00000000..5dbfbd96
--- /dev/null
+++ b/nacl/curvecp/byte.h
@@ -0,0 +1,8 @@
1#ifndef BYTE_H
2#define BYTE_H
3
4extern void byte_zero(void *,long long);
5extern void byte_copy(void *,long long,const void *);
6extern int byte_isequal(const void *,long long,const void *);
7
8#endif
diff --git a/nacl/curvecp/byte_copy.c b/nacl/curvecp/byte_copy.c
new file mode 100644
index 00000000..55f446a4
--- /dev/null
+++ b/nacl/curvecp/byte_copy.c
@@ -0,0 +1,8 @@
1#include "byte.h"
2
3void byte_copy(void *yv,long long ylen,const void *xv)
4{
5 char *y = yv;
6 const char *x = xv;
7 while (ylen > 0) { *y++ = *x++; --ylen; }
8}
diff --git a/nacl/curvecp/byte_isequal.c b/nacl/curvecp/byte_isequal.c
new file mode 100644
index 00000000..625d361e
--- /dev/null
+++ b/nacl/curvecp/byte_isequal.c
@@ -0,0 +1,10 @@
1#include "byte.h"
2
3int byte_isequal(const void *yv,long long ylen,const void *xv)
4{
5 const unsigned char *y = yv;
6 const unsigned char *x = xv;
7 unsigned char diff = 0;
8 while (ylen > 0) { diff |= (*y++ ^ *x++); --ylen; }
9 return (256 - (unsigned int) diff) >> 8;
10}
diff --git a/nacl/curvecp/byte_zero.c b/nacl/curvecp/byte_zero.c
new file mode 100644
index 00000000..bdc1f799
--- /dev/null
+++ b/nacl/curvecp/byte_zero.c
@@ -0,0 +1,7 @@
1#include "byte.h"
2
3void byte_zero(void *yv,long long ylen)
4{
5 char *y = yv;
6 while (ylen > 0) { *y++ = 0; --ylen; }
7}
diff --git a/nacl/curvecp/crypto_block.c b/nacl/curvecp/crypto_block.c
new file mode 100644
index 00000000..5c7cf35e
--- /dev/null
+++ b/nacl/curvecp/crypto_block.c
@@ -0,0 +1,35 @@
1#include "crypto_block.h"
2#include "crypto_uint64.h"
3#include "uint64_unpack.h"
4#include "uint64_pack.h"
5
6/*
7TEA with double-size words.
8XXX: Switch to crypto_block_aes256.
9XXX: Build crypto_stream_aes256 on top of crypto_block_aes256.
10*/
11
12int crypto_block(
13 unsigned char *out,
14 const unsigned char *in,
15 const unsigned char *k
16)
17{
18 crypto_uint64 v0 = uint64_unpack(in + 0);
19 crypto_uint64 v1 = uint64_unpack(in + 8);
20 crypto_uint64 k0 = uint64_unpack(k + 0);
21 crypto_uint64 k1 = uint64_unpack(k + 8);
22 crypto_uint64 k2 = uint64_unpack(k + 16);
23 crypto_uint64 k3 = uint64_unpack(k + 24);
24 crypto_uint64 sum = 0;
25 crypto_uint64 delta = 0x9e3779b97f4a7c15;
26 int i;
27 for (i = 0;i < 32;++i) {
28 sum += delta;
29 v0 += ((v1<<7) + k0) ^ (v1 + sum) ^ ((v1>>12) + k1);
30 v1 += ((v0<<16) + k2) ^ (v0 + sum) ^ ((v0>>8) + k3);
31 }
32 uint64_pack(out + 0,v0);
33 uint64_pack(out + 8,v1);
34 return 0;
35}
diff --git a/nacl/curvecp/crypto_block.h b/nacl/curvecp/crypto_block.h
new file mode 100644
index 00000000..f13620c4
--- /dev/null
+++ b/nacl/curvecp/crypto_block.h
@@ -0,0 +1,4 @@
1#define crypto_block_BYTES 16
2#define crypto_block_KEYBYTES 32
3
4extern int crypto_block(unsigned char *,const unsigned char *,const unsigned char *);
diff --git a/nacl/curvecp/curvecpclient.c b/nacl/curvecp/curvecpclient.c
new file mode 100644
index 00000000..00793f00
--- /dev/null
+++ b/nacl/curvecp/curvecpclient.c
@@ -0,0 +1,476 @@
1#include <signal.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <sys/wait.h>
5#include <fcntl.h>
6#include <poll.h>
7#include <unistd.h>
8#include "e.h"
9#include "die.h"
10#include "load.h"
11#include "open.h"
12#include "byte.h"
13#include "socket.h"
14#include "uint64_pack.h"
15#include "uint64_unpack.h"
16#include "nanoseconds.h"
17#include "hexparse.h"
18#include "nameparse.h"
19#include "portparse.h"
20#include "writeall.h"
21#include "safenonce.h"
22#include "randommod.h"
23
24long long recent = 0;
25
26#define NUMIP 8
27long long hellowait[NUMIP] = {
28 1000000000
29, 1500000000
30, 2250000000
31, 3375000000
32, 5062500000
33, 7593750000
34, 11390625000
35, 17085937500
36} ;
37
38#include "crypto_box.h"
39#include "randombytes.h"
40#if crypto_box_PUBLICKEYBYTES != 32
41error!
42#endif
43#if crypto_box_NONCEBYTES != 24
44error!
45#endif
46#if crypto_box_BOXZEROBYTES != 16
47error!
48#endif
49#if crypto_box_ZEROBYTES != 32
50error!
51#endif
52#if crypto_box_BEFORENMBYTES != 32
53error!
54#endif
55
56int flagverbose = 1;
57
58#define USAGE "\
59curvecpclient: how to use:\n\
60curvecpclient: -q (optional): no error messages\n\
61curvecpclient: -Q (optional): print error messages (default)\n\
62curvecpclient: -v (optional): print extra information\n\
63curvecpclient: -c keydir (optional): use this public-key directory\n\
64curvecpclient: sname: server's name\n\
65curvecpclient: pk: server's public key\n\
66curvecpclient: ip: server's IP address\n\
67curvecpclient: port: server's UDP port\n\
68curvecpclient: ext: server's extension\n\
69curvecpclient: prog: run this client\n\
70"
71
72void die_usage(const char *s)
73{
74 if (s) die_4(100,USAGE,"curvecpclient: fatal: ",s,"\n");
75 die_1(100,USAGE);
76}
77
78void die_fatal(const char *trouble,const char *d,const char *fn)
79{
80 /* XXX: clean up? OS can do it much more reliably */
81 if (!flagverbose) die_0(111);
82 if (d) {
83 if (fn) die_9(111,"curvecpclient: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
84 die_7(111,"curvecpclient: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
85 }
86 if (errno) die_5(111,"curvecpclient: fatal: ",trouble,": ",e_str(errno),"\n");
87 die_3(111,"curvecpclient: fatal: ",trouble,"\n");
88}
89
90int multiipparse(unsigned char *y,const char *x)
91{
92 long long pos;
93 long long pos2;
94 long long ynum;
95 long long ypos;
96 long long j;
97 long long k;
98 long long d;
99 for (j = 0;j < 4 * NUMIP;++j) y[j] = 0;
100 ynum = 0;
101 while (ynum < 1000) {
102 ++ynum;
103 ypos = randommod(ynum);
104 for (k = 0;k < 4;++k) {
105 pos = ypos * 4 + k;
106 pos2 = (ynum - 1) * 4 + k;
107 if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos];
108 d = 0;
109 for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0');
110 if (j == 0) return 0;
111 x += j;
112 if (pos >= 0 && pos < 4 * NUMIP) y[pos] = d;
113 if (k < 3) {
114 if (*x != '.') return 0;
115 ++x;
116 }
117 }
118 if (!*x) break;
119 if (*x != ',') return 0;
120 ++x;
121 }
122 /* if fewer than 8 IP addresses, cycle through them: */
123 pos = 0;
124 pos2 = ynum * 4;
125 while (pos2 < 4 * NUMIP) {
126 if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos];
127 ++pos2;
128 ++pos;
129 }
130 return 1;
131}
132
133
134/* routing to the client: */
135unsigned char clientextension[16];
136long long clientextensionloadtime = 0;
137int udpfd = -1;
138
139void clientextension_init(void)
140{
141 if (recent >= clientextensionloadtime) {
142 clientextensionloadtime = recent + 30000000000LL;
143 if (load("/etc/curvecpextension",clientextension,16) == -1)
144 if (errno == ENOENT || errno == ENAMETOOLONG)
145 byte_zero(clientextension,16);
146 }
147}
148
149
150/* client security: */
151char *keydir = 0;
152unsigned char clientlongtermpk[32];
153unsigned char clientlongtermsk[32];
154unsigned char clientshorttermpk[32];
155unsigned char clientshorttermsk[32];
156crypto_uint64 clientshorttermnonce;
157unsigned char vouch[64];
158
159void clientshorttermnonce_update(void)
160{
161 ++clientshorttermnonce;
162 if (clientshorttermnonce) return;
163 errno = EPROTO;
164 die_fatal("nonce space expired",0,0);
165}
166
167/* routing to the server: */
168unsigned char serverip[4 * NUMIP];
169unsigned char serverport[2];
170unsigned char serverextension[16];
171
172/* server security: */
173unsigned char servername[256];
174unsigned char serverlongtermpk[32];
175unsigned char servershorttermpk[32];
176unsigned char servercookie[96];
177
178/* shared secrets: */
179unsigned char clientshortserverlong[32];
180unsigned char clientshortservershort[32];
181unsigned char clientlongserverlong[32];
182
183unsigned char allzero[128] = {0};
184
185unsigned char nonce[24];
186unsigned char text[2048];
187
188unsigned char packet[4096];
189unsigned char packetip[4];
190unsigned char packetport[2];
191crypto_uint64 packetnonce;
192int flagreceivedmessage = 0;
193crypto_uint64 receivednonce = 0;
194
195struct pollfd p[3];
196
197int fdwd = -1;
198
199int tochild[2] = {-1,-1};
200int fromchild[2] = {-1,-1};
201pid_t child = -1;
202int childstatus = 0;
203
204unsigned char childbuf[4096];
205long long childbuflen = 0;
206unsigned char childmessage[2048];
207long long childmessagelen = 0;
208
209int main(int argc,char **argv)
210{
211 long long hellopackets;
212 long long r;
213 long long nextaction;
214
215 signal(SIGPIPE,SIG_IGN);
216
217 if (!argv[0]) die_usage(0);
218 for (;;) {
219 char *x;
220 if (!argv[1]) break;
221 if (argv[1][0] != '-') break;
222 x = *++argv;
223 if (x[0] == '-' && x[1] == 0) break;
224 if (x[0] == '-' && x[1] == '-' && x[2] == 0) break;
225 while (*++x) {
226 if (*x == 'q') { flagverbose = 0; continue; }
227 if (*x == 'Q') { flagverbose = 1; continue; }
228 if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; }
229 if (*x == 'c') {
230 if (x[1]) { keydir = x + 1; break; }
231 if (argv[1]) { keydir = *++argv; break; }
232 }
233 die_usage(0);
234 }
235 }
236 if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots");
237 if (!hexparse(serverlongtermpk,32,*++argv)) die_usage("pk must be exactly 64 hex characters");
238 if (!multiipparse(serverip,*++argv)) die_usage("ip must be a comma-separated series of IPv4 addresses");
239 if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535");
240 if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters");
241 if (!*++argv) die_usage("missing prog");
242
243 for (;;) {
244 r = open_read("/dev/null");
245 if (r == -1) die_fatal("unable to open /dev/null",0,0);
246 if (r > 9) { close(r); break; }
247 }
248
249 if (keydir) {
250 fdwd = open_cwd();
251 if (fdwd == -1) die_fatal("unable to open current working directory",0,0);
252 if (chdir(keydir) == -1) die_fatal("unable to change to directory",keydir,0);
253 if (load("publickey",clientlongtermpk,sizeof clientlongtermpk) == -1) die_fatal("unable to read public key from",keydir,0);
254 if (load(".expertsonly/secretkey",clientlongtermsk,sizeof clientlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0);
255 } else {
256 crypto_box_keypair(clientlongtermpk,clientlongtermsk);
257 }
258
259 crypto_box_keypair(clientshorttermpk,clientshorttermsk);
260 clientshorttermnonce = randommod(281474976710656LL);
261 crypto_box_beforenm(clientshortserverlong,serverlongtermpk,clientshorttermsk);
262 crypto_box_beforenm(clientlongserverlong,serverlongtermpk,clientlongtermsk);
263
264 udpfd = socket_udp();
265 if (udpfd == -1) die_fatal("unable to create socket",0,0);
266
267 for (hellopackets = 0;hellopackets < NUMIP;++hellopackets) {
268 recent = nanoseconds();
269
270 /* send a Hello packet: */
271
272 clientextension_init();
273
274 clientshorttermnonce_update();
275 byte_copy(nonce,16,"CurveCP-client-H");
276 uint64_pack(nonce + 16,clientshorttermnonce);
277
278 byte_copy(packet,8,"QvnQ5XlH");
279 byte_copy(packet + 8,16,serverextension);
280 byte_copy(packet + 24,16,clientextension);
281 byte_copy(packet + 40,32,clientshorttermpk);
282 byte_copy(packet + 72,64,allzero);
283 byte_copy(packet + 136,8,nonce + 16);
284 crypto_box_afternm(text,allzero,96,nonce,clientshortserverlong);
285 byte_copy(packet + 144,80,text + 16);
286
287 socket_send(udpfd,packet,224,serverip + 4 * hellopackets,serverport);
288
289 nextaction = recent + hellowait[hellopackets] + randommod(hellowait[hellopackets]);
290
291 for (;;) {
292 long long timeout = nextaction - recent;
293 if (timeout <= 0) break;
294 p[0].fd = udpfd;
295 p[0].events = POLLIN;
296 if (poll(p,1,timeout / 1000000 + 1) < 0) p[0].revents = 0;
297
298 do { /* try receiving a Cookie packet: */
299 if (!p[0].revents) break;
300 r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
301 if (r != 200) break;
302 if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
303 byte_isequal(packetport,2,serverport) &
304 byte_isequal(packet,8,"RL3aNMXK") &
305 byte_isequal(packet + 8,16,clientextension) &
306 byte_isequal(packet + 24,16,serverextension)
307 )) break;
308 byte_copy(nonce,8,"CurveCPK");
309 byte_copy(nonce + 8,16,packet + 40);
310 byte_zero(text,16);
311 byte_copy(text + 16,144,packet + 56);
312 if (crypto_box_open_afternm(text,text,160,nonce,clientshortserverlong)) break;
313 byte_copy(servershorttermpk,32,text + 32);
314 byte_copy(servercookie,96,text + 64);
315 byte_copy(serverip,4,serverip + 4 * hellopackets);
316 goto receivedcookie;
317 } while (0);
318
319 recent = nanoseconds();
320 }
321 }
322
323 errno = ETIMEDOUT; die_fatal("no response from server",0,0);
324
325 receivedcookie:
326
327 crypto_box_beforenm(clientshortservershort,servershorttermpk,clientshorttermsk);
328
329 byte_copy(nonce,8,"CurveCPV");
330 if (keydir) {
331 if (safenonce(nonce + 8,0) == -1) die_fatal("nonce-generation disaster",0,0);
332 } else {
333 randombytes(nonce + 8,16);
334 }
335
336 byte_zero(text,32);
337 byte_copy(text + 32,32,clientshorttermpk);
338 crypto_box_afternm(text,text,64,nonce,clientlongserverlong);
339 byte_copy(vouch,16,nonce + 8);
340 byte_copy(vouch + 16,48,text + 16);
341
342 /* server is responding, so start child: */
343
344 if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0);
345 if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0);
346
347 child = fork();
348 if (child == -1) die_fatal("unable to fork",0,0);
349 if (child == 0) {
350 if (keydir) if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0);
351 close(8);
352 if (dup(tochild[0]) != 8) die_fatal("unable to dup",0,0);
353 close(9);
354 if (dup(fromchild[1]) != 9) die_fatal("unable to dup",0,0);
355 /* XXX: set up environment variables */
356 signal(SIGPIPE,SIG_DFL);
357 execvp(*argv,argv);
358 die_fatal("unable to run",*argv,0);
359 }
360
361 close(fromchild[1]);
362 close(tochild[0]);
363
364
365 for (;;) {
366 p[0].fd = udpfd;
367 p[0].events = POLLIN;
368 p[1].fd = fromchild[0];
369 p[1].events = POLLIN;
370
371 if (poll(p,2,-1) < 0) {
372 p[0].revents = 0;
373 p[1].revents = 0;
374 }
375
376 do { /* try receiving a Message packet: */
377 if (!p[0].revents) break;
378 r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
379 if (r < 80) break;
380 if (r > 1152) break;
381 if (r & 15) break;
382 packetnonce = uint64_unpack(packet + 40);
383 if (flagreceivedmessage && packetnonce <= receivednonce) break;
384 if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
385 byte_isequal(packetport,2,serverport) &
386 byte_isequal(packet,8,"RL3aNMXM") &
387 byte_isequal(packet + 8,16,clientextension) &
388 byte_isequal(packet + 24,16,serverextension)
389 )) break;
390 byte_copy(nonce,16,"CurveCP-server-M");
391 byte_copy(nonce + 16,8,packet + 40);
392 byte_zero(text,16);
393 byte_copy(text + 16,r - 48,packet + 48);
394 if (crypto_box_open_afternm(text,text,r - 32,nonce,clientshortservershort)) break;
395
396 if (!flagreceivedmessage) {
397 flagreceivedmessage = 1;
398 randombytes(clientlongtermpk,sizeof clientlongtermpk);
399 randombytes(vouch,sizeof vouch);
400 randombytes(servername,sizeof servername);
401 randombytes(servercookie,sizeof servercookie);
402 }
403
404 receivednonce = packetnonce;
405 text[31] = (r - 64) >> 4;
406 /* child is responsible for reading all data immediately, so we won't block: */
407 if (writeall(tochild[1],text + 31,r - 63) == -1) goto done;
408 } while (0);
409
410 do { /* try receiving data from child: */
411 long long i;
412 if (!p[1].revents) break;
413 r = read(fromchild[0],childbuf,sizeof childbuf);
414 if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
415 if (r <= 0) goto done;
416 childbuflen = r;
417 for (i = 0;i < childbuflen;++i) {
418 if (childmessagelen < 0) goto done;
419 if (childmessagelen >= sizeof childmessage) goto done;
420 childmessage[childmessagelen++] = childbuf[i];
421 if (childmessage[0] & 128) goto done;
422 if (childmessagelen == 1 + 16 * (unsigned long long) childmessage[0]) {
423 clientextension_init();
424 clientshorttermnonce_update();
425 uint64_pack(nonce + 16,clientshorttermnonce);
426 if (flagreceivedmessage) {
427 r = childmessagelen - 1;
428 if (r < 16) goto done;
429 if (r > 1088) goto done;
430 byte_copy(nonce,16,"CurveCP-client-M");
431 byte_zero(text,32);
432 byte_copy(text + 32,r,childmessage + 1);
433 crypto_box_afternm(text,text,r + 32,nonce,clientshortservershort);
434 byte_copy(packet,8,"QvnQ5XlM");
435 byte_copy(packet + 8,16,serverextension);
436 byte_copy(packet + 24,16,clientextension);
437 byte_copy(packet + 40,32,clientshorttermpk);
438 byte_copy(packet + 72,8,nonce + 16);
439 byte_copy(packet + 80,r + 16,text + 16);
440 socket_send(udpfd,packet,r + 96,serverip,serverport);
441 } else {
442 r = childmessagelen - 1;
443 if (r < 16) goto done;
444 if (r > 640) goto done;
445 byte_copy(nonce,16,"CurveCP-client-I");
446 byte_zero(text,32);
447 byte_copy(text + 32,32,clientlongtermpk);
448 byte_copy(text + 64,64,vouch);
449 byte_copy(text + 128,256,servername);
450 byte_copy(text + 384,r,childmessage + 1);
451 crypto_box_afternm(text,text,r + 384,nonce,clientshortservershort);
452 byte_copy(packet,8,"QvnQ5XlI");
453 byte_copy(packet + 8,16,serverextension);
454 byte_copy(packet + 24,16,clientextension);
455 byte_copy(packet + 40,32,clientshorttermpk);
456 byte_copy(packet + 72,96,servercookie);
457 byte_copy(packet + 168,8,nonce + 16);
458 byte_copy(packet + 176,r + 368,text + 16);
459 socket_send(udpfd,packet,r + 544,serverip,serverport);
460 }
461 childmessagelen = 0;
462 }
463 }
464 } while (0);
465 }
466
467
468 done:
469
470 do {
471 r = waitpid(child,&childstatus,0);
472 } while (r == -1 && errno == EINTR);
473
474 if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); }
475 return WEXITSTATUS(childstatus);
476}
diff --git a/nacl/curvecp/curvecpmakekey.c b/nacl/curvecp/curvecpmakekey.c
new file mode 100644
index 00000000..dfa181b0
--- /dev/null
+++ b/nacl/curvecp/curvecpmakekey.c
@@ -0,0 +1,57 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include "die.h"
5#include "e.h"
6#include "savesync.h"
7#include "randombytes.h"
8#include "crypto_box.h"
9
10void die_usage(void)
11{
12 die_1(111,"curvecpmakekey: usage: curvecpmakekey keydir\n");
13}
14
15void die_fatal(const char *trouble,const char *d,const char *fn)
16{
17 if (fn) die_9(111,"curvecpmakekey: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
18 die_7(111,"curvecpmakekey: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
19}
20
21unsigned char pk[crypto_box_PUBLICKEYBYTES];
22unsigned char sk[crypto_box_SECRETKEYBYTES];
23unsigned char lock[1];
24unsigned char noncekey[32];
25unsigned char noncecounter[8];
26
27void create(const char *d,const char *fn,const unsigned char *x,long long xlen)
28{
29 if (savesync(fn,x,xlen) == -1) die_fatal("unable to create",d,fn);
30}
31
32int main(int argc,char **argv)
33{
34 char *d;
35
36 if (!argv[0]) die_usage();
37 if (!argv[1]) die_usage();
38 d = argv[1];
39
40 umask(022);
41 if (mkdir(d,0755) == -1) die_fatal("unable to create directory",d,0);
42 if (chdir(d) == -1) die_fatal("unable to chdir to directory",d,0);
43 if (mkdir(".expertsonly",0700) == -1) die_fatal("unable to create directory",d,".expertsonly");
44
45 crypto_box_keypair(pk,sk);
46 create(d,"publickey",pk,sizeof pk);
47
48 randombytes(noncekey,sizeof noncekey);
49
50 umask(077);
51 create(d,".expertsonly/secretkey",sk,sizeof sk);
52 create(d,".expertsonly/lock",lock,sizeof lock);
53 create(d,".expertsonly/noncekey",noncekey,sizeof noncekey);
54 create(d,".expertsonly/noncecounter",noncecounter,sizeof noncecounter);
55
56 return 0;
57}
diff --git a/nacl/curvecp/curvecpmessage.c b/nacl/curvecp/curvecpmessage.c
new file mode 100644
index 00000000..df1e1664
--- /dev/null
+++ b/nacl/curvecp/curvecpmessage.c
@@ -0,0 +1,654 @@
1#include <sys/types.h>
2#include <sys/wait.h>
3#include <unistd.h>
4#include <signal.h>
5#include <poll.h>
6#include "open.h"
7#include "blocking.h"
8#include "e.h"
9#include "die.h"
10#include "randommod.h"
11#include "byte.h"
12#include "crypto_uint32.h"
13#include "uint16_pack.h"
14#include "uint32_pack.h"
15#include "uint64_pack.h"
16#include "uint16_unpack.h"
17#include "uint32_unpack.h"
18#include "uint64_unpack.h"
19#include "nanoseconds.h"
20#include "writeall.h"
21
22int flagverbose = 1;
23int flagserver = 1;
24int wantping = 0; /* 1: ping after a second; 2: ping immediately */
25
26#define USAGE "\
27curvecpmessage: how to use:\n\
28curvecpmessage: -q (optional): no error messages\n\
29curvecpmessage: -Q (optional): print error messages (default)\n\
30curvecpmessage: -v (optional): print extra information\n\
31curvecpmessage: -c (optional): program is a client; server starts first\n\
32curvecpmessage: -C (optional): program is a client that starts first\n\
33curvecpmessage: -s (optional): program is a server (default)\n\
34curvecpmessage: prog: run this program\n\
35"
36
37void die_usage(const char *s)
38{
39 if (s) die_4(100,USAGE,"curvecpmessage: fatal: ",s,"\n");
40 die_1(100,USAGE);
41}
42
43void die_fatal(const char *trouble,const char *d,const char *fn)
44{
45 if (!flagverbose) die_0(111);
46 if (d) {
47 if (fn) die_9(111,"curvecpmessage: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
48 die_7(111,"curvecpmessage: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
49 }
50 if (errno) die_5(111,"curvecpmessage: fatal: ",trouble,": ",e_str(errno),"\n");
51 die_3(111,"curvecpmessage: fatal: ",trouble,"\n");
52}
53
54void die_badmessage(void)
55{
56 errno = EPROTO;
57 die_fatal("unable to read from file descriptor 8",0,0);
58}
59
60void die_internalerror(void)
61{
62 errno = EPROTO;
63 die_fatal("internal error",0,0);
64}
65
66
67int tochild[2] = {-1,-1};
68int fromchild[2] = {-1,-1};
69pid_t child = -1;
70int childstatus;
71
72struct pollfd p[3];
73
74long long sendacked = 0; /* number of initial bytes sent and fully acknowledged */
75long long sendbytes = 0; /* number of additional bytes to send */
76unsigned char sendbuf[131072]; /* circular queue with the additional bytes; size must be power of 2 */
77long long sendprocessed = 0; /* within sendbytes, number of bytes absorbed into blocks */
78
79crypto_uint16 sendeof = 0; /* 2048 for normal eof after sendbytes, 4096 for error after sendbytes */
80int sendeofprocessed = 0;
81int sendeofacked = 0;
82
83long long totalblocktransmissions = 0;
84long long totalblocks = 0;
85
86#define OUTGOING 128 /* must be power of 2 */
87long long blocknum = 0; /* number of outgoing blocks being tracked */
88long long blockfirst = 0; /* circular queue */
89long long blockpos[OUTGOING]; /* position of block's first byte within stream */
90long long blocklen[OUTGOING]; /* number of bytes in this block */
91crypto_uint16 blockeof[OUTGOING]; /* 0, 2048, 4096 */
92long long blocktransmissions[OUTGOING];
93long long blocktime[OUTGOING]; /* time of last message sending this block; 0 means acked */
94long long earliestblocktime = 0; /* if nonzero, minimum of active blocktime values */
95crypto_uint32 blockid[OUTGOING]; /* ID of last message sending this block */
96
97#define INCOMING 64 /* must be power of 2 */
98long long messagenum = 0; /* number of messages in incoming queue */
99long long messagefirst = 0; /* position of first message; circular queue */
100unsigned char messagelen[INCOMING]; /* times 16 */
101unsigned char message[INCOMING][1088];
102unsigned char messagetodo[2048];
103long long messagetodolen = 0;
104
105long long receivebytes = 0; /* number of initial bytes fully received */
106long long receivewritten = 0; /* within receivebytes, number of bytes given to child */
107crypto_uint16 receiveeof = 0; /* 0, 2048, 4096 */
108long long receivetotalbytes = 0; /* total number of bytes in stream, if receiveeof */
109unsigned char receivebuf[131072]; /* circular queue beyond receivewritten; size must be power of 2 */
110unsigned char receivevalid[131072]; /* 1 for byte successfully received; XXX: use buddy structure to speed this up */
111
112long long maxblocklen = 512;
113crypto_uint32 nextmessageid = 1;
114
115unsigned char buf[4096];
116
117long long lastblocktime = 0;
118long long nsecperblock = 1000000000;
119long long lastspeedadjustment = 0;
120long long lastedge = 0;
121long long lastdoubling = 0;
122
123long long rtt;
124long long rtt_delta;
125long long rtt_average = 0;
126long long rtt_deviation = 0;
127long long rtt_lowwater = 0;
128long long rtt_highwater = 0;
129long long rtt_timeout = 1000000000;
130long long rtt_seenrecenthigh = 0;
131long long rtt_seenrecentlow = 0;
132long long rtt_seenolderhigh = 0;
133long long rtt_seenolderlow = 0;
134long long rtt_phase = 0;
135
136long long lastpanic = 0;
137
138void earliestblocktime_compute(void) /* XXX: use priority queue */
139{
140 long long i;
141 long long pos;
142 earliestblocktime = 0;
143 for (i = 0;i < blocknum;++i) {
144 pos = (blockfirst + i) & (OUTGOING - 1);
145 if (blocktime[pos]) {
146 if (!earliestblocktime)
147 earliestblocktime = blocktime[pos];
148 else
149 if (blocktime[pos] < earliestblocktime)
150 earliestblocktime = blocktime[pos];
151 }
152 }
153}
154
155void acknowledged(unsigned long long start,unsigned long long stop)
156{
157 long long i;
158 long long pos;
159 if (stop == start) return;
160 for (i = 0;i < blocknum;++i) {
161 pos = (blockfirst + i) & (OUTGOING - 1);
162 if (blockpos[pos] >= start && blockpos[pos] + blocklen[pos] <= stop) {
163 blocktime[pos] = 0;
164 totalblocktransmissions += blocktransmissions[pos];
165 totalblocks += 1;
166 }
167 }
168 while (blocknum) {
169 pos = blockfirst & (OUTGOING - 1);
170 if (blocktime[pos]) break;
171 sendacked += blocklen[pos];
172 sendbytes -= blocklen[pos];
173 sendprocessed -= blocklen[pos];
174 ++blockfirst;
175 --blocknum;
176 }
177 if (sendeof)
178 if (start == 0)
179 if (stop > sendacked + sendbytes)
180 if (!sendeofacked) {
181 sendeofacked = 1;
182 }
183 earliestblocktime_compute();
184}
185
186int main(int argc,char **argv)
187{
188 long long pos;
189 long long len;
190 long long u;
191 long long r;
192 long long i;
193 long long k;
194 long long recent;
195 long long nextaction;
196 long long timeout;
197 struct pollfd *q;
198 struct pollfd *watch8;
199 struct pollfd *watchtochild;
200 struct pollfd *watchfromchild;
201
202 signal(SIGPIPE,SIG_IGN);
203
204 if (!argv[0]) die_usage(0);
205 for (;;) {
206 char *x;
207 if (!argv[1]) break;
208 if (argv[1][0] != '-') break;
209 x = *++argv;
210 if (x[0] == '-' && x[1] == 0) break;
211 if (x[0] == '-' && x[1] == '-' && x[2] == 0) break;
212 while (*++x) {
213 if (*x == 'q') { flagverbose = 0; continue; }
214 if (*x == 'Q') { flagverbose = 1; continue; }
215 if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; }
216 if (*x == 'c') { flagserver = 0; wantping = 2; continue; }
217 if (*x == 'C') { flagserver = 0; wantping = 1; continue; }
218 if (*x == 's') { flagserver = 1; wantping = 0; continue; }
219 die_usage(0);
220 }
221 }
222 if (!*++argv) die_usage("missing prog");
223
224 for (;;) {
225 r = open_read("/dev/null");
226 if (r == -1) die_fatal("unable to open /dev/null",0,0);
227 if (r > 9) { close(r); break; }
228 }
229
230 if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0);
231 if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0);
232
233 blocking_enable(tochild[0]);
234 blocking_enable(fromchild[1]);
235
236 child = fork();
237 if (child == -1) die_fatal("unable to fork",0,0);
238 if (child == 0) {
239 close(8);
240 close(9);
241 if (flagserver) {
242 close(0);
243 if (dup(tochild[0]) != 0) die_fatal("unable to dup",0,0);
244 close(1);
245 if (dup(fromchild[1]) != 1) die_fatal("unable to dup",0,0);
246 } else {
247 close(6);
248 if (dup(tochild[0]) != 6) die_fatal("unable to dup",0,0);
249 close(7);
250 if (dup(fromchild[1]) != 7) die_fatal("unable to dup",0,0);
251 }
252 signal(SIGPIPE,SIG_DFL);
253 execvp(*argv,argv);
254 die_fatal("unable to run",*argv,0);
255 }
256
257 close(tochild[0]);
258 close(fromchild[1]);
259
260 recent = nanoseconds();
261 lastspeedadjustment = recent;
262 if (flagserver) maxblocklen = 1024;
263
264 for (;;) {
265 if (sendeofacked)
266 if (receivewritten == receivetotalbytes)
267 if (receiveeof)
268 if (tochild[1] < 0)
269 break; /* XXX: to re-ack should enter a TIME-WAIT state here */
270
271 q = p;
272
273 watch8 = q;
274 if (watch8) { q->fd = 8; q->events = POLLIN; ++q; }
275
276 watchtochild = q;
277 if (tochild[1] < 0) watchtochild = 0;
278 if (receivewritten >= receivebytes) watchtochild = 0;
279 if (watchtochild) { q->fd = tochild[1]; q->events = POLLOUT; ++q; }
280
281 watchfromchild = q;
282 if (sendeof) watchfromchild = 0;
283 if (sendbytes + 4096 > sizeof sendbuf) watchfromchild = 0;
284 if (watchfromchild) { q->fd = fromchild[0]; q->events = POLLIN; ++q; }
285
286 nextaction = recent + 60000000000LL;
287 if (wantping == 1) nextaction = recent + 1000000000;
288 if (wantping == 2)
289 if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock;
290 if (blocknum < OUTGOING)
291 if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes))
292 if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock;
293 if (earliestblocktime)
294 if (earliestblocktime + rtt_timeout > lastblocktime + nsecperblock)
295 if (earliestblocktime + rtt_timeout < nextaction)
296 nextaction = earliestblocktime + rtt_timeout;
297
298 if (messagenum)
299 if (!watchtochild)
300 nextaction = 0;
301
302 if (nextaction <= recent)
303 timeout = 0;
304 else
305 timeout = (nextaction - recent) / 1000000 + 1;
306
307 if (poll(p,q - p,timeout) < 0) {
308 watch8 = 0;
309 watchtochild = 0;
310 watchfromchild = 0;
311 } else {
312 if (watch8) if (!watch8->revents) watch8 = 0;
313 if (watchtochild) if (!watchtochild->revents) watchtochild = 0;
314 if (watchfromchild) if (!watchfromchild->revents) watchfromchild = 0;
315 }
316
317 /* XXX: keepalives */
318
319 do { /* try receiving data from child: */
320 if (!watchfromchild) break;
321 if (sendeof) break;
322 if (sendbytes + 4096 > sizeof sendbuf) break;
323
324 pos = (sendacked & (sizeof sendbuf - 1)) + sendbytes;
325 if (pos < sizeof sendbuf) {
326 r = read(fromchild[0],sendbuf + pos,sizeof sendbuf - pos);
327 } else {
328 r = read(fromchild[0],sendbuf + pos - sizeof sendbuf,sizeof sendbuf - sendbytes);
329 }
330 if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
331 if (r < 0) { sendeof = 4096; break; }
332 if (r == 0) { sendeof = 2048; break; }
333 sendbytes += r;
334 if (sendbytes >= 1152921504606846976LL) die_internalerror();
335 } while(0);
336
337 recent = nanoseconds();
338
339 do { /* try re-sending an old block: */
340 if (recent < lastblocktime + nsecperblock) break;
341 if (earliestblocktime == 0) break;
342 if (recent < earliestblocktime + rtt_timeout) break;
343
344 for (i = 0;i < blocknum;++i) {
345 pos = (blockfirst + i) & (OUTGOING - 1);
346 if (blocktime[pos] == earliestblocktime) {
347 if (recent > lastpanic + 4 * rtt_timeout) {
348 nsecperblock *= 2;
349 lastpanic = recent;
350 lastedge = recent;
351 }
352 goto sendblock;
353 }
354 }
355 } while(0);
356
357 do { /* try sending a new block: */
358 if (recent < lastblocktime + nsecperblock) break;
359 if (blocknum >= OUTGOING) break;
360 if (!wantping)
361 if (sendeof ? sendeofprocessed : sendprocessed >= sendbytes) break;
362 /* XXX: if any Nagle-type processing is desired, do it here */
363
364 pos = (blockfirst + blocknum) & (OUTGOING - 1);
365 ++blocknum;
366 blockpos[pos] = sendacked + sendprocessed;
367 blocklen[pos] = sendbytes - sendprocessed;
368 if (blocklen[pos] > maxblocklen) blocklen[pos] = maxblocklen;
369 if ((blockpos[pos] & (sizeof sendbuf - 1)) + blocklen[pos] > sizeof sendbuf)
370 blocklen[pos] = sizeof sendbuf - (blockpos[pos] & (sizeof sendbuf - 1));
371 /* XXX: or could have the full block in post-buffer space */
372 sendprocessed += blocklen[pos];
373 blockeof[pos] = 0;
374 if (sendprocessed == sendbytes) {
375 blockeof[pos] = sendeof;
376 if (sendeof) sendeofprocessed = 1;
377 }
378 blocktransmissions[pos] = 0;
379
380 sendblock:
381
382 blocktransmissions[pos] += 1;
383 blocktime[pos] = recent;
384 blockid[pos] = nextmessageid;
385 if (!++nextmessageid) ++nextmessageid;
386
387 /* constraints: u multiple of 16; u >= 16; u <= 1088; u >= 48 + blocklen[pos] */
388 u = 64 + blocklen[pos];
389 if (u <= 192) u = 192;
390 else if (u <= 320) u = 320;
391 else if (u <= 576) u = 576;
392 else if (u <= 1088) u = 1088;
393 else die_internalerror();
394 if (blocklen[pos] < 0 || blocklen[pos] > 1024) die_internalerror();
395
396 byte_zero(buf + 8,u);
397 buf[7] = u / 16;
398 uint32_pack(buf + 8,blockid[pos]);
399 /* XXX: include any acknowledgments that have piled up */
400 uint16_pack(buf + 46,blockeof[pos] | (crypto_uint16) blocklen[pos]);
401 uint64_pack(buf + 48,blockpos[pos]);
402 byte_copy(buf + 8 + u - blocklen[pos],blocklen[pos],sendbuf + (blockpos[pos] & (sizeof sendbuf - 1)));
403
404 if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0);
405 lastblocktime = recent;
406 wantping = 0;
407
408 earliestblocktime_compute();
409 } while(0);
410
411 do { /* try receiving messages: */
412 if (!watch8) break;
413 r = read(8,buf,sizeof buf);
414 if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
415 if (r == 0) die_badmessage();
416 if (r < 0) die_fatal("unable to read from file descriptor 8",0,0);
417 for (k = 0;k < r;++k) {
418 messagetodo[messagetodolen++] = buf[k];
419 u = 16 * (unsigned long long) messagetodo[0];
420 if (u < 16) die_badmessage();
421 if (u > 1088) die_badmessage();
422 if (messagetodolen == 1 + u) {
423 if (messagenum < INCOMING) {
424 pos = (messagefirst + messagenum) & (INCOMING - 1);
425 messagelen[pos] = messagetodo[0];
426 byte_copy(message[pos],u,messagetodo + 1);
427 ++messagenum;
428 } else {
429 ; /* drop tail */
430 }
431 messagetodolen = 0;
432 }
433 }
434 } while(0);
435
436 do { /* try processing a message: */
437 if (!messagenum) break;
438 if (tochild[1] >= 0 && receivewritten < receivebytes) break;
439
440 maxblocklen = 1024;
441
442 pos = messagefirst & (INCOMING - 1);
443 len = 16 * (unsigned long long) messagelen[pos];
444 do { /* handle this message if it's comprehensible: */
445 unsigned long long D;
446 unsigned long long SF;
447 unsigned long long startbyte;
448 unsigned long long stopbyte;
449 crypto_uint32 id;
450 long long i;
451
452 if (len < 48) break;
453 if (len > 1088) break;
454
455 id = uint32_unpack(message[pos] + 4);
456 for (i = 0;i < blocknum;++i) {
457 k = (blockfirst + i) & (OUTGOING - 1);
458 if (blockid[k] == id) {
459 rtt = recent - blocktime[k];
460 if (!rtt_average) {
461 nsecperblock = rtt;
462 rtt_average = rtt;
463 rtt_deviation = rtt / 2;
464 rtt_highwater = rtt;
465 rtt_lowwater = rtt;
466 }
467
468 /* Jacobson's retransmission timeout calculation: */
469 rtt_delta = rtt - rtt_average;
470 rtt_average += rtt_delta / 8;
471 if (rtt_delta < 0) rtt_delta = -rtt_delta;
472 rtt_delta -= rtt_deviation;
473 rtt_deviation += rtt_delta / 4;
474 rtt_timeout = rtt_average + 4 * rtt_deviation;
475 /* adjust for delayed acks with anti-spiking: */
476 rtt_timeout += 8 * nsecperblock;
477
478 /* recognizing top and bottom of congestion cycle: */
479 rtt_delta = rtt - rtt_highwater;
480 rtt_highwater += rtt_delta / 1024;
481 rtt_delta = rtt - rtt_lowwater;
482 if (rtt_delta > 0) rtt_lowwater += rtt_delta / 8192;
483 else rtt_lowwater += rtt_delta / 256;
484
485 if (rtt_average > rtt_highwater + 5000000) rtt_seenrecenthigh = 1;
486 else if (rtt_average < rtt_lowwater) rtt_seenrecentlow = 1;
487
488 if (recent >= lastspeedadjustment + 16 * nsecperblock) {
489 if (recent - lastspeedadjustment > 10000000000LL) {
490 nsecperblock = 1000000000; /* slow restart */
491 nsecperblock += randommod(nsecperblock / 8);
492 }
493
494 lastspeedadjustment = recent;
495
496 if (nsecperblock >= 131072) {
497 /* additive increase: adjust 1/N by a constant c */
498 /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */
499 /* approximation: adjust 1/N by cN every N nanoseconds */
500 /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */
501 if (nsecperblock < 16777216) {
502 /* N/(1+cN^2) approx N - cN^3 */
503 u = nsecperblock / 131072;
504 nsecperblock -= u * u * u;
505 } else {
506 double d = nsecperblock;
507 nsecperblock = d/(1 + d*d / 2251799813685248.0);
508 }
509 }
510
511 if (rtt_phase == 0) {
512 if (rtt_seenolderhigh) {
513 rtt_phase = 1;
514 lastedge = recent;
515 nsecperblock += randommod(nsecperblock / 4);
516 }
517 } else {
518 if (rtt_seenolderlow) {
519 rtt_phase = 0;
520 }
521 }
522
523 rtt_seenolderhigh = rtt_seenrecenthigh;
524 rtt_seenolderlow = rtt_seenrecentlow;
525 rtt_seenrecenthigh = 0;
526 rtt_seenrecentlow = 0;
527 }
528
529 do {
530 if (recent - lastedge < 60000000000LL) {
531 if (recent < lastdoubling + 4 * nsecperblock + 64 * rtt_timeout + 5000000000LL) break;
532 } else {
533 if (recent < lastdoubling + 4 * nsecperblock + 2 * rtt_timeout) break;
534 }
535 if (nsecperblock <= 65535) break;
536
537 nsecperblock /= 2;
538 lastdoubling = recent;
539 if (lastedge) lastedge = recent;
540 } while(0);
541 }
542 }
543
544 stopbyte = uint64_unpack(message[pos] + 8);
545 acknowledged(0,stopbyte);
546 startbyte = stopbyte + (unsigned long long) uint32_unpack(message[pos] + 16);
547 stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 20);
548 acknowledged(startbyte,stopbyte);
549 startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 22);
550 stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 24);
551 acknowledged(startbyte,stopbyte);
552 startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 26);
553 stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 28);
554 acknowledged(startbyte,stopbyte);
555 startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 30);
556 stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 32);
557 acknowledged(startbyte,stopbyte);
558 startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 34);
559 stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 36);
560 acknowledged(startbyte,stopbyte);
561
562 D = uint16_unpack(message[pos] + 38);
563 SF = D & (2048 + 4096);
564 D -= SF;
565 if (D > 1024) break;
566 if (48 + D > len) break;
567
568 startbyte = uint64_unpack(message[pos] + 40);
569 stopbyte = startbyte + D;
570
571 if (stopbyte > receivewritten + sizeof receivebuf) {
572 break;
573 /* of course, flow control would avoid this case */
574 }
575
576 if (SF) {
577 receiveeof = SF;
578 receivetotalbytes = stopbyte;
579 }
580
581 for (k = 0;k < D;++k) {
582 unsigned char ch = message[pos][len - D + k];
583 unsigned long long where = startbyte + k;
584 if (where >= receivewritten && where < receivewritten + sizeof receivebuf) {
585 receivevalid[where & (sizeof receivebuf - 1)] = 1;
586 receivebuf[where & (sizeof receivebuf - 1)] = ch;
587 }
588 }
589 for (;;) {
590 if (receivebytes >= receivewritten + sizeof receivebuf) break;
591 if (!receivevalid[receivebytes & (sizeof receivebuf - 1)]) break;
592 ++receivebytes;
593 }
594
595 if (!uint32_unpack(message[pos])) break; /* never acknowledge a pure acknowledgment */
596
597 /* XXX: delay acknowledgments */
598 u = 192;
599 byte_zero(buf + 8,u);
600 buf[7] = u / 16;
601 byte_copy(buf + 12,4,message[pos]);
602 if (receiveeof && receivebytes == receivetotalbytes) {
603 uint64_pack(buf + 16,receivebytes + 1);
604 } else
605 uint64_pack(buf + 16,receivebytes);
606 /* XXX: incorporate selective acknowledgments */
607
608 if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0);
609 } while(0);
610
611 ++messagefirst;
612 --messagenum;
613 } while(0);
614
615 do { /* try sending data to child: */
616 if (!watchtochild) break;
617 if (tochild[1] < 0) { receivewritten = receivebytes; break; }
618 if (receivewritten >= receivebytes) break;
619
620 pos = receivewritten & (sizeof receivebuf - 1);
621 len = receivebytes - receivewritten;
622 if (pos + len > sizeof receivebuf) len = sizeof receivebuf - pos;
623 r = write(tochild[1],receivebuf + pos,len);
624 if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
625 if (r <= 0) {
626 close(tochild[1]);
627 tochild[1] = -1;
628 break;
629 }
630 byte_zero(receivevalid + pos,r);
631 receivewritten += r;
632 } while(0);
633
634 do { /* try closing pipe to child: */
635 if (!receiveeof) break;
636 if (receivewritten < receivetotalbytes) break;
637 if (tochild[1] < 0) break;
638
639 if (receiveeof == 4096)
640 ; /* XXX: UNIX doesn't provide a way to signal an error through a pipe */
641 close(tochild[1]);
642 tochild[1] = -1;
643 } while(0);
644
645 }
646
647
648 do {
649 r = waitpid(child,&childstatus,0);
650 } while (r == -1 && errno == EINTR);
651
652 if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); }
653 return WEXITSTATUS(childstatus);
654}
diff --git a/nacl/curvecp/curvecpprintkey.c b/nacl/curvecp/curvecpprintkey.c
new file mode 100644
index 00000000..8fd26bcf
--- /dev/null
+++ b/nacl/curvecp/curvecpprintkey.c
@@ -0,0 +1,46 @@
1#include <unistd.h>
2#include "die.h"
3#include "e.h"
4#include "load.h"
5#include "writeall.h"
6#include "crypto_box.h"
7
8unsigned char pk[crypto_box_PUBLICKEYBYTES];
9unsigned char out[crypto_box_PUBLICKEYBYTES * 2 + 1];
10
11void die_usage(void)
12{
13 die_1(111,"curvecpprintkey: usage: curvecpprintkey keydir\n");
14}
15
16void die_fatal(const char *trouble,const char *d,const char *fn)
17{
18 if (d) {
19 if (fn) die_9(111,"curvecpmakekey: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
20 die_7(111,"curvecpmakekey: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
21 }
22 die_5(111,"curvecpmakekey: fatal: ",trouble,": ",e_str(errno),"\n");
23}
24
25int main(int argc,char **argv)
26{
27 char *d;
28 long long j;
29
30 if (!argv[0]) die_usage();
31 if (!argv[1]) die_usage();
32 d = argv[1];
33
34 if (chdir(d) == -1) die_fatal("unable to chdir to directory",d,0);
35 if (load("publickey",pk,sizeof pk) == -1) die_fatal("unable to read",d,"publickey");
36
37 for (j = 0;j < crypto_box_PUBLICKEYBYTES;++j) {
38 out[2 * j + 0] = "0123456789abcdef"[15 & (int) (pk[j] >> 4)];
39 out[2 * j + 1] = "0123456789abcdef"[15 & (int) (pk[j] >> 0)];
40 }
41 out[2 * j] = '\n';
42
43 if (writeall(1,out,sizeof out) == -1) die_fatal("unable to write output",0,0);
44
45 return 0;
46}
diff --git a/nacl/curvecp/curvecpserver.c b/nacl/curvecp/curvecpserver.c
new file mode 100644
index 00000000..82cc6670
--- /dev/null
+++ b/nacl/curvecp/curvecpserver.c
@@ -0,0 +1,497 @@
1#include <signal.h>
2#include <stdlib.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <poll.h>
8#include "e.h"
9#include "die.h"
10#include "byte.h"
11#include "open.h"
12#include "load.h"
13#include "socket.h"
14#include "uint64_pack.h"
15#include "uint64_unpack.h"
16#include "writeall.h"
17#include "nanoseconds.h"
18#include "safenonce.h"
19#include "nameparse.h"
20#include "hexparse.h"
21#include "portparse.h"
22#include "randommod.h"
23
24#include "randombytes.h"
25#include "crypto_box.h"
26#include "crypto_secretbox.h"
27#if crypto_box_PUBLICKEYBYTES != 32
28error!
29#endif
30#if crypto_box_NONCEBYTES != 24
31error!
32#endif
33#if crypto_box_BOXZEROBYTES != 16
34error!
35#endif
36#if crypto_box_ZEROBYTES != 32
37error!
38#endif
39#if crypto_box_BEFORENMBYTES != 32
40error!
41#endif
42#if crypto_secretbox_KEYBYTES != 32
43error!
44#endif
45#if crypto_secretbox_NONCEBYTES != 24
46error!
47#endif
48#if crypto_secretbox_BOXZEROBYTES != 16
49error!
50#endif
51#if crypto_secretbox_ZEROBYTES != 32
52error!
53#endif
54
55int flagverbose;
56
57#define USAGE "\
58curvecpserver: how to use:\n\
59curvecpserver: -q (optional): no error messages\n\
60curvecpserver: -Q (optional): print error messages (default)\n\
61curvecpserver: -v (optional): print extra information\n\
62curvecpserver: -c n (optional): allow at most n clients at once (default 100)\n\
63curvecpserver: sname: server's name\n\
64curvecpserver: keydir: use this public-key directory\n\
65curvecpserver: ip: server's IP address\n\
66curvecpserver: port: server's UDP port\n\
67curvecpserver: ext: server's extension\n\
68curvecpserver: prog: run this server\n\
69"
70
71void die_usage(const char *s)
72{
73 if (s) die_4(100,USAGE,"curvecpserver: fatal: ",s,"\n");
74 die_1(100,USAGE);
75}
76
77void die_fatal(const char *trouble,const char *d,const char *fn)
78{
79 if (!flagverbose) die_0(111);
80 if (d) {
81 if (fn) die_9(111,"curvecpserver: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
82 die_7(111,"curvecpserver: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
83 }
84 die_5(111,"curvecpserver: fatal: ",trouble,": ",e_str(errno),"\n");
85}
86
87int ipparse(unsigned char *y,const char *x)
88{
89 long long j;
90 long long k;
91 long long d;
92
93 for (k = 0;k < 4;++k) y[k] = 0;
94 for (k = 0;k < 4;++k) {
95 d = 0;
96 for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0');
97 if (j == 0) return 0;
98 x += j;
99 if (k >= 0 && k < 4) y[k] = d;
100 if (k < 3) {
101 if (*x != '.') return 0;
102 ++x;
103 }
104 }
105 if (*x) return 0;
106 return 1;
107}
108
109int maxparse(long long *y,const char *x)
110{
111 long long d;
112 long long j;
113
114 d = 0;
115 for (j = 0;j < 9 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0');
116 if (x[j]) return 0;
117 if (d < 1) return 0;
118 if (d > 65535) return 0;
119 *y = d;
120 return 1;
121}
122
123/* cookies: */
124long long nextminute;
125unsigned char minutekey[32];
126unsigned char lastminutekey[32];
127
128/* routing to the server: */
129unsigned char serverip[4];
130unsigned char serverport[2];
131unsigned char serverextension[16];
132int udpfd = -1;
133
134/* server security: */
135char *keydir = 0;
136unsigned char servername[256];
137unsigned char serverlongtermsk[32];
138unsigned char servershorttermpk[32];
139unsigned char servershorttermsk[32];
140
141/* routing to the client: */
142unsigned char clientextension[16];
143
144/* client security: */
145unsigned char clientlongtermpk[32];
146unsigned char clientshorttermpk[32];
147
148/* shared secrets: */
149unsigned char clientshortserverlong[32];
150unsigned char clientshortservershort[32];
151unsigned char clientlongserverlong[32];
152
153unsigned char allzero[128] = {0};
154
155unsigned char nonce[24];
156unsigned char text[2048];
157
158unsigned char packetip[4];
159unsigned char packetport[2];
160unsigned char packet[4096];
161crypto_uint64 packetnonce;
162
163#define MESSAGELEN 1104
164
165struct activeclient {
166 unsigned char clientshorttermpk[32];
167 unsigned char clientshortservershort[32];
168 crypto_uint64 receivednonce;
169 crypto_uint64 sentnonce;
170 long long messagelen;
171 pid_t child;
172 int tochild;
173 int fromchild;
174 unsigned char clientextension[16];
175 unsigned char clientip[4];
176 unsigned char clientport[2];
177 unsigned char message[MESSAGELEN];
178} ;
179
180const char *strmaxactiveclients = "100";
181long long maxactiveclients = 0;
182long long numactiveclients = 0;
183struct activeclient *activeclients = 0;
184struct pollfd *p;
185
186int fdwd = -1;
187
188int pi0[2];
189int pi1[2];
190
191unsigned char childbuf[4096];
192long long childbuflen = 0;
193unsigned char childmessage[2048];
194long long childmessagelen = 0;
195
196int main(int argc,char **argv)
197{
198 long long r;
199 long long i;
200 long long k;
201
202 signal(SIGPIPE,SIG_IGN);
203 signal(SIGCHLD,SIG_IGN);
204
205 if (!argv[0]) die_usage(0);
206 for (;;) {
207 char *x;
208 if (!argv[1]) break;
209 if (argv[1][0] != '-') break;
210 x = *++argv;
211 if (x[0] == '-' && x[1] == 0) break;
212 if (x[0] == '-' && x[1] == '-' && x[2] == 0) break;
213 while (*++x) {
214 if (*x == 'q') { flagverbose = 0; continue; }
215 if (*x == 'Q') { flagverbose = 1; continue; }
216 if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; }
217 if (*x == 'c') {
218 if (x[1]) { strmaxactiveclients = x + 1; break; }
219 if (argv[1]) { strmaxactiveclients = *++argv; break; }
220 }
221 die_usage(0);
222 }
223 }
224 if (!maxparse(&maxactiveclients,strmaxactiveclients)) die_usage("concurrency must be between 1 and 65535");
225 if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots");
226 keydir = *++argv; if (!keydir) die_usage("missing keydir");
227 if (!ipparse(serverip,*++argv)) die_usage("ip must be an IPv4 address");
228 if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535");
229 if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters");
230 if (!*++argv) die_usage("missing prog");
231
232 for (;;) {
233 r = open_read("/dev/null");
234 if (r == -1) die_fatal("unable to open /dev/null",0,0);
235 if (r > 9) { close(r); break; }
236 }
237
238 activeclients = malloc(maxactiveclients * sizeof(struct activeclient));
239 if (!activeclients) die_fatal("unable to create activeclients array",0,0);
240 randombytes((void *) activeclients,maxactiveclients * sizeof(struct activeclient));
241 for (i = 0;i < maxactiveclients;++i) {
242 activeclients[i].child = -1;
243 activeclients[i].tochild = -1;
244 activeclients[i].fromchild = -1;
245 activeclients[i].receivednonce = 0;
246 activeclients[i].sentnonce = randommod(281474976710656LL);
247 }
248
249 p = malloc((1 + maxactiveclients) * sizeof(struct pollfd));
250 if (!p) die_fatal("unable to create poll array",0,0);
251
252 fdwd = open_cwd();
253 if (fdwd == -1) die_fatal("unable to open current directory",0,0);
254
255 if (chdir(keydir) == -1) die_fatal("unable to chdir to",keydir,0);
256 if (load(".expertsonly/secretkey",serverlongtermsk,sizeof serverlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0);
257
258 udpfd = socket_udp();
259 if (udpfd == -1) die_fatal("unable to create socket",0,0);
260 if (socket_bind(udpfd,serverip,serverport) == -1) die_fatal("unable to bind socket",0,0);
261
262 randombytes(minutekey,sizeof minutekey);
263 randombytes(lastminutekey,sizeof lastminutekey);
264 nextminute = nanoseconds() + 60000000000ULL;
265
266 for (;;) {
267 long long timeout = nextminute - nanoseconds();
268 if (timeout <= 0) {
269 timeout = 60000000000ULL;
270 byte_copy(lastminutekey,sizeof lastminutekey,minutekey);
271 randombytes(minutekey,sizeof minutekey);
272 nextminute = nanoseconds() + timeout;
273 randombytes(packet,sizeof packet);
274 randombytes(packetip,sizeof packetip);
275 randombytes(packetport,sizeof packetport);
276 randombytes(clientshorttermpk,sizeof clientshorttermpk);
277 randombytes(clientshortserverlong,sizeof clientshortserverlong);
278 randombytes(nonce,sizeof nonce);
279 randombytes(text,sizeof text);
280 randombytes(childbuf,sizeof childbuf);
281 randombytes(childmessage,sizeof childmessage);
282 randombytes(servershorttermpk,sizeof servershorttermpk);
283 randombytes(servershorttermsk,sizeof servershorttermsk);
284 }
285
286 for (i = 0;i < numactiveclients;++i) {
287 p[i].fd = activeclients[i].fromchild;
288 p[i].events = POLLIN;
289 }
290 p[numactiveclients].fd = udpfd;
291 p[numactiveclients].events = POLLIN;
292 if (poll(p,1 + numactiveclients,timeout / 1000000 + 1) < 0) continue;
293
294 do { /* try receiving a packet: */
295 if (!p[numactiveclients].revents) break;
296 r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
297 if (r < 80) break;
298 if (r > 1184) break;
299 if (r & 15) break;
300 if (!(byte_isequal(packet,7,"QvnQ5Xl") & byte_isequal(packet + 8,16,serverextension))) break;
301 byte_copy(clientextension,16,packet + 24);
302 if (packet[7] == 'H') { /* Hello packet: */
303 if (r != 224) break;
304 byte_copy(clientshorttermpk,32,packet + 40);
305 crypto_box_beforenm(clientshortserverlong,clientshorttermpk,serverlongtermsk);
306 byte_copy(nonce,16,"CurveCP-client-H");
307 byte_copy(nonce + 16,8,packet + 136);
308 byte_zero(text,16);
309 byte_copy(text + 16,80,packet + 144);
310 if (crypto_box_open_afternm(text,text,96,nonce,clientshortserverlong)) break;
311
312 /* send Cookie packet: */
313
314 crypto_box_keypair(servershorttermpk,servershorttermsk);
315 byte_zero(text + 64,32);
316 byte_copy(text + 96,32,clientshorttermpk);
317 byte_copy(text + 128,32,servershorttermsk);
318 byte_copy(nonce,8,"minute-k");
319 if (safenonce(nonce + 8,1) == -1) die_fatal("nonce-generation disaster",0,0);
320 crypto_secretbox(text + 64,text + 64,96,nonce,minutekey);
321 byte_copy(text + 64,16,nonce + 8);
322
323 byte_zero(text,32);
324 byte_copy(text + 32,32,servershorttermpk);
325 byte_copy(nonce,8,"CurveCPK"); /* reusing the other 16 bytes */
326 crypto_box_afternm(text,text,160,nonce,clientshortserverlong);
327
328 byte_copy(packet,8,"RL3aNMXK");
329 byte_copy(packet + 8,16,clientextension);
330 byte_copy(packet + 24,16,serverextension);
331 byte_copy(packet + 40,16,nonce + 8);
332 byte_copy(packet + 56,144,text + 16);
333
334 socket_send(udpfd,packet,200,packetip,packetport);
335 }
336 if (packet[7] == 'I') { /* Initiate packet: */
337 if (r < 560) break;
338 for (i = 0;i < numactiveclients;++i) /* XXX use better data structure */
339 if (byte_isequal(activeclients[i].clientshorttermpk,32,packet + 40))
340 break;
341 if (i < numactiveclients) {
342 packetnonce = uint64_unpack(packet + 168);
343 if (packetnonce <= activeclients[i].receivednonce) break;
344 byte_copy(nonce,16,"CurveCP-client-I");
345 byte_copy(nonce + 16,8,packet + 168);
346 byte_zero(text,16);
347 byte_copy(text + 16,r - 176,packet + 176);
348 if (crypto_box_open_afternm(text,text,r - 160,nonce,activeclients[i].clientshortservershort)) break;
349
350 /* XXX: update clientip, clientextension; but not if client has spoken recently */
351 activeclients[i].receivednonce = packetnonce;
352 text[383] = (r - 544) >> 4;
353 if (writeall(activeclients[i].tochild,text + 383,r - 543) == -1)
354 ; /* child is gone; will see eof later */
355 break;
356 }
357 if (i == maxactiveclients) break;
358
359 byte_copy(nonce,8,"minute-k");
360 byte_copy(nonce + 8,16,packet + 72);
361 byte_zero(text,16);
362 byte_copy(text + 16,80,packet + 88);
363 if (crypto_secretbox_open(text,text,96,nonce,minutekey)) {
364 byte_zero(text,16);
365 byte_copy(text + 16,80,packet + 88);
366 if (crypto_secretbox_open(text,text,96,nonce,lastminutekey)) break;
367 }
368 if (!byte_isequal(packet + 40,32,text + 32)) break;
369 byte_copy(servershorttermsk,32,text + 64);
370 byte_copy(clientshorttermpk,32,packet + 40);
371 crypto_box_beforenm(clientshortservershort,clientshorttermpk,servershorttermsk);
372
373 byte_copy(nonce,16,"CurveCP-client-I");
374 byte_copy(nonce + 16,8,packet + 168);
375 byte_zero(text,16);
376 byte_copy(text + 16,r - 176,packet + 176);
377 if (crypto_box_open_afternm(text,text,r - 160,nonce,clientshortservershort)) break;
378
379 if (!byte_isequal(text + 128,256,servername)) break;
380
381 /* XXX skip if client authentication is not desired: */
382 byte_copy(clientlongtermpk,32,text + 32);
383 /* XXX impose policy limitations on clients: known, maxconn */
384 /* XXX for known clients, retrieve shared secret from cache: */
385 crypto_box_beforenm(clientlongserverlong,clientlongtermpk,serverlongtermsk);
386 byte_copy(nonce,8,"CurveCPV");
387 byte_copy(nonce + 8,16,text + 64);
388 byte_zero(text + 64,16);
389 if (crypto_box_open_afternm(text + 64,text + 64,64,nonce,clientlongserverlong)) break;
390 if (!byte_isequal(text + 96,32,clientshorttermpk)) break;
391
392 if (open_pipe(pi0) == -1) break; /* XXX: error message */
393 if (open_pipe(pi1) == -1) { close(pi0[0]); close(pi0[1]); break; } /* XXX: error message */
394
395 activeclients[i].child = fork();
396 if (activeclients[i].child == -1) {
397 close(pi0[0]); close(pi0[1]);
398 close(pi1[0]); close(pi1[1]);
399 break; /* XXX: error message */
400 }
401 if (activeclients[i].child == 0) {
402 if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0);
403 close(8);
404 if (dup(pi0[0]) != 8) die_fatal("unable to dup",0,0);
405 close(9);
406 if (dup(pi1[1]) != 9) die_fatal("unable to dup",0,0);
407 /* XXX: set up environment variables */
408 signal(SIGPIPE,SIG_DFL);
409 signal(SIGCHLD,SIG_DFL);
410 execvp(*argv,argv);
411 die_fatal("unable to run",*argv,0);
412 }
413
414 activeclients[i].tochild = pi0[1]; close(pi0[0]);
415 activeclients[i].fromchild = pi1[0]; close(pi1[1]);
416 activeclients[i].messagelen = 0;
417 byte_copy(activeclients[i].clientshorttermpk,32,clientshorttermpk);
418 byte_copy(activeclients[i].clientshortservershort,32,clientshortservershort);
419 activeclients[i].receivednonce = uint64_unpack(packet + 168);
420 byte_copy(activeclients[i].clientextension,16,clientextension);
421 byte_copy(activeclients[i].clientip,4,packetip);
422 byte_copy(activeclients[i].clientport,2,packetport);
423 ++numactiveclients;
424
425 text[383] = (r - 544) >> 4;
426 if (writeall(activeclients[i].tochild,text + 383,r - 543) == -1)
427 ; /* child is gone; will see eof later */
428 }
429 if (packet[7] == 'M') { /* Message packet: */
430 if (r < 112) break;
431 for (i = 0;i < numactiveclients;++i) /* XXX use better data structure */
432 if (byte_isequal(activeclients[i].clientshorttermpk,32,packet + 40))
433 break;
434 if (i < numactiveclients) {
435 packetnonce = uint64_unpack(packet + 72);
436 if (packetnonce <= activeclients[i].receivednonce) break;
437 byte_copy(nonce,16,"CurveCP-client-M");
438 byte_copy(nonce + 16,8,packet + 72);
439 byte_zero(text,16);
440 byte_copy(text + 16,r - 80,packet + 80);
441 if (crypto_box_open_afternm(text,text,r - 64,nonce,activeclients[i].clientshortservershort)) break;
442
443 /* XXX: update clientip, clientextension */
444 activeclients[i].receivednonce = packetnonce;
445 text[31] = (r - 96) >> 4;
446 if (writeall(activeclients[i].tochild,text + 31,r - 95) == -1)
447 ; /* child is gone; will see eof later */
448 break;
449 }
450 }
451 } while (0);
452
453 for (i = numactiveclients - 1;i >= 0;--i) {
454 do {
455 if (!p[i].revents) break;
456 r = read(activeclients[i].fromchild,childbuf,sizeof childbuf);
457 if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
458 if (r <= 0) goto endconnection;
459 childbuflen = r;
460 for (k = 0;k < childbuflen;++k) {
461 r = activeclients[i].messagelen;
462 if (r < 0) goto endconnection;
463 if (r >= MESSAGELEN) goto endconnection;
464 activeclients[i].message[r] = childbuf[k];
465 if (r == 0) if (childbuf[k] & 128) goto endconnection;
466 activeclients[i].messagelen = r + 1;
467 if (r == 16 * (unsigned long long) activeclients[i].message[0]) {
468 if (r < 16) goto endconnection;
469 if (r > 1088) goto endconnection;
470 byte_copy(nonce,16,"CurveCP-server-M");
471 uint64_pack(nonce + 16,++activeclients[i].sentnonce);
472 byte_zero(text,32);
473 byte_copy(text + 32,r,activeclients[i].message + 1);
474 crypto_box_afternm(text,text,r + 32,nonce,activeclients[i].clientshortservershort);
475 byte_copy(packet,8,"RL3aNMXM");
476 byte_copy(packet + 8,16,clientextension);
477 byte_copy(packet + 24,16,serverextension);
478 byte_copy(packet + 40,8,nonce + 16);
479 byte_copy(packet + 48,r + 16,text + 16);
480 socket_send(udpfd,packet,r + 64,activeclients[i].clientip,activeclients[i].clientport);
481 activeclients[i].messagelen = 0;
482 }
483 }
484 break;
485
486 endconnection:
487
488 /* XXX: cache cookie if it's recent */
489 close(activeclients[i].fromchild); activeclients[i].fromchild = -1;
490 close(activeclients[i].tochild); activeclients[i].tochild = -1;
491 --numactiveclients;
492 activeclients[i] = activeclients[numactiveclients];
493 randombytes((void *) &activeclients[numactiveclients],sizeof(struct activeclient));
494 } while (0);
495 }
496 }
497}
diff --git a/nacl/curvecp/die.c b/nacl/curvecp/die.c
new file mode 100644
index 00000000..2220cf38
--- /dev/null
+++ b/nacl/curvecp/die.c
@@ -0,0 +1,42 @@
1#include <unistd.h>
2#include "writeall.h"
3#include "die.h"
4
5void die_9(int e
6 ,const char *s0
7 ,const char *s1
8 ,const char *s2
9 ,const char *s3
10 ,const char *s4
11 ,const char *s5
12 ,const char *s6
13 ,const char *s7
14 ,const char *s8
15)
16{
17 const char *s[9];
18 const char *x;
19 char buf[1024];
20 int buflen = 0;
21 int i;
22
23 s[0] = s0;
24 s[1] = s1;
25 s[2] = s2;
26 s[3] = s3;
27 s[4] = s4;
28 s[5] = s5;
29 s[6] = s6;
30 s[7] = s7;
31 s[8] = s8;
32 for (i = 0;i < 9;++i) {
33 x = s[i];
34 if (!x) continue;
35 while (*x) {
36 if (buflen == sizeof buf) { writeall(2,buf,buflen); buflen = 0; }
37 buf[buflen++] = *x++;
38 }
39 }
40 writeall(2,buf,buflen);
41 _exit(e);
42}
diff --git a/nacl/curvecp/die.h b/nacl/curvecp/die.h
new file mode 100644
index 00000000..52ec7616
--- /dev/null
+++ b/nacl/curvecp/die.h
@@ -0,0 +1,16 @@
1#ifndef DIE_H
2#define DIE_H
3
4extern void die_9(int,const char *,const char *,const char *,const char *,const char *,const char *,const char *,const char *,const char *);
5
6#define die_8(x,a,b,c,d,e,f,g,h) die_9(x,a,b,c,d,e,f,g,h,0)
7#define die_7(x,a,b,c,d,e,f,g) die_8(x,a,b,c,d,e,f,g,0)
8#define die_6(x,a,b,c,d,e,f) die_7(x,a,b,c,d,e,f,0)
9#define die_5(x,a,b,c,d,e) die_6(x,a,b,c,d,e,0)
10#define die_4(x,a,b,c,d) die_5(x,a,b,c,d,0)
11#define die_3(x,a,b,c) die_4(x,a,b,c,0)
12#define die_2(x,a,b) die_3(x,a,b,0)
13#define die_1(x,a) die_2(x,a,0)
14#define die_0(x) die_1(x,0)
15
16#endif
diff --git a/nacl/curvecp/e.c b/nacl/curvecp/e.c
new file mode 100644
index 00000000..00ff7fd9
--- /dev/null
+++ b/nacl/curvecp/e.c
@@ -0,0 +1,106 @@
1#include "e.h"
2
3#define X(e,s) if (i == e) return s;
4
5const char *e_str(int i)
6{
7 X(0,"no error");
8 X(EINTR,"interrupted system call")
9 X(ENOMEM,"out of memory")
10 X(ENOENT,"file does not exist")
11 X(ETXTBSY,"text busy")
12 X(EIO,"input/output error")
13 X(EEXIST,"file already exists")
14 X(ETIMEDOUT,"timed out")
15 X(EINPROGRESS,"operation in progress")
16 X(EAGAIN,"temporary failure")
17 X(EWOULDBLOCK,"input/output would block")
18 X(EPIPE,"broken pipe")
19 X(EPERM,"permission denied")
20 X(EACCES,"access denied")
21 X(ENODEV,"device not configured")
22 X(EPROTO,"protocol error")
23 X(EISDIR,"is a directory")
24 X(ESRCH,"no such process")
25 X(E2BIG,"argument list too long")
26 X(ENOEXEC,"exec format error")
27 X(EBADF,"file descriptor not open")
28 X(ECHILD,"no child processes")
29 X(EDEADLK,"operation would cause deadlock")
30 X(EFAULT,"bad address")
31 X(ENOTBLK,"not a block device")
32 X(EBUSY,"device busy")
33 X(EXDEV,"cross-device link")
34 X(ENODEV,"device does not support operation")
35 X(ENOTDIR,"not a directory")
36 X(EINVAL,"invalid argument")
37 X(ENFILE,"system cannot open more files")
38 X(EMFILE,"process cannot open more files")
39 X(ENOTTY,"not a tty")
40 X(EFBIG,"file too big")
41 X(ENOSPC,"out of disk space")
42 X(ESPIPE,"unseekable descriptor")
43 X(EROFS,"read-only file system")
44 X(EMLINK,"too many links")
45 X(EDOM,"input out of range")
46 X(ERANGE,"output out of range")
47 X(EALREADY,"operation already in progress")
48 X(ENOTSOCK,"not a socket")
49 X(EDESTADDRREQ,"destination address required")
50 X(EMSGSIZE,"message too long")
51 X(EPROTOTYPE,"incorrect protocol type")
52 X(ENOPROTOOPT,"protocol not available")
53 X(EPROTONOSUPPORT,"protocol not supported")
54 X(ESOCKTNOSUPPORT,"socket type not supported")
55 X(EOPNOTSUPP,"operation not supported")
56 X(EPFNOSUPPORT,"protocol family not supported")
57 X(EAFNOSUPPORT,"address family not supported")
58 X(EADDRINUSE,"address already used")
59 X(EADDRNOTAVAIL,"address not available")
60 X(ENETDOWN,"network down")
61 X(ENETUNREACH,"network unreachable")
62 X(ENETRESET,"network reset")
63 X(ECONNABORTED,"connection aborted")
64 X(ECONNRESET,"connection reset")
65 X(ENOBUFS,"out of buffer space")
66 X(EISCONN,"already connected")
67 X(ENOTCONN,"not connected")
68 X(ESHUTDOWN,"socket shut down")
69 X(ETOOMANYREFS,"too many references")
70 X(ECONNREFUSED,"connection refused")
71 X(ELOOP,"symbolic link loop")
72 X(ENAMETOOLONG,"file name too long")
73 X(EHOSTDOWN,"host down")
74 X(EHOSTUNREACH,"host unreachable")
75 X(ENOTEMPTY,"directory not empty")
76 X(EPROCLIM,"too many processes")
77 X(EUSERS,"too many users")
78 X(EDQUOT,"disk quota exceeded")
79 X(ESTALE,"stale NFS file handle")
80 X(EREMOTE,"too many levels of remote in path")
81 X(EBADRPC,"RPC structure is bad")
82 X(ERPCMISMATCH,"RPC version mismatch")
83 X(EPROGUNAVAIL,"RPC program unavailable")
84 X(EPROGMISMATCH,"program version mismatch")
85 X(EPROCUNAVAIL,"bad procedure for program")
86 X(ENOLCK,"no locks available")
87 X(ENOSYS,"system call not available")
88 X(EFTYPE,"bad file type")
89 X(EAUTH,"authentication error")
90 X(ENEEDAUTH,"not authenticated")
91 X(ENOSTR,"not a stream device")
92 X(ETIME,"timer expired")
93 X(ENOSR,"out of stream resources")
94 X(ENOMSG,"no message of desired type")
95 X(EBADMSG,"bad message type")
96 X(EIDRM,"identifier removed")
97 X(ENONET,"machine not on network")
98 X(EREMOTE,"object not local")
99 X(ENOLINK,"link severed")
100 X(EADV,"advertise error")
101 X(ESRMNT,"srmount error")
102 X(ECOMM,"communication error")
103 X(EMULTIHOP,"multihop attempted")
104 X(EREMCHG,"remote address changed")
105 return "unknown error";
106}
diff --git a/nacl/curvecp/e.h b/nacl/curvecp/e.h
new file mode 100644
index 00000000..add0768b
--- /dev/null
+++ b/nacl/curvecp/e.h
@@ -0,0 +1,438 @@
1#ifndef E_H
2#define E_H
3
4#include <errno.h>
5
6extern const char *e_str(int);
7
8#ifndef EPERM
9#define EPERM (-5001)
10#endif
11#ifndef ENOENT
12#define ENOENT (-5002)
13#endif
14#ifndef ESRCH
15#define ESRCH (-5003)
16#endif
17#ifndef EINTR
18#define EINTR (-5004)
19#endif
20#ifndef EIO
21#define EIO (-5005)
22#endif
23#ifndef ENXIO
24#define ENXIO (-5006)
25#endif
26#ifndef E2BIG
27#define E2BIG (-5007)
28#endif
29#ifndef ENOEXEC
30#define ENOEXEC (-5008)
31#endif
32#ifndef EBADF
33#define EBADF (-5009)
34#endif
35#ifndef ECHILD
36#define ECHILD (-5010)
37#endif
38#ifndef EAGAIN
39#define EAGAIN (-5011)
40#endif
41#ifndef EWOULDBLOCK
42#define EWOULDBLOCK (-7011)
43#endif
44#ifndef ENOMEM
45#define ENOMEM (-5012)
46#endif
47#ifndef EACCES
48#define EACCES (-5013)
49#endif
50#ifndef EFAULT
51#define EFAULT (-5014)
52#endif
53#ifndef ENOTBLK
54#define ENOTBLK (-5015)
55#endif
56#ifndef EBUSY
57#define EBUSY (-5016)
58#endif
59#ifndef EEXIST
60#define EEXIST (-5017)
61#endif
62#ifndef EXDEV
63#define EXDEV (-5018)
64#endif
65#ifndef ENODEV
66#define ENODEV (-5019)
67#endif
68#ifndef ENOTDIR
69#define ENOTDIR (-5020)
70#endif
71#ifndef EISDIR
72#define EISDIR (-5021)
73#endif
74#ifndef EINVAL
75#define EINVAL (-5022)
76#endif
77#ifndef ENFILE
78#define ENFILE (-5023)
79#endif
80#ifndef EMFILE
81#define EMFILE (-5024)
82#endif
83#ifndef ENOTTY
84#define ENOTTY (-5025)
85#endif
86#ifndef ETXTBSY
87#define ETXTBSY (-5026)
88#endif
89#ifndef EFBIG
90#define EFBIG (-5027)
91#endif
92#ifndef ENOSPC
93#define ENOSPC (-5028)
94#endif
95#ifndef ESPIPE
96#define ESPIPE (-5029)
97#endif
98#ifndef EROFS
99#define EROFS (-5030)
100#endif
101#ifndef EMLINK
102#define EMLINK (-5031)
103#endif
104#ifndef EPIPE
105#define EPIPE (-5032)
106#endif
107#ifndef EDOM
108#define EDOM (-5033)
109#endif
110#ifndef ERANGE
111#define ERANGE (-5034)
112#endif
113#ifndef EDEADLK
114#define EDEADLK (-5035)
115#endif
116#ifndef EDEADLOCK
117#define EDEADLOCK (-7035)
118#endif
119#ifndef ENAMETOOLONG
120#define ENAMETOOLONG (-5036)
121#endif
122#ifndef ENOLCK
123#define ENOLCK (-5037)
124#endif
125#ifndef ENOSYS
126#define ENOSYS (-5038)
127#endif
128#ifndef ENOTEMPTY
129#define ENOTEMPTY (-5039)
130#endif
131#ifndef ELOOP
132#define ELOOP (-5040)
133#endif
134#ifndef ENOMSG
135#define ENOMSG (-5042)
136#endif
137#ifndef EIDRM
138#define EIDRM (-5043)
139#endif
140#ifndef ECHRNG
141#define ECHRNG (-5044)
142#endif
143#ifndef EL2NSYNC
144#define EL2NSYNC (-5045)
145#endif
146#ifndef EL3HLT
147#define EL3HLT (-5046)
148#endif
149#ifndef EL3RST
150#define EL3RST (-5047)
151#endif
152#ifndef ELNRNG
153#define ELNRNG (-5048)
154#endif
155#ifndef EUNATCH
156#define EUNATCH (-5049)
157#endif
158#ifndef ENOCSI
159#define ENOCSI (-5050)
160#endif
161#ifndef EL2HLT
162#define EL2HLT (-5051)
163#endif
164#ifndef EBADE
165#define EBADE (-5052)
166#endif
167#ifndef EBADR
168#define EBADR (-5053)
169#endif
170#ifndef EXFULL
171#define EXFULL (-5054)
172#endif
173#ifndef ENOANO
174#define ENOANO (-5055)
175#endif
176#ifndef EBADRQC
177#define EBADRQC (-5056)
178#endif
179#ifndef EBADSLT
180#define EBADSLT (-5057)
181#endif
182#ifndef EBFONT
183#define EBFONT (-5059)
184#endif
185#ifndef ENOSTR
186#define ENOSTR (-5060)
187#endif
188#ifndef ENODATA
189#define ENODATA (-5061)
190#endif
191#ifndef ETIME
192#define ETIME (-5062)
193#endif
194#ifndef ENOSR
195#define ENOSR (-5063)
196#endif
197#ifndef ENONET
198#define ENONET (-5064)
199#endif
200#ifndef ENOPKG
201#define ENOPKG (-5065)
202#endif
203#ifndef EREMOTE
204#define EREMOTE (-5066)
205#endif
206#ifndef ENOLINK
207#define ENOLINK (-5067)
208#endif
209#ifndef EADV
210#define EADV (-5068)
211#endif
212#ifndef ESRMNT
213#define ESRMNT (-5069)
214#endif
215#ifndef ECOMM
216#define ECOMM (-5070)
217#endif
218#ifndef EPROTO
219#define EPROTO (-5071)
220#endif
221#ifndef EMULTIHOP
222#define EMULTIHOP (-5072)
223#endif
224#ifndef EDOTDOT
225#define EDOTDOT (-5073)
226#endif
227#ifndef EBADMSG
228#define EBADMSG (-5074)
229#endif
230#ifndef EOVERFLOW
231#define EOVERFLOW (-5075)
232#endif
233#ifndef ENOTUNIQ
234#define ENOTUNIQ (-5076)
235#endif
236#ifndef EBADFD
237#define EBADFD (-5077)
238#endif
239#ifndef EREMCHG
240#define EREMCHG (-5078)
241#endif
242#ifndef ELIBACC
243#define ELIBACC (-5079)
244#endif
245#ifndef ELIBBAD
246#define ELIBBAD (-5080)
247#endif
248#ifndef ELIBSCN
249#define ELIBSCN (-5081)
250#endif
251#ifndef ELIBMAX
252#define ELIBMAX (-5082)
253#endif
254#ifndef ELIBEXEC
255#define ELIBEXEC (-5083)
256#endif
257#ifndef EILSEQ
258#define EILSEQ (-5084)
259#endif
260#ifndef ERESTART
261#define ERESTART (-5085)
262#endif
263#ifndef ESTRPIPE
264#define ESTRPIPE (-5086)
265#endif
266#ifndef EUSERS
267#define EUSERS (-5087)
268#endif
269#ifndef ENOTSOCK
270#define ENOTSOCK (-5088)
271#endif
272#ifndef EDESTADDRREQ
273#define EDESTADDRREQ (-5089)
274#endif
275#ifndef EMSGSIZE
276#define EMSGSIZE (-5090)
277#endif
278#ifndef EPROTOTYPE
279#define EPROTOTYPE (-5091)
280#endif
281#ifndef ENOPROTOOPT
282#define ENOPROTOOPT (-5092)
283#endif
284#ifndef EPROTONOSUPPORT
285#define EPROTONOSUPPORT (-5093)
286#endif
287#ifndef ESOCKTNOSUPPORT
288#define ESOCKTNOSUPPORT (-5094)
289#endif
290#ifndef EOPNOTSUPP
291#define EOPNOTSUPP (-5095)
292#endif
293#ifndef EPFNOSUPPORT
294#define EPFNOSUPPORT (-5096)
295#endif
296#ifndef EAFNOSUPPORT
297#define EAFNOSUPPORT (-5097)
298#endif
299#ifndef EADDRINUSE
300#define EADDRINUSE (-5098)
301#endif
302#ifndef EADDRNOTAVAIL
303#define EADDRNOTAVAIL (-5099)
304#endif
305#ifndef ENETDOWN
306#define ENETDOWN (-5100)
307#endif
308#ifndef ENETUNREACH
309#define ENETUNREACH (-5101)
310#endif
311#ifndef ENETRESET
312#define ENETRESET (-5102)
313#endif
314#ifndef ECONNABORTED
315#define ECONNABORTED (-5103)
316#endif
317#ifndef ECONNRESET
318#define ECONNRESET (-5104)
319#endif
320#ifndef ENOBUFS
321#define ENOBUFS (-5105)
322#endif
323#ifndef EISCONN
324#define EISCONN (-5106)
325#endif
326#ifndef ENOTCONN
327#define ENOTCONN (-5107)
328#endif
329#ifndef ESHUTDOWN
330#define ESHUTDOWN (-5108)
331#endif
332#ifndef ETOOMANYREFS
333#define ETOOMANYREFS (-5109)
334#endif
335#ifndef ETIMEDOUT
336#define ETIMEDOUT (-5110)
337#endif
338#ifndef ECONNREFUSED
339#define ECONNREFUSED (-5111)
340#endif
341#ifndef EHOSTDOWN
342#define EHOSTDOWN (-5112)
343#endif
344#ifndef EHOSTUNREACH
345#define EHOSTUNREACH (-5113)
346#endif
347#ifndef EALREADY
348#define EALREADY (-5114)
349#endif
350#ifndef EINPROGRESS
351#define EINPROGRESS (-5115)
352#endif
353#ifndef ESTALE
354#define ESTALE (-5116)
355#endif
356#ifndef EUCLEAN
357#define EUCLEAN (-5117)
358#endif
359#ifndef ENOTNAM
360#define ENOTNAM (-5118)
361#endif
362#ifndef ENAVAIL
363#define ENAVAIL (-5119)
364#endif
365#ifndef EISNAM
366#define EISNAM (-5120)
367#endif
368#ifndef EREMOTEIO
369#define EREMOTEIO (-5121)
370#endif
371#ifndef EDQUOT
372#define EDQUOT (-5122)
373#endif
374#ifndef ENOMEDIUM
375#define ENOMEDIUM (-5123)
376#endif
377#ifndef EMEDIUMTYPE
378#define EMEDIUMTYPE (-5124)
379#endif
380#ifndef ECANCELED
381#define ECANCELED (-5125)
382#endif
383#ifndef ENOKEY
384#define ENOKEY (-5126)
385#endif
386#ifndef EKEYEXPIRED
387#define EKEYEXPIRED (-5127)
388#endif
389#ifndef EKEYREVOKED
390#define EKEYREVOKED (-5128)
391#endif
392#ifndef EKEYREJECTED
393#define EKEYREJECTED (-5129)
394#endif
395#ifndef EOWNERDEAD
396#define EOWNERDEAD (-5130)
397#endif
398#ifndef ENOTRECOVERABLE
399#define ENOTRECOVERABLE (-5131)
400#endif
401#ifndef ERFKILL
402#define ERFKILL (-5132)
403#endif
404#ifndef EPROCLIM
405#define EPROCLIM (-6067)
406#endif
407#ifndef EBADRPC
408#define EBADRPC (-6072)
409#endif
410#ifndef ERPCMISMATCH
411#define ERPCMISMATCH (-6073)
412#endif
413#ifndef EPROGUNAVAIL
414#define EPROGUNAVAIL (-6074)
415#endif
416#ifndef EPROGMISMATCH
417#define EPROGMISMATCH (-6075)
418#endif
419#ifndef EPROCUNAVAIL
420#define EPROCUNAVAIL (-6076)
421#endif
422#ifndef EFTYPE
423#define EFTYPE (-6079)
424#endif
425#ifndef EAUTH
426#define EAUTH (-6080)
427#endif
428#ifndef ENEEDAUTH
429#define ENEEDAUTH (-6081)
430#endif
431#ifndef ENOATTR
432#define ENOATTR (-6087)
433#endif
434#ifndef ENOTCAPABLE
435#define ENOTCAPABLE (-6093)
436#endif
437
438#endif
diff --git a/nacl/curvecp/hexparse.c b/nacl/curvecp/hexparse.c
new file mode 100644
index 00000000..43bfe044
--- /dev/null
+++ b/nacl/curvecp/hexparse.c
@@ -0,0 +1,25 @@
1#include "hexparse.h"
2
3static int hexdigit(char x)
4{
5 if (x >= '0' && x <= '9') return x - '0';
6 if (x >= 'a' && x <= 'f') return 10 + (x - 'a');
7 if (x >= 'A' && x <= 'F') return 10 + (x - 'A');
8 return -1;
9}
10
11int hexparse(unsigned char *y,long long len,const char *x)
12{
13 if (!x) return 0;
14 while (len > 0) {
15 int digit0;
16 int digit1;
17 digit0 = hexdigit(x[0]); if (digit0 == -1) return 0;
18 digit1 = hexdigit(x[1]); if (digit1 == -1) return 0;
19 *y++ = digit1 + 16 * digit0;
20 --len;
21 x += 2;
22 }
23 if (x[0]) return 0;
24 return 1;
25}
diff --git a/nacl/curvecp/hexparse.h b/nacl/curvecp/hexparse.h
new file mode 100644
index 00000000..4e88e187
--- /dev/null
+++ b/nacl/curvecp/hexparse.h
@@ -0,0 +1,6 @@
1#ifndef HEXPARSE_H
2#define HEXPARSE_H
3
4extern int hexparse(unsigned char *,long long,const char *);
5
6#endif
diff --git a/nacl/curvecp/load.c b/nacl/curvecp/load.c
new file mode 100644
index 00000000..0cd4e43d
--- /dev/null
+++ b/nacl/curvecp/load.c
@@ -0,0 +1,33 @@
1#include <unistd.h>
2#include "open.h"
3#include "e.h"
4#include "load.h"
5
6static int readall(int fd,void *x,long long xlen)
7{
8 long long r;
9 while (xlen > 0) {
10 r = xlen;
11 if (r > 1048576) r = 1048576;
12 r = read(fd,x,r);
13 if (r == 0) errno = EPROTO;
14 if (r <= 0) {
15 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) continue;
16 return -1;
17 }
18 x += r;
19 xlen -= r;
20 }
21 return 0;
22}
23
24int load(const char *fn,void *x,long long xlen)
25{
26 int fd;
27 int r;
28 fd = open_read(fn);
29 if (fd == -1) return -1;
30 r = readall(fd,x,xlen);
31 close(fd);
32 return r;
33}
diff --git a/nacl/curvecp/load.h b/nacl/curvecp/load.h
new file mode 100644
index 00000000..9ff1ab2c
--- /dev/null
+++ b/nacl/curvecp/load.h
@@ -0,0 +1,6 @@
1#ifndef LOAD_H
2#define LOAD_H
3
4extern int load(const char *,void *,long long);
5
6#endif
diff --git a/nacl/curvecp/nameparse.c b/nacl/curvecp/nameparse.c
new file mode 100644
index 00000000..f6386d73
--- /dev/null
+++ b/nacl/curvecp/nameparse.c
@@ -0,0 +1,19 @@
1#include "nameparse.h"
2
3int nameparse(unsigned char *s,const char *x)
4{
5 long long pos;
6 long long j;
7 if (!x) return 0;
8 for (pos = 0;pos < 256;++pos) s[pos] = 0;
9 pos = 0;
10 while (*x) {
11 if (*x == '.') { ++x; continue; }
12 for (j = 0;x[j];++j) if (x[j] == '.') break;
13 if (j > 63) return 0;
14 if (pos < 0 || pos >= 256) return 0; s[pos++] = j;
15 while (j > 0) { if (pos < 0 || pos >= 256) return 0; s[pos++] = *x++; --j; }
16 }
17 if (pos < 0 || pos >= 256) return 0; s[pos++] = 0;
18 return 1;
19}
diff --git a/nacl/curvecp/nameparse.h b/nacl/curvecp/nameparse.h
new file mode 100644
index 00000000..97c56e8b
--- /dev/null
+++ b/nacl/curvecp/nameparse.h
@@ -0,0 +1,6 @@
1#ifndef NAMEPARSE_H
2#define NAMEPARSE_H
3
4extern int nameparse(unsigned char *,const char *);
5
6#endif
diff --git a/nacl/curvecp/nanoseconds.c b/nacl/curvecp/nanoseconds.c
new file mode 100644
index 00000000..158ff402
--- /dev/null
+++ b/nacl/curvecp/nanoseconds.c
@@ -0,0 +1,12 @@
1#include <time.h>
2#include "nanoseconds.h"
3
4/* XXX: Y2036 problems; should upgrade to a 128-bit type for this */
5/* XXX: nanosecond granularity limits users to 1 terabyte per second */
6
7long long nanoseconds(void)
8{
9 struct timespec t;
10 if (clock_gettime(CLOCK_REALTIME,&t) != 0) return -1;
11 return t.tv_sec * 1000000000LL + t.tv_nsec;
12}
diff --git a/nacl/curvecp/nanoseconds.h b/nacl/curvecp/nanoseconds.h
new file mode 100644
index 00000000..eb72ec0f
--- /dev/null
+++ b/nacl/curvecp/nanoseconds.h
@@ -0,0 +1,6 @@
1#ifndef NANOSECONDS_H
2#define NANOSECONDS_H
3
4extern long long nanoseconds(void);
5
6#endif
diff --git a/nacl/curvecp/open.h b/nacl/curvecp/open.h
new file mode 100644
index 00000000..a6ef9ec4
--- /dev/null
+++ b/nacl/curvecp/open.h
@@ -0,0 +1,10 @@
1#ifndef OPEN_H
2#define OPEN_H
3
4extern int open_read(const char *);
5extern int open_write(const char *);
6extern int open_lock(const char *);
7extern int open_cwd(void);
8extern int open_pipe(int *);
9
10#endif
diff --git a/nacl/curvecp/open_cwd.c b/nacl/curvecp/open_cwd.c
new file mode 100644
index 00000000..65d53bcd
--- /dev/null
+++ b/nacl/curvecp/open_cwd.c
@@ -0,0 +1,6 @@
1#include "open.h"
2
3int open_cwd(void)
4{
5 return open_read(".");
6}
diff --git a/nacl/curvecp/open_lock.c b/nacl/curvecp/open_lock.c
new file mode 100644
index 00000000..898f3b60
--- /dev/null
+++ b/nacl/curvecp/open_lock.c
@@ -0,0 +1,19 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include "open.h"
6
7int open_lock(const char *fn)
8{
9#ifdef O_CLOEXEC
10 int fd = open(fn,O_RDWR | O_CLOEXEC);
11 if (fd == -1) return -1;
12#else
13 int fd = open(fn,O_RDWR);
14 if (fd == -1) return -1;
15 fcntl(fd,F_SETFD,1);
16#endif
17 if (lockf(fd,F_LOCK,0) == -1) { close(fd); return -1; }
18 return fd;
19}
diff --git a/nacl/curvecp/open_pipe.c b/nacl/curvecp/open_pipe.c
new file mode 100644
index 00000000..2fc2b1af
--- /dev/null
+++ b/nacl/curvecp/open_pipe.c
@@ -0,0 +1,15 @@
1#include <unistd.h>
2#include <fcntl.h>
3#include "open.h"
4#include "blocking.h"
5
6int open_pipe(int *fd)
7{
8 int i;
9 if (pipe(fd) == -1) return -1;
10 for (i = 0;i < 2;++i) {
11 fcntl(fd[i],F_SETFD,1);
12 blocking_disable(fd[i]);
13 }
14 return 0;
15}
diff --git a/nacl/curvecp/open_read.c b/nacl/curvecp/open_read.c
new file mode 100644
index 00000000..cea667b5
--- /dev/null
+++ b/nacl/curvecp/open_read.c
@@ -0,0 +1,17 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include "open.h"
6
7int open_read(const char *fn)
8{
9#ifdef O_CLOEXEC
10 return open(fn,O_RDONLY | O_NONBLOCK | O_CLOEXEC);
11#else
12 int fd = open(fn,O_RDONLY | O_NONBLOCK);
13 if (fd == -1) return -1;
14 fcntl(fd,F_SETFD,1);
15 return fd;
16#endif
17}
diff --git a/nacl/curvecp/open_write.c b/nacl/curvecp/open_write.c
new file mode 100644
index 00000000..e23752d1
--- /dev/null
+++ b/nacl/curvecp/open_write.c
@@ -0,0 +1,17 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include "open.h"
6
7int open_write(const char *fn)
8{
9#ifdef O_CLOEXEC
10 return open(fn,O_CREAT | O_WRONLY | O_NONBLOCK | O_CLOEXEC,0644);
11#else
12 int fd = open(fn,O_CREAT | O_WRONLY | O_NONBLOCK,0644);
13 if (fd == -1) return -1;
14 fcntl(fd,F_SETFD,1);
15 return fd;
16#endif
17}
diff --git a/nacl/curvecp/portparse.c b/nacl/curvecp/portparse.c
new file mode 100644
index 00000000..37e4caca
--- /dev/null
+++ b/nacl/curvecp/portparse.c
@@ -0,0 +1,14 @@
1#include "portparse.h"
2
3int portparse(unsigned char *y,const char *x)
4{
5 long long d = 0;
6 long long j;
7 for (j = 0;j < 5 && x[j] >= '0' && x[j] <= '9';++j)
8 d = d * 10 + (x[j] - '0');
9 if (j == 0) return 0;
10 if (x[j]) return 0;
11 y[0] = d >> 8;
12 y[1] = d;
13 return 1;
14}
diff --git a/nacl/curvecp/portparse.h b/nacl/curvecp/portparse.h
new file mode 100644
index 00000000..99a17748
--- /dev/null
+++ b/nacl/curvecp/portparse.h
@@ -0,0 +1,6 @@
1#ifndef PORTPARSE_H
2#define PORTPARSE_H
3
4extern int portparse(unsigned char *,const char *);
5
6#endif
diff --git a/nacl/curvecp/randommod.c b/nacl/curvecp/randommod.c
new file mode 100644
index 00000000..575a627b
--- /dev/null
+++ b/nacl/curvecp/randommod.c
@@ -0,0 +1,14 @@
1#include "randombytes.h"
2
3/* XXX: current implementation is limited to n<2^55 */
4
5long long randommod(long long n)
6{
7 long long result = 0;
8 long long j;
9 unsigned char r[32];
10 if (n <= 1) return 0;
11 randombytes(r,32);
12 for (j = 0;j < 32;++j) result = (result * 256 + (unsigned long long) r[j]) % n;
13 return result;
14}
diff --git a/nacl/curvecp/randommod.h b/nacl/curvecp/randommod.h
new file mode 100644
index 00000000..2b8405d6
--- /dev/null
+++ b/nacl/curvecp/randommod.h
@@ -0,0 +1,6 @@
1#ifndef RANDOMMOD_H
2#define RANDOMMOD_H
3
4extern long long randommod(long long);
5
6#endif
diff --git a/nacl/curvecp/safenonce.c b/nacl/curvecp/safenonce.c
new file mode 100644
index 00000000..cfcabcd2
--- /dev/null
+++ b/nacl/curvecp/safenonce.c
@@ -0,0 +1,74 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include "crypto_uint64.h"
6#include "uint64_pack.h"
7#include "uint64_unpack.h"
8#include "savesync.h"
9#include "open.h"
10#include "load.h"
11#include "randombytes.h"
12#include "safenonce.h"
13
14#include "crypto_block.h"
15#if crypto_block_BYTES != 16
16error!
17#endif
18#if crypto_block_KEYBYTES != 32
19error!
20#endif
21
22/*
23Output: 128-bit nonce y[0],...,y[15].
24Reads and writes existing 8-byte file ".expertsonly/noncecounter",
25locked via existing 1-byte file ".expertsonly/lock".
26Also reads existing 32-byte file ".expertsonly/noncekey".
27Not thread-safe.
28
29Invariants:
30This process is free to use counters that are >=counterlow and <counterhigh.
31The 8-byte file contains a counter that is safe to use and >=counterhigh.
32
33XXX: should rewrite file in background, rather than briefly pausing
34*/
35
36static crypto_uint64 counterlow = 0;
37static crypto_uint64 counterhigh = 0;
38
39static unsigned char flagkeyloaded = 0;
40static unsigned char noncekey[32];
41static unsigned char data[16];
42
43int safenonce(unsigned char *y,int flaglongterm)
44{
45 if (!flagkeyloaded) {
46 int fdlock;
47 fdlock = open_lock(".expertsonly/lock");
48 if (fdlock == -1) return -1;
49 if (load(".expertsonly/noncekey",noncekey,sizeof noncekey) == -1) { close(fdlock); return -1; }
50 close(fdlock);
51 flagkeyloaded = 1;
52 }
53
54 if (counterlow >= counterhigh) {
55 int fdlock;
56 fdlock = open_lock(".expertsonly/lock");
57 if (fdlock == -1) return -1;
58 if (load(".expertsonly/noncecounter",data,8) == -1) { close(fdlock); return -1; }
59 counterlow = uint64_unpack(data);
60 if (flaglongterm)
61 counterhigh = counterlow + 1048576;
62 else
63 counterhigh = counterlow + 1;
64 uint64_pack(data,counterhigh);
65 if (savesync(".expertsonly/noncecounter",data,8) == -1) { close(fdlock); return -1; }
66 close(fdlock);
67 }
68
69 randombytes(data + 8,8);
70 uint64_pack(data,counterlow++);
71 crypto_block(y,data,noncekey);
72
73 return 0;
74}
diff --git a/nacl/curvecp/safenonce.h b/nacl/curvecp/safenonce.h
new file mode 100644
index 00000000..c01271aa
--- /dev/null
+++ b/nacl/curvecp/safenonce.h
@@ -0,0 +1,6 @@
1#ifndef SAFENONCE_H
2#define SAFENONCE_H
3
4extern int safenonce(unsigned char *,int);
5
6#endif
diff --git a/nacl/curvecp/savesync.c b/nacl/curvecp/savesync.c
new file mode 100644
index 00000000..73074a4b
--- /dev/null
+++ b/nacl/curvecp/savesync.c
@@ -0,0 +1,24 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include "open.h"
6#include "savesync.h"
7#include "writeall.h"
8
9static int writesync(int fd,const void *x,long long xlen)
10{
11 if (writeall(fd,x,xlen) == -1) return -1;
12 return fsync(fd);
13}
14
15int savesync(const char *fn,const void *x,long long xlen)
16{
17 int fd;
18 int r;
19 fd = open_write(fn);
20 if (fd == -1) return -1;
21 r = writesync(fd,x,xlen);
22 close(fd);
23 return r;
24}
diff --git a/nacl/curvecp/savesync.h b/nacl/curvecp/savesync.h
new file mode 100644
index 00000000..4c0cd3d2
--- /dev/null
+++ b/nacl/curvecp/savesync.h
@@ -0,0 +1,6 @@
1#ifndef SAVESYNC_H
2#define SAVESYNC_H
3
4extern int savesync(const char *,const void *,long long);
5
6#endif
diff --git a/nacl/curvecp/socket.h b/nacl/curvecp/socket.h
new file mode 100644
index 00000000..9fab01c7
--- /dev/null
+++ b/nacl/curvecp/socket.h
@@ -0,0 +1,9 @@
1#ifndef SOCKET_H
2#define SOCKET_H
3
4extern int socket_udp(void);
5extern int socket_bind(int,const unsigned char *,const unsigned char *);
6extern int socket_send(int,const unsigned char *,long long,const unsigned char *,const unsigned char *);
7extern long long socket_recv(int,unsigned char *,long long,unsigned char *,unsigned char *);
8
9#endif
diff --git a/nacl/curvecp/socket_bind.c b/nacl/curvecp/socket_bind.c
new file mode 100644
index 00000000..9e36925d
--- /dev/null
+++ b/nacl/curvecp/socket_bind.c
@@ -0,0 +1,15 @@
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <netinet/in.h>
4#include <errno.h>
5#include "socket.h"
6#include "byte.h"
7
8int socket_bind(int fd,const unsigned char *ip,const unsigned char *port)
9{
10 struct sockaddr_in sa;
11 byte_zero(&sa,sizeof sa);
12 byte_copy(&sa.sin_addr,4,ip);
13 byte_copy(&sa.sin_port,2,port);
14 return bind(fd,(struct sockaddr *) &sa,sizeof sa);
15}
diff --git a/nacl/curvecp/socket_recv.c b/nacl/curvecp/socket_recv.c
new file mode 100644
index 00000000..8b266ba2
--- /dev/null
+++ b/nacl/curvecp/socket_recv.c
@@ -0,0 +1,23 @@
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <netinet/in.h>
4#include <errno.h>
5#include "socket.h"
6#include "byte.h"
7
8long long socket_recv(int fd,unsigned char *x,long long xlen,unsigned char *ip,unsigned char *port)
9{
10 struct sockaddr_in sa;
11 socklen_t salen;
12 int r;
13
14 if (xlen < 0) { errno = EPROTO; return -1; }
15 if (xlen > 1048576) xlen = 1048576;
16
17 byte_zero(&sa,sizeof sa);
18 salen = sizeof sa;
19 r = recvfrom(fd,x,xlen,0,(struct sockaddr *) &sa,&salen);
20 byte_copy(ip,4,&sa.sin_addr);
21 byte_copy(port,2,&sa.sin_port);
22 return r;
23}
diff --git a/nacl/curvecp/socket_send.c b/nacl/curvecp/socket_send.c
new file mode 100644
index 00000000..1521384c
--- /dev/null
+++ b/nacl/curvecp/socket_send.c
@@ -0,0 +1,19 @@
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <netinet/in.h>
4#include <errno.h>
5#include "socket.h"
6#include "byte.h"
7
8int socket_send(int fd,const unsigned char *x,long long xlen,const unsigned char *ip,const unsigned char *port)
9{
10 struct sockaddr_in sa;
11
12 if (xlen < 0 || xlen > 1048576) { errno = EPROTO; return -1; }
13
14 byte_zero(&sa,sizeof sa);
15 sa.sin_family = AF_INET;
16 byte_copy(&sa.sin_addr,4,ip);
17 byte_copy(&sa.sin_port,2,port);
18 return sendto(fd,x,xlen,0,(struct sockaddr *) &sa,sizeof sa);
19}
diff --git a/nacl/curvecp/socket_udp.c b/nacl/curvecp/socket_udp.c
new file mode 100644
index 00000000..f64762f1
--- /dev/null
+++ b/nacl/curvecp/socket_udp.c
@@ -0,0 +1,36 @@
1#include <unistd.h>
2#include <fcntl.h>
3#include <sys/types.h>
4#include <sys/socket.h>
5#include <netinet/in.h>
6#include "socket.h"
7#include "blocking.h"
8
9static void enable_bsd_fragmentation(int fd)
10{
11#ifdef IP_DONTFRAG
12 const int x = 0;
13 setsockopt(fd,SOL_IP,IP_DONTFRAG,&x,sizeof x);
14#endif
15}
16
17static void enable_linux_fragmentation(int fd)
18{
19#ifdef IP_MTU_DISCOVER
20#ifdef IP_PMTUDISC_DONT
21 const int x = IP_PMTUDISC_DONT;
22 setsockopt(fd,SOL_IP,IP_MTU_DISCOVER,&x,sizeof x);
23#endif
24#endif
25}
26
27int socket_udp(void)
28{
29 int fd = socket(PF_INET,SOCK_DGRAM,0);
30 if (fd == -1) return -1;
31 fcntl(fd,F_SETFD,1);
32 blocking_disable(fd);
33 enable_bsd_fragmentation(fd);
34 enable_linux_fragmentation(fd);
35 return fd;
36}
diff --git a/nacl/curvecp/uint16_pack.c b/nacl/curvecp/uint16_pack.c
new file mode 100644
index 00000000..f3761035
--- /dev/null
+++ b/nacl/curvecp/uint16_pack.c
@@ -0,0 +1,7 @@
1#include "uint16_pack.h"
2
3void uint16_pack(unsigned char *y,crypto_uint16 x)
4{
5 *y++ = x; x >>= 8;
6 *y++ = x; x >>= 8;
7}
diff --git a/nacl/curvecp/uint16_pack.h b/nacl/curvecp/uint16_pack.h
new file mode 100644
index 00000000..6c5b65e1
--- /dev/null
+++ b/nacl/curvecp/uint16_pack.h
@@ -0,0 +1,8 @@
1#ifndef UINT16_PACK_H
2#define UINT16_PACK_H
3
4#include "crypto_uint16.h"
5
6extern void uint16_pack(unsigned char *,crypto_uint16);
7
8#endif
diff --git a/nacl/curvecp/uint16_unpack.c b/nacl/curvecp/uint16_unpack.c
new file mode 100644
index 00000000..b4e74ee4
--- /dev/null
+++ b/nacl/curvecp/uint16_unpack.c
@@ -0,0 +1,9 @@
1#include "uint16_unpack.h"
2
3crypto_uint16 uint16_unpack(const unsigned char *x)
4{
5 crypto_uint16 result;
6 result = x[1];
7 result <<= 8; result |= x[0];
8 return result;
9}
diff --git a/nacl/curvecp/uint16_unpack.h b/nacl/curvecp/uint16_unpack.h
new file mode 100644
index 00000000..3e3aedfc
--- /dev/null
+++ b/nacl/curvecp/uint16_unpack.h
@@ -0,0 +1,8 @@
1#ifndef UINT16_UNPACK_H
2#define UINT16_UNPACK_H
3
4#include "crypto_uint16.h"
5
6extern crypto_uint16 uint16_unpack(const unsigned char *);
7
8#endif
diff --git a/nacl/curvecp/uint32_pack.c b/nacl/curvecp/uint32_pack.c
new file mode 100644
index 00000000..d54fe542
--- /dev/null
+++ b/nacl/curvecp/uint32_pack.c
@@ -0,0 +1,9 @@
1#include "uint32_pack.h"
2
3void uint32_pack(unsigned char *y,crypto_uint32 x)
4{
5 *y++ = x; x >>= 8;
6 *y++ = x; x >>= 8;
7 *y++ = x; x >>= 8;
8 *y++ = x; x >>= 8;
9}
diff --git a/nacl/curvecp/uint32_pack.h b/nacl/curvecp/uint32_pack.h
new file mode 100644
index 00000000..efdf7919
--- /dev/null
+++ b/nacl/curvecp/uint32_pack.h
@@ -0,0 +1,8 @@
1#ifndef UINT32_PACK_H
2#define UINT32_PACK_H
3
4#include "crypto_uint32.h"
5
6extern void uint32_pack(unsigned char *,crypto_uint32);
7
8#endif
diff --git a/nacl/curvecp/uint32_unpack.c b/nacl/curvecp/uint32_unpack.c
new file mode 100644
index 00000000..adde6987
--- /dev/null
+++ b/nacl/curvecp/uint32_unpack.c
@@ -0,0 +1,11 @@
1#include "uint32_unpack.h"
2
3crypto_uint32 uint32_unpack(const unsigned char *x)
4{
5 crypto_uint32 result;
6 result = x[3];
7 result <<= 8; result |= x[2];
8 result <<= 8; result |= x[1];
9 result <<= 8; result |= x[0];
10 return result;
11}
diff --git a/nacl/curvecp/uint32_unpack.h b/nacl/curvecp/uint32_unpack.h
new file mode 100644
index 00000000..dd65f365
--- /dev/null
+++ b/nacl/curvecp/uint32_unpack.h
@@ -0,0 +1,8 @@
1#ifndef UINT32_UNPACK_H
2#define UINT32_UNPACK_H
3
4#include "crypto_uint32.h"
5
6extern crypto_uint32 uint32_unpack(const unsigned char *);
7
8#endif
diff --git a/nacl/curvecp/uint64_pack.c b/nacl/curvecp/uint64_pack.c
new file mode 100644
index 00000000..898a80a3
--- /dev/null
+++ b/nacl/curvecp/uint64_pack.c
@@ -0,0 +1,13 @@
1#include "uint64_pack.h"
2
3void uint64_pack(unsigned char *y,crypto_uint64 x)
4{
5 *y++ = x; x >>= 8;
6 *y++ = x; x >>= 8;
7 *y++ = x; x >>= 8;
8 *y++ = x; x >>= 8;
9 *y++ = x; x >>= 8;
10 *y++ = x; x >>= 8;
11 *y++ = x; x >>= 8;
12 *y++ = x; x >>= 8;
13}
diff --git a/nacl/curvecp/uint64_pack.h b/nacl/curvecp/uint64_pack.h
new file mode 100644
index 00000000..be8330fd
--- /dev/null
+++ b/nacl/curvecp/uint64_pack.h
@@ -0,0 +1,8 @@
1#ifndef UINT64_PACK_H
2#define UINT64_PACK_H
3
4#include "crypto_uint64.h"
5
6extern void uint64_pack(unsigned char *,crypto_uint64);
7
8#endif
diff --git a/nacl/curvecp/uint64_unpack.c b/nacl/curvecp/uint64_unpack.c
new file mode 100644
index 00000000..2d69bf72
--- /dev/null
+++ b/nacl/curvecp/uint64_unpack.c
@@ -0,0 +1,15 @@
1#include "uint64_unpack.h"
2
3crypto_uint64 uint64_unpack(const unsigned char *x)
4{
5 crypto_uint64 result;
6 result = x[7];
7 result <<= 8; result |= x[6];
8 result <<= 8; result |= x[5];
9 result <<= 8; result |= x[4];
10 result <<= 8; result |= x[3];
11 result <<= 8; result |= x[2];
12 result <<= 8; result |= x[1];
13 result <<= 8; result |= x[0];
14 return result;
15}
diff --git a/nacl/curvecp/uint64_unpack.h b/nacl/curvecp/uint64_unpack.h
new file mode 100644
index 00000000..f40e7a8a
--- /dev/null
+++ b/nacl/curvecp/uint64_unpack.h
@@ -0,0 +1,8 @@
1#ifndef UINT64_UNPACK_H
2#define UINT64_UNPACK_H
3
4#include "crypto_uint64.h"
5
6extern crypto_uint64 uint64_unpack(const unsigned char *);
7
8#endif
diff --git a/nacl/curvecp/writeall.c b/nacl/curvecp/writeall.c
new file mode 100644
index 00000000..58f93011
--- /dev/null
+++ b/nacl/curvecp/writeall.c
@@ -0,0 +1,27 @@
1#include <poll.h>
2#include <unistd.h>
3#include "e.h"
4#include "writeall.h"
5
6int writeall(int fd,const void *x,long long xlen)
7{
8 long long w;
9 while (xlen > 0) {
10 w = xlen;
11 if (w > 1048576) w = 1048576;
12 w = write(fd,x,w);
13 if (w < 0) {
14 if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
15 struct pollfd p;
16 p.fd = fd;
17 p.events = POLLOUT | POLLERR;
18 poll(&p,1,-1);
19 continue;
20 }
21 return -1;
22 }
23 x += w;
24 xlen -= w;
25 }
26 return 0;
27}
diff --git a/nacl/curvecp/writeall.h b/nacl/curvecp/writeall.h
new file mode 100644
index 00000000..92341236
--- /dev/null
+++ b/nacl/curvecp/writeall.h
@@ -0,0 +1,6 @@
1#ifndef WRITEALL_H
2#define WRITEALL_H
3
4extern int writeall(int,const void *,long long);
5
6#endif