├── forward ├── Makefile ├── base32-test.c ├── base32.c ├── base32.h ├── dns.h ├── dns_packet.c ├── dns_random.c ├── dns_random.h ├── dnscurve-keygen.c ├── dnscurve-test-client.c ├── forward.c ├── ip_parse.c ├── ip_parse.h ├── randombytes.c └── udpserver.c ├── nacl-python.patch ├── slownacl ├── __init__.py ├── __init__.pyc ├── curve25519.py ├── curve25519.pyc ├── hash.py ├── hash.pyc ├── poly1305.py ├── poly1305.pyc ├── salsa20.py ├── salsa20.pyc ├── test.py ├── util.py ├── util.pyc ├── verify.py └── verify.pyc └── tools ├── base32.py ├── dns-make-query.py ├── dns-print.py ├── dns.py ├── dnscurve.py ├── nacl-box-open.py ├── nacl-box.py ├── nacl-keypair.py └── netstring.py /forward/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wall -ggdb -std=c99 2 | TARGETS=forward udpserver dnscurve-keygen dnscurve-test-client 3 | 4 | targets: $(TARGETS) 5 | 6 | clean: 7 | rm -f *.o $(TARGETS) 8 | 9 | dnscurve-test-client: dnscurve-test-client.o randombytes.o ip_parse.o dns_packet.o base32.o 10 | gcc $(CFLAGS) -o dnscurve-test-client dnscurve-test-client.o randombytes.o ip_parse.o dns_packet.o base32.o -lnacl 11 | 12 | forward: forward.o dns_packet.o base32.o randombytes.o ip_parse.o dns_random.o 13 | gcc $(CFLAGS) -o forward forward.o dns_packet.o base32.o randombytes.o ip_parse.o dns_random.o -lpthread -lnacl -lrt 14 | 15 | udpserver: udpserver.o ip_parse.o 16 | gcc $(CFLAGS) -o udpserver udpserver.o ip_parse.o 17 | 18 | dnscurve-keygen: dnscurve-keygen.o base32.o randombytes.o 19 | gcc $(CFLAGS) -o dnscurve-keygen dnscurve-keygen.o base32.o randombytes.o -lnacl 20 | 21 | forward.o: forward.c dns.h 22 | gcc $(CFLAGS) -c forward.c 23 | 24 | dns_packet.o: dns_packet.c base32.h dns.h 25 | gcc $(CFLAGS) -c dns_packet.c 26 | 27 | base32.o: base32.c base32.h 28 | gcc $(CFLAGS) -c base32.c 29 | 30 | randombytes.o: randombytes.c 31 | gcc $(CFLAGS) -c randombytes.c 32 | 33 | ip_parse.o: ip_parse.c 34 | gcc $(CFLAGS) -c ip_parse.c 35 | 36 | dns_random.o: ip_parse.c 37 | gcc $(CFLAGS) -c dns_random.c 38 | 39 | udpserver.o: udpserver.c 40 | gcc $(CFLAGS) -c udpserver.c 41 | 42 | dnscurve-keygen.o: dnscurve-keygen.c 43 | gcc $(CFLAGS) -c dnscurve-keygen.c 44 | 45 | dnscurve-test-client.o: dnscurve-test-client.c 46 | gcc $(CFLAGS) -c dnscurve-test-client.c 47 | -------------------------------------------------------------------------------- /forward/base32-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "base32.h" 5 | 6 | int 7 | main(int argc, char **argv) { 8 | uint8_t a[128]; 9 | unsigned alen = sizeof(a); 10 | 11 | if (!base32_encode(a, &alen, argv[1], strlen(argv[1]))) { 12 | perror("encode"); 13 | return 1; 14 | } 15 | 16 | write(1, a, alen); 17 | write(1, "\n", 1); 18 | 19 | uint8_t b[128]; 20 | unsigned blen = sizeof(b); 21 | 22 | if (!base32_decode(b, &blen, a, alen)) { 23 | perror("decode"); 24 | return 1; 25 | } 26 | 27 | write(1, b, blen); 28 | write(1, "\n", 1); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /forward/base32.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const uint8_t kValues[] = 5 | {99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 6 | 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,0,1, 7 | 2,3,4,5,6,7,8,9,99,99,99,99,99,99,99,10,11,12,13,14,15,16,17,18,19,20,21, 8 | 22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,99,99,99,99,99,10,11,12,13,14, 9 | 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,99,99,99,99}; 10 | 11 | int 12 | base32_decode(uint8_t *output, unsigned *ooutlen, 13 | const uint8_t *in, unsigned inlen, int mode) { 14 | unsigned i = 0, j = 0; 15 | unsigned v = 0, bits = 0; 16 | const unsigned outlen = *ooutlen; 17 | 18 | while (j < inlen) { 19 | if (in[j] & 0x80) 20 | goto PROTO; 21 | const uint8_t b = kValues[in[j++]]; 22 | if (b > 31) 23 | goto PROTO; 24 | 25 | v |= ((unsigned) b) << bits; 26 | bits += 5; 27 | 28 | if (bits >= 8) { 29 | if (i >= outlen) 30 | goto TOOBIG; 31 | output[i++] = v; 32 | bits -= 8; 33 | v >>= 8; 34 | } 35 | } 36 | 37 | if (mode) { 38 | if (bits && i >= outlen) 39 | goto TOOBIG; 40 | output[i++] = v & ((1 << bits) - 1); 41 | } 42 | 43 | *ooutlen = i; 44 | return 1; 45 | 46 | TOOBIG: 47 | errno = E2BIG; 48 | return 0; 49 | 50 | PROTO: 51 | errno = EPROTO; 52 | return 0; 53 | } 54 | 55 | int 56 | base32_encode(uint8_t *output, unsigned *ooutlen, const uint8_t *in, unsigned inlen) { 57 | unsigned i = 0, j = 0; 58 | unsigned v = 0, bits = 0; 59 | const unsigned outlen = *ooutlen; 60 | static const char kChars[] = "0123456789abcdefghijklmnopqrstuv"; 61 | 62 | while (j < inlen) { 63 | v |= ((unsigned) in[j++]) << bits; 64 | bits += 8; 65 | 66 | while (bits >= 5) { 67 | if (i >= outlen) 68 | goto TOOBIG; 69 | output[i++] = kChars[v & 31]; 70 | bits -= 5; 71 | v >>= 5; 72 | } 73 | } 74 | 75 | if (bits && i >= outlen) 76 | goto TOOBIG; 77 | output[i++] = kChars[v]; 78 | 79 | *ooutlen = i; 80 | 81 | return 1; 82 | 83 | TOOBIG: 84 | errno = E2BIG; 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /forward/base32.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_32_H 2 | #define BASE_32_H 3 | 4 | #include 5 | 6 | int base32_decode(uint8_t *output, unsigned *ooutlen, 7 | const uint8_t *in, unsigned inlen, int mode); 8 | int base32_encode(uint8_t *output, unsigned *ooutlen, 9 | const uint8_t *in, unsigned inlen); 10 | 11 | #endif // BASE_32_H 12 | -------------------------------------------------------------------------------- /forward/dns.h: -------------------------------------------------------------------------------- 1 | #ifndef DNS_H 2 | #define DNS_H 3 | 4 | // ----------------------------------------------------------------------------- 5 | // Read a DNS name from a packet, decoding jumps etc 6 | // 7 | // name: (output) the resulting name, in DNS length-prefixed, NUL terminated 8 | // format, but without jumps 9 | // namemax: length of @name 10 | // buf: DNS packet 11 | // len: length of @buf 12 | // pos: starting position to read the name from 13 | // returns: 0 on error or the position following the name. 14 | // 15 | // Errno: 16 | // EPROTO: invalid packet 17 | // ----------------------------------------------------------------------------- 18 | unsigned dns_packet_getname(uint8_t *name, unsigned namemax, 19 | const uint8_t *buf, unsigned len, unsigned pos); 20 | 21 | // ----------------------------------------------------------------------------- 22 | // Try to parse and decode a dnscurve query name 23 | // 24 | // box: (output) the 8-byte nonce and box (in binary form) 25 | // boxlen: (in/out) number of bytes in @box on entry. Number of valid bytes on 26 | // successful exit 27 | // publickey: (output) 32-byte array which receives the public key 28 | // zone: (output) the offset into @name where the server's zone starts 29 | // name: (input) a DNS name, without jumps and trusted to be valid 30 | // returns: 1 on success, 0 otherwise 31 | // 32 | // Errno: 33 | // EPROTO: Invalid packet 34 | // E2BIG: one of the base32 values was too large 35 | // ENAMETOOLONG: too many box components found 36 | // ----------------------------------------------------------------------------- 37 | int dns_curve_name_parse(uint8_t *box, unsigned *boxlen, 38 | uint8_t *publickey, unsigned *zone, 39 | const uint8_t *name); 40 | 41 | // ----------------------------------------------------------------------------- 42 | // Try to parse a packet as a DNS curve request 43 | // 44 | // plaintext: (output) a 4096 byte buffer which receives the enclosed packet 45 | // plaintextlen: (output) on success, the length of the data in @plaintext 46 | // public_key: (output) the client's public key (32-bytes) 47 | // nonce: (output) the client's nonce (8-bytes) 48 | // qname: (output) set to point within @buffer to the start of the query name 49 | // qnamelen: (output) set to contain the number of bytes of query name 50 | // buffer: the packet contents 51 | // n: number of bytes in @buffer 52 | // returns: 1 on success, 0 if this doesn't appear to be a DNS curve packet and 53 | // -1 if the DNS curve packet is invalid 54 | // ----------------------------------------------------------------------------- 55 | int dns_curve_request_parse(uint8_t *plaintext, unsigned *plaintextlen, 56 | uint8_t *public_key, uint8_t *nonce, 57 | const uint8_t **qname, unsigned *qnamelen, 58 | const uint8_t *buffer, unsigned n); 59 | 60 | 61 | int dns_curve_request_build(uint8_t *output, unsigned *ooutlen, 62 | const uint8_t *box, unsigned boxlen, 63 | const uint8_t *public_key, 64 | const uint8_t *zone); 65 | 66 | #endif // DNS_H 67 | -------------------------------------------------------------------------------- /forward/dns_packet.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "dns.h" 8 | #include "base32.h" 9 | 10 | extern uint8_t global_secret_key[32]; 11 | 12 | unsigned 13 | dns_packet_getname(uint8_t *name, unsigned namemax, 14 | const uint8_t *buf, unsigned len, unsigned pos) { 15 | unsigned int loop = 0; 16 | unsigned int state = 0; 17 | unsigned int firstcompress = 0; 18 | unsigned int where; 19 | uint8_t ch; 20 | unsigned int namelen = 0; 21 | 22 | for (;;) { 23 | if (pos >= len) goto PROTO; 24 | ch = buf[pos++]; 25 | if (++loop >= 4096) goto PROTO; 26 | 27 | if (state) { 28 | if (namelen + 1 > namemax) goto PROTO; 29 | name[namelen++] = ch; 30 | --state; 31 | } else { 32 | while (ch >= 192) { 33 | where = ch; where -= 192; where <<= 8; 34 | if (pos >= len) goto PROTO; 35 | ch = buf[pos++]; 36 | if (!firstcompress) firstcompress = pos; 37 | pos = where + ch; 38 | if (pos >= len) goto PROTO; 39 | ch = buf[pos++]; 40 | if (++loop >= 4096) goto PROTO; 41 | } 42 | if (ch >= 64) goto PROTO; 43 | if (namelen + 1 > namemax) goto PROTO; 44 | name[namelen++] = ch; 45 | if (!ch) break; 46 | state = ch; 47 | } 48 | } 49 | 50 | if (firstcompress) return firstcompress; 51 | return pos; 52 | 53 | PROTO: 54 | errno = EPROTO; 55 | return 0; 56 | } 57 | 58 | int 59 | dns_curve_name_parse(uint8_t *box, unsigned *boxlen, 60 | uint8_t *publickey, unsigned *zone, 61 | const uint8_t *name) { 62 | uint8_t encoded_box[4096]; 63 | unsigned encoded_boxlen = 0; 64 | unsigned i = 0; 65 | 66 | errno = EPROTO; 67 | 68 | // Concatenate the base32 encoded components which make up the nonce and box 69 | for (;;) { 70 | const uint8_t component_len = name[i]; 71 | if (component_len == 54) { 72 | break; 73 | } else if (component_len > 50) { 74 | return 0; 75 | } else if (component_len == 0) { 76 | return 0; 77 | } 78 | 79 | if (encoded_boxlen + component_len > sizeof(encoded_box)) 80 | goto NAMETOOLONG; 81 | memcpy(encoded_box + encoded_boxlen, name + i + 1, component_len); 82 | encoded_boxlen += component_len; 83 | i += component_len + 1; 84 | } 85 | 86 | // Base32 decode the box 87 | if (!base32_decode(box, boxlen, encoded_box, encoded_boxlen, 0)) 88 | return 0; 89 | 90 | // Next is the public key 91 | if (!(name[i] == 54 && 92 | name[i+1] == 'x' && 93 | name[i+2] == '1' && 94 | name[i+3] == 'a')) 95 | return 0; 96 | 97 | unsigned publickeylen = 32; 98 | if (!base32_decode(publickey, &publickeylen, name + i + 4, 51, 1)) 99 | return 0; 100 | if (publickeylen != 32) 101 | return 0; 102 | 103 | i += 54 + 1; 104 | *zone = i; 105 | 106 | return 1; 107 | 108 | NAMETOOLONG: 109 | errno = ENAMETOOLONG; 110 | return 0; 111 | } 112 | 113 | // ----------------------------------------------------------------------------- 114 | // Try to parse a packet as a DNS curve request 115 | // 116 | // plaintext: (output) a 4096 byte buffer which receives the enclosed packet 117 | // plaintextlen: (output) on success, the length of the data in @plaintext 118 | // public_key: (output) the client's public key (32-bytes) 119 | // nonce: (output) the client's nonce (8-bytes) 120 | // qname: (output) set to point within @buffer to the start of the query name 121 | // qnamelen: (output) set to contain the number of bytes of query name 122 | // buffer: the packet contents 123 | // n: number of bytes in @buffer 124 | // returns: 1 on success, 0 if this doesn't appear to be a DNS curve packet and 125 | // -1 if the DNS curve packet is invalid 126 | // ----------------------------------------------------------------------------- 127 | int 128 | dns_curve_request_parse(uint8_t *plaintext, unsigned *plaintextlen, 129 | uint8_t *public_key, uint8_t *nonce, 130 | const uint8_t **qname, unsigned *qnamelen, 131 | const uint8_t *buffer, unsigned n) { 132 | // The DNSCurve format is quite strict. This is an absolute minimum number 133 | // of bytes 134 | if (n < 17) 135 | return 0; 136 | 137 | // First two bytes are the client selected transaction id 138 | uint16_t transid; 139 | memcpy(&transid, buffer, 2); 140 | 141 | if (memcmp(buffer + 2, "\x00" // query, opcode 0, not authoritative, not 142 | // truncated, recursion not desired 143 | "\x00" // recursion not available, no Z bits, RCODE 0 144 | "\x00\x01" // exactly one question 145 | "\x00\x00" // no answer records 146 | "\x00\x00" // no authority records 147 | "\x00\x00", // no additional records 148 | 10)) 149 | return 0; 150 | 151 | uint8_t queryname[4096]; 152 | unsigned pos = 12; 153 | 154 | *qname = buffer + 12; 155 | pos = dns_packet_getname(queryname, sizeof(queryname), buffer, n, pos); 156 | if (!pos) 157 | return 0; 158 | *qnamelen = pos - 12; 159 | 160 | if (n - pos != 4) 161 | return 0; 162 | 163 | if (memcmp(&buffer[pos], "\x00\x10" // query type TXT 164 | "\x00\x01", 4)) // internet class 165 | return 0; 166 | 167 | uint8_t nonce_and_box[4096]; 168 | unsigned server_zone, nonce_and_box_len = sizeof(nonce_and_box); 169 | if (!dns_curve_name_parse(nonce_and_box, &nonce_and_box_len, 170 | public_key, &server_zone, queryname)) 171 | return 0; 172 | 173 | if (nonce_and_box_len < 8 + crypto_box_curve25519salsa20hmacsha512_ref_AUTHBYTES) 174 | return 0; 175 | 176 | if (*plaintextlen < (nonce_and_box_len - 8) + crypto_box_curve25519salsa20hmacsha512_EXTRABYTES) 177 | return 0; 178 | 179 | if (-1 == crypto_box_curve25519salsa20hmacsha512_open 180 | (plaintext, nonce_and_box + 8, nonce_and_box_len - 8, 181 | nonce_and_box, public_key, global_secret_key)) 182 | return -1; 183 | 184 | memcpy(nonce, nonce_and_box, 8); 185 | *plaintextlen = nonce_and_box_len - 8 - crypto_box_curve25519salsa20hmacsha512_AUTHBYTES; 186 | 187 | return 1; 188 | } 189 | 190 | int 191 | dns_curve_request_build(uint8_t *output, unsigned *ooutlen, 192 | const uint8_t *box, unsigned boxlen, 193 | const uint8_t *public_key, 194 | const uint8_t *zone) { 195 | uint8_t encoded[4096]; 196 | unsigned encodedlen = sizeof(encoded); 197 | unsigned i = 0, j = 0; 198 | const unsigned outlen = *ooutlen; 199 | 200 | if (i + 10 > outlen) 201 | goto TOOBIG; 202 | 203 | memcpy(output + i, "\x00" // query, opcode 0, not authoritative, not 204 | // truncated, recursion not desired 205 | "\x00" // recursion not available, no Z bits, RCODE 0 206 | "\x00\x01" // exactly one question 207 | "\x00\x00" // no answer records 208 | "\x00\x00" // no authority records 209 | "\x00\x00", // no additional records 210 | 10); 211 | i += 10; 212 | 213 | if (!base32_encode(encoded, &encodedlen, box, boxlen)) 214 | return 0; 215 | 216 | while (encodedlen) { 217 | unsigned component_length = encodedlen; 218 | if (component_length > 50) 219 | component_length = 50; 220 | 221 | if (i >= outlen) 222 | goto TOOBIG; 223 | output[i++] = component_length; 224 | if (i + component_length >= outlen) 225 | goto TOOBIG; 226 | memcpy(output + i, encoded + j, component_length); 227 | encodedlen -= component_length; 228 | j += component_length; 229 | i += component_length; 230 | } 231 | 232 | encodedlen = sizeof(encoded); 233 | if (!base32_encode(encoded, &encodedlen, public_key, 32)) 234 | return 0; 235 | if (i + 55 >= outlen) 236 | goto TOOBIG; 237 | 238 | memcpy(output + i, "\x36x1a", 4); 239 | i += 4; 240 | memcpy(output + i, encoded, 51); 241 | i += 51; 242 | 243 | j = 0; 244 | while (zone[j]) { 245 | const unsigned component_length = zone[j++]; 246 | if (i >= outlen) 247 | goto TOOBIG; 248 | output[i++] = component_length; 249 | if (i + component_length >= outlen) 250 | goto TOOBIG; 251 | memcpy(output + i, zone + j, component_length); 252 | i += component_length; 253 | j += component_length; 254 | } 255 | if (i >= outlen) 256 | goto TOOBIG; 257 | output[i++] = 0; 258 | 259 | if (i + 4 > outlen) 260 | goto TOOBIG; 261 | 262 | memcpy(output + i, "\x00\x10" // query type TXT 263 | "\x00\x01", 4); // internet class 264 | i += 4; 265 | 266 | *ooutlen = i; 267 | 268 | return 1; 269 | 270 | TOOBIG: 271 | errno = E2BIG; 272 | return 0; 273 | } 274 | -------------------------------------------------------------------------------- /forward/dns_random.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | static uint32_t seed[32]; 6 | static uint32_t in[12]; 7 | static uint32_t out[8]; 8 | static int outleft = 0; 9 | 10 | #define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b)))) 11 | #define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b)); 12 | 13 | static void 14 | surf(void) { 15 | uint32_t t[12]; uint32_t x; uint32_t sum = 0; 16 | int r; int i; int loop; 17 | 18 | for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i]; 19 | for (i = 0;i < 8;++i) out[i] = seed[24 + i]; 20 | x = t[11]; 21 | for (loop = 0;loop < 2;++loop) { 22 | for (r = 0;r < 16;++r) { 23 | sum += 0x9e3779b9; 24 | MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13) 25 | MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13) 26 | MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13) 27 | } 28 | for (i = 0;i < 8;++i) out[i] ^= t[i + 4]; 29 | } 30 | } 31 | 32 | void 33 | dns_random_init() { 34 | randombytes((uint8_t *) in, sizeof(in)); 35 | } 36 | 37 | unsigned int 38 | dns_random(unsigned int n) { 39 | if (!n) return 0; 40 | 41 | if (!outleft) { 42 | if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3]; 43 | surf(); 44 | outleft = 8; 45 | } 46 | 47 | return out[--outleft] % n; 48 | } 49 | -------------------------------------------------------------------------------- /forward/dns_random.h: -------------------------------------------------------------------------------- 1 | #ifndef DNS_RANDOM_H 2 | #define DNS_RANDOM_H 3 | 4 | // ----------------------------------------------------------------------------- 5 | // Uses randombytes() to see the RNG 6 | // ----------------------------------------------------------------------------- 7 | void dns_random_init(); 8 | 9 | // ----------------------------------------------------------------------------- 10 | // Get a random number in [0..n-1] 11 | // ----------------------------------------------------------------------------- 12 | unsigned int dns_random(unsigned int n); 13 | 14 | #endif // DNS_RANDOM_H 15 | -------------------------------------------------------------------------------- /forward/dnscurve-keygen.c: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // dnscurve-keygen: generate a DNS curve key pair 3 | // 4 | // % keycurve-keygen 5 | // Public key: uz5q7op4l1olejadl91gchal06lfeee9acst0rn9qee3manv4494hs 6 | // Private key: 50fc1266a832ca39c9c6b220b957f7692b6dc38d946726185e164414293d0444 7 | // ----------------------------------------------------------------------------- 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "base32.h" 19 | 20 | // An open descriptor to /dev/urandom 21 | int global_urandom_fd = -1; 22 | 23 | int 24 | main() { 25 | global_urandom_fd = open("/dev/urandom", O_RDONLY); 26 | if (global_urandom_fd < 0) { 27 | perror("Opening /dev/urandom"); 28 | return 1; 29 | } 30 | 31 | uint8_t public[32], private[32]; 32 | crypto_box_curve25519salsa20hmacsha512_keypair(public, private); 33 | 34 | uint8_t dnspublic[64]; 35 | unsigned dnspublic_len = sizeof(dnspublic) - 3; 36 | 37 | memcpy(dnspublic, "uz5", 3); 38 | if (!base32_encode(dnspublic + 3, &dnspublic_len, public, 32)) { 39 | perror("base32_encode"); 40 | return 1; 41 | } 42 | dnspublic[54] = 0; 43 | printf("Public key: %s\n", dnspublic); 44 | 45 | char hexprivate[65]; 46 | static const char hextable[] = "0123456789abcdef"; 47 | 48 | for (unsigned i = 0; i < 32; ++i) { 49 | hexprivate[i*2 ] = hextable[private[i] >> 4]; 50 | hexprivate[i*2 + 1] = hextable[private[i] & 15]; 51 | } 52 | hexprivate[64] = 0; 53 | printf("Private key: %s\n", hexprivate); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /forward/dnscurve-test-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "ip_parse.h" 17 | #include "dns.h" 18 | #include "base32.h" 19 | 20 | static int 21 | usage(const char *argv0) { 22 | fprintf(stderr, "Usage: %s \n", argv0); 23 | return 1; 24 | } 25 | 26 | int global_urandom_fd; 27 | uint8_t global_secret_key[32]; 28 | 29 | int 30 | main(int argc, char **argv) { 31 | global_urandom_fd = open("/dev/urandom", O_RDONLY); 32 | if (global_urandom_fd < 0) { 33 | perror("Opening /dev/urandom"); 34 | return 1; 35 | } 36 | 37 | if (argc != 4) 38 | return usage(argv[0]); 39 | 40 | uint32_t target_ip; 41 | 42 | if (!ip_parse(&target_ip, argv[1])) 43 | return usage(argv[0]); 44 | 45 | const unsigned portnum = strtoul(argv[2], NULL, 10); 46 | 47 | uint8_t server_pk[32]; 48 | unsigned server_pk_len = sizeof(server_pk); 49 | if (!base32_decode(server_pk, &server_pk_len, (const uint8_t *) argv[3], strlen(argv[3]), 1)) { 50 | perror("base32_decode"); 51 | return 1; 52 | } 53 | if (server_pk_len != 32) { 54 | fprintf(stderr, "Invalid server public key\n"); 55 | return 1; 56 | } 57 | 58 | static const char query[] = 59 | "\xab\xcd\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03org\x00\x00\x02\x00\x01"; 60 | 61 | uint8_t pk[32]; 62 | crypto_box_curve25519salsa20hmacsha512_keypair(pk, global_secret_key); 63 | 64 | uint8_t nonce_and_box[4096]; 65 | randombytes(nonce_and_box, 8); 66 | crypto_box_curve25519salsa20hmacsha512(nonce_and_box + 8, query, sizeof(query) - 1, 67 | nonce_and_box, server_pk, global_secret_key); 68 | write(1, pk, 32); 69 | write(1, nonce_and_box, 8 + sizeof(query) + crypto_box_curve25519salsa20hmacsha512_AUTHBYTES); 70 | 71 | uint8_t request[4096]; 72 | unsigned requestlen = sizeof(request) - 2; 73 | 74 | if (!dns_curve_request_build 75 | (request + 2, &requestlen, 76 | nonce_and_box, 8 + sizeof(query) - 1 + 77 | crypto_box_curve25519salsa20hmacsha512_AUTHBYTES, 78 | pk, "\x06google\x03org\x00")) { 79 | perror("dns_curve_request_build"); 80 | return 1; 81 | } 82 | 83 | requestlen += 2; 84 | 85 | const int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 86 | if (fd < 0) { 87 | perror("socket"); 88 | return 1; 89 | } 90 | 91 | struct sockaddr_in sin; 92 | memset(&sin, 0, sizeof(sin)); 93 | sin.sin_family = AF_INET; 94 | sin.sin_addr.s_addr = target_ip; 95 | sin.sin_port = htons(portnum); 96 | 97 | ssize_t n; 98 | do { 99 | n = sendto(fd, request, requestlen, 0, (struct sockaddr *) &sin, sizeof(sin)); 100 | } while (n == -1 && errno == EINTR); 101 | 102 | if (n < 0) { 103 | perror("sendto"); 104 | return 1; 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /forward/forward.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include "dns.h" 20 | #include "ip_parse.h" 21 | #include "dns_random.h" 22 | 23 | // The server's private key 24 | uint8_t global_secret_key[32]; 25 | // An open descriptor to /dev/urandom 26 | int global_urandom_fd = -1; 27 | // The IP address (big-endian) of the backend server 28 | static uint32_t global_target_address; 29 | 30 | static const unsigned TIMEOUT = 5000; // 5 seconds 31 | 32 | // ----------------------------------------------------------------------------- 33 | // Our timeouts are special since they are always for the same amount of time. 34 | // Thus we simply have a double-linked list for timeouts. When transmitting a 35 | // packet we put the txidentry at the head of the timeout queue and we expire 36 | // entries from the tail. When a reply comes back, the double-linked nature of 37 | // the list means that we can remove the element quickly. 38 | // ----------------------------------------------------------------------------- 39 | struct txidentry { 40 | struct txidentry *to_prev, *to_next; // timeout double-linked list 41 | uint64_t tx_time; // transmit time (milliseconds) 42 | int fd; // socket 43 | uint32_t source_ip; 44 | uint16_t source_port; 45 | uint16_t source_txid; 46 | uint16_t target_txid; 47 | 48 | char is_dnscurve; 49 | 50 | // The following are only valid if @is_dnscurve is non-zero 51 | uint8_t public_key[32]; 52 | uint8_t nonce[8]; 53 | uint16_t qnamelen; // length of the client's query name 54 | uint8_t qname[0]; // query name follows directly 55 | }; 56 | 57 | // The head and tail of the timeout queue. 58 | static struct txidentry *global_txid_to_head = NULL; 59 | static struct txidentry *global_txid_to_tail = NULL; 60 | 61 | // ----------------------------------------------------------------------------- 62 | // Append data to a buffer, if it will fit 63 | // 64 | // output: a buffer 65 | // len: the length of @output 66 | // pos: (in/out) the current position in @buffer - updated on exit 67 | // input: the data to be appended 68 | // inlen: the length of @input 69 | // returns: 1 on success, 0 otherwise 70 | // ----------------------------------------------------------------------------- 71 | static int 72 | buffer_append(uint8_t *output, unsigned len, unsigned *pos, 73 | const void *input, unsigned inlen) { 74 | if (*pos + inlen > len) 75 | return 0; 76 | 77 | memcpy(output + *pos, input, inlen); 78 | *pos += inlen; 79 | 80 | return 1; 81 | } 82 | 83 | // ----------------------------------------------------------------------------- 84 | // Return the current mission time in milliseconds 85 | // ----------------------------------------------------------------------------- 86 | static uint64_t 87 | time_now() { 88 | struct timespec ts; 89 | 90 | if (clock_gettime(CLOCK_MONOTONIC, &ts)) { 91 | perror("clock_gettime"); 92 | abort(); // there are no temporary errors with clock_gettime 93 | } 94 | 95 | uint64_t msecs = ts.tv_sec; 96 | msecs *= 1000; 97 | msecs += ts.tv_nsec / 1000000; 98 | 99 | return msecs; 100 | } 101 | 102 | // ----------------------------------------------------------------------------- 103 | // Get a socket with a random port number to transmit on or -1 on error 104 | // ----------------------------------------------------------------------------- 105 | static int 106 | tx_socket_get() { 107 | const int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 108 | if (sock < 0) 109 | return -1; 110 | 111 | struct sockaddr_in sin; 112 | memset(&sin, 0, sizeof(sin)); 113 | sin.sin_family = AF_INET; 114 | 115 | for (unsigned i = 0; i < 10; ++i) { 116 | uint16_t port = 1025 + dns_random(64510); 117 | sin.sin_port = htons(port); 118 | 119 | if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) 120 | return sock; 121 | } 122 | 123 | // Give up and let the kernel pick the port number for us. 124 | return sock; 125 | } 126 | 127 | // ----------------------------------------------------------------------------- 128 | // Expire any txids 129 | // ----------------------------------------------------------------------------- 130 | static void 131 | txids_expire(uint64_t current_time) { 132 | while (global_txid_to_tail) { 133 | struct txidentry *entry = global_txid_to_tail; 134 | if (entry->tx_time + TIMEOUT < current_time) { 135 | if (entry->to_prev) { 136 | entry->to_prev->to_next = NULL; 137 | global_txid_to_tail = entry->to_prev; 138 | } else { 139 | global_txid_to_head = NULL; 140 | global_txid_to_tail = NULL; 141 | } 142 | close(entry->fd); 143 | free(entry); 144 | } else { 145 | break; 146 | } 147 | } 148 | } 149 | 150 | // ----------------------------------------------------------------------------- 151 | // Return the number of milliseconds until the next txid expires, or -1 if 152 | // nothing is inflight. 153 | // ----------------------------------------------------------------------------- 154 | static int 155 | txids_expire_sleep(uint64_t current_time) { 156 | if (!global_txid_to_tail) 157 | return -1; 158 | 159 | if (global_txid_to_tail->tx_time + TIMEOUT < current_time) 160 | return 0; 161 | return (10 + global_txid_to_tail->tx_time + TIMEOUT) - current_time; 162 | } 163 | 164 | // ----------------------------------------------------------------------------- 165 | // Transmit a packet to the server on a new socket. Return the txidentry of the 166 | // new request with @fd valid. 167 | // 168 | // extra: extra bytes to allocate at the end of the returned txidentry 169 | // ----------------------------------------------------------------------------- 170 | static struct txidentry * 171 | dns_transmit(const uint8_t *packet, unsigned len, unsigned extra) { 172 | int sock = tx_socket_get(); 173 | if (sock < 0) 174 | return NULL; 175 | 176 | struct sockaddr_in sin; 177 | memset(&sin, 0, sizeof(sin)); 178 | sin.sin_family = AF_INET; 179 | sin.sin_addr.s_addr = global_target_address; 180 | sin.sin_port = htons(53); 181 | 182 | ssize_t n; 183 | 184 | do { 185 | n = sendto(sock, packet, len, MSG_DONTWAIT, (struct sockaddr *) &sin, sizeof(sin)); 186 | } while (n == -1 && errno == EINTR); 187 | 188 | if (n != len) { 189 | close(sock); 190 | return NULL; 191 | } 192 | 193 | struct txidentry *entry = malloc(sizeof(struct txidentry) + extra); 194 | if (!entry) { 195 | close(sock); 196 | return NULL; 197 | } 198 | entry->fd = sock; 199 | 200 | return entry; 201 | } 202 | 203 | // ----------------------------------------------------------------------------- 204 | // Forward a packet to the backend server 205 | // 206 | // packet: DNS packet 207 | // length: number of bytes in @packet 208 | // efd: epoll file descriptor into which the new socket is added 209 | // sin: source location 210 | // is_dnscurve: true iff the source packet was DNS curve protected 211 | // public_key: (if @is_dnscurve) the client's public key (32 bytes) 212 | // nonce: (if @is_dnscurve) the client's nonce (8 bytes) 213 | // qname: (if @is_dnscurve) the original query string 214 | // qnamelen: (if @is_dnscurve) number of bytes in @qname 215 | // ----------------------------------------------------------------------------- 216 | static void 217 | dns_forward(const uint8_t *packet, unsigned length, int efd, 218 | const struct sockaddr_in *sin, uint16_t txid, 219 | char is_dnscurve, 220 | const uint8_t *public_key, const uint8_t *nonce, 221 | const uint8_t *qname, unsigned qnamelen) { 222 | if (length < 16) 223 | return; // clearly bogus, drop it. 224 | 225 | struct txidentry *entry = dns_transmit(packet, length, is_dnscurve ? qnamelen : 0); 226 | if (!entry) 227 | return; 228 | 229 | entry->is_dnscurve = is_dnscurve; 230 | if (is_dnscurve) { 231 | memcpy(entry->public_key, public_key, 32); 232 | memcpy(entry->nonce, nonce, 8); 233 | entry->qnamelen = qnamelen; 234 | memcpy(entry->qname, qname, qnamelen); 235 | } 236 | 237 | struct epoll_event event; 238 | event.data.ptr = entry; 239 | event.events = EPOLLIN; 240 | 241 | if (epoll_ctl(efd, EPOLL_CTL_ADD, entry->fd, &event)) { 242 | close(entry->fd); 243 | free(entry); 244 | } 245 | 246 | entry->source_port = sin->sin_port; 247 | entry->source_ip = sin->sin_addr.s_addr; 248 | entry->source_txid = txid; 249 | entry->target_txid = *((uint16_t *) packet); 250 | entry->tx_time = time_now(); 251 | 252 | entry->to_prev = NULL; 253 | entry->to_next = global_txid_to_head; 254 | if (!entry->to_next) { 255 | global_txid_to_tail = entry; 256 | } else { 257 | entry->to_next->to_prev = entry; 258 | } 259 | global_txid_to_head = entry; 260 | } 261 | 262 | // ----------------------------------------------------------------------------- 263 | // Pass a reply back to the requestor 264 | // 265 | // packet: the reply from the backend server. 8 free bytes are available preceeding 266 | // this buffer 267 | // length: number of bytes in @packet 268 | // entry: the txidentry for this request 269 | // ----------------------------------------------------------------------------- 270 | static void 271 | dns_reply(uint8_t *packet, unsigned length, struct txidentry *entry) { 272 | if (entry->to_prev) { 273 | entry->to_prev->to_next = entry->to_next; 274 | } else { 275 | global_txid_to_head = entry->to_next; 276 | } 277 | 278 | if (entry->to_next) { 279 | entry->to_next->to_prev = entry->to_prev; 280 | } else { 281 | global_txid_to_tail = entry->to_prev; 282 | } 283 | 284 | struct sockaddr_in sin; 285 | memset(&sin, 0, sizeof(sin)); 286 | sin.sin_family = AF_INET; 287 | sin.sin_addr.s_addr = entry->source_ip; 288 | sin.sin_port = entry->source_port; 289 | 290 | if (!entry->is_dnscurve) { 291 | ssize_t n; 292 | 293 | do { 294 | n = sendto(3, packet, length, MSG_DONTWAIT, 295 | (struct sockaddr *) &sin, sizeof(sin)); 296 | } while (n == -1 && errno == EINTR); 297 | 298 | return; 299 | } 300 | 301 | // client is DNS curve. Need to construct a wrapping 302 | 303 | uint8_t wrapper[4096]; 304 | uint8_t nonce_and_box[4096]; 305 | randombytes(nonce_and_box, 8); 306 | 307 | if (8 + length + crypto_box_curve25519salsa20hmacsha512_AUTHBYTES + 308 | crypto_box_curve25519salsa20hmacsha512_EXTRABYTES > 309 | sizeof(nonce_and_box) - 8) 310 | return; 311 | 312 | memcpy(packet - 8, entry->nonce, 8); 313 | 314 | crypto_box_curve25519salsa20hmacsha512(nonce_and_box + 8, packet - 8, length + 8, 315 | nonce_and_box, entry->public_key, 316 | global_secret_key); 317 | const unsigned payload_length = 318 | length + 8 + 8 + crypto_box_curve25519salsa20hmacsha512_AUTHBYTES; 319 | 320 | unsigned pos = 0; 321 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, &entry->source_txid, 2)) 322 | return; 323 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, 324 | "\x84" // response, opcode 0, authoritative, 325 | // not truncated, recursion not desired 326 | "\x00" // recursion not available, no Z bits, RCODE 0 327 | "\x00\x01" // one question 328 | "\x00\x01" // one answer 329 | "\x00\x00" // no authority 330 | "\x00\x00", // no additional 331 | 10)) 332 | return; 333 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, 334 | entry->qname, entry->qnamelen)) 335 | return; 336 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, 337 | "\x00\x10" // query type TXT 338 | "\x00\x01" // Internet class 339 | "\xc0\x0c" // pointer back to the first qname 340 | "\x00\x10" // TXT reply 341 | "\x00\x01" // Internet class 342 | "\x00\x00\x00\x00", // TTL 0 343 | 14)) 344 | return; 345 | 346 | // The DNS RDATA is a series of charactor strings, which are 8-bit length 347 | // prefixed strings. Thus we need to split the nonce_and_box into parts, at 348 | // most 255 bytes long. 349 | const unsigned rdatalen = payload_length + (payload_length + 254) / 255; 350 | const uint16_t rdatalen_be = htons(rdatalen); 351 | 352 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, &rdatalen_be, 2)) 353 | return; 354 | 355 | unsigned todo = payload_length, i = 0; 356 | while (todo) { 357 | unsigned stringlen = todo; 358 | if (stringlen > 255) stringlen = 255; 359 | const uint8_t strlenbyte = stringlen; 360 | 361 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, &strlenbyte, 1)) 362 | return; 363 | 364 | if (!buffer_append(wrapper, sizeof(wrapper), &pos, nonce_and_box + i, stringlen)) 365 | return; 366 | 367 | todo -= stringlen; 368 | i += stringlen; 369 | } 370 | 371 | ssize_t n; 372 | 373 | do { 374 | n = sendto(3, wrapper, pos, MSG_DONTWAIT, 375 | (struct sockaddr *) &sin, sizeof(sin)); 376 | } while (n == -1 && errno == EINTR); 377 | } 378 | 379 | static int 380 | curve_worker() { 381 | uint8_t buffer[4096]; 382 | uint8_t plaintext[4096]; 383 | unsigned plaintextlen; 384 | 385 | const int efd = epoll_create(32); 386 | if (efd < 0) { 387 | perror("epoll_create"); 388 | return 1; 389 | } 390 | 391 | struct epoll_event curve_event; 392 | curve_event.data.ptr = NULL; 393 | curve_event.events = EPOLLIN; 394 | if (epoll_ctl(efd, EPOLL_CTL_ADD, 3, &curve_event)) { 395 | perror("epoll_ctl"); 396 | return 1; 397 | } 398 | 399 | for (;;) { 400 | struct epoll_event events[8]; 401 | 402 | uint64_t current_time = time_now(); 403 | txids_expire(current_time); 404 | 405 | int r; 406 | do { 407 | r = epoll_wait(efd, events, 8, txids_expire_sleep(current_time)); 408 | } while (r == -1 && errno == EINTR); 409 | 410 | if (r < 0) { 411 | perror("epoll_wait"); 412 | return 1; 413 | } 414 | 415 | struct sockaddr_in sin; 416 | socklen_t sinlen; 417 | ssize_t n; 418 | const uint8_t *qname; 419 | unsigned qnamelen; 420 | uint8_t public_key[32], nonce[8]; 421 | 422 | for (unsigned i = 0; i < r; ++i) { 423 | if (events[i].data.ptr == NULL) { 424 | // This is the world facing, DNS curve, UDP socket 425 | 426 | sinlen = sizeof(sin); 427 | do { 428 | n = recvfrom(3, buffer, sizeof(buffer), MSG_DONTWAIT, 429 | (struct sockaddr *) &sin, &sinlen); 430 | } while (n == -1 && errno == EINTR); 431 | 432 | if (n < 0) { 433 | perror("reading from curve socket"); 434 | continue; 435 | } 436 | 437 | if (n < 2) { 438 | // packet is too short 439 | continue; 440 | } 441 | 442 | const uint16_t txid = *((uint16_t *) buffer); 443 | plaintextlen = sizeof(plaintext); 444 | int cr; 445 | cr = dns_curve_request_parse(plaintext, &plaintextlen, public_key, 446 | nonce, &qname, &qnamelen, buffer, n); 447 | if (cr == 0) { 448 | // not a DNS curve packet. Forward directly 449 | dns_forward(buffer, n, efd, &sin, txid, 0, NULL, NULL, NULL, 0); 450 | } else if (cr == -1) { 451 | // invalid DNS curve packet. Drop 452 | } else { 453 | // valid DNS curve packet, inner packet in plaintext 454 | dns_forward(plaintext, plaintextlen, efd, &sin, txid, 1, public_key, 455 | nonce, qname, qnamelen); 456 | } 457 | } else { 458 | // this is a socket talking to our server 459 | struct txidentry *entry = events[i].data.ptr; 460 | 461 | sinlen = sizeof(sin); 462 | do { 463 | n = recvfrom(entry->fd, buffer + 8, sizeof(buffer) - 8, MSG_DONTWAIT, 464 | (struct sockaddr *) &sin, &sinlen); 465 | } while (n == -1 && errno == EINTR); 466 | 467 | if (n < 0) { 468 | perror("reading from curve socket"); 469 | continue; 470 | } 471 | 472 | if (sin.sin_addr.s_addr != global_target_address || 473 | sin.sin_port != htons(53) || 474 | n < 2 || 475 | *((uint16_t *) (buffer + 8)) != entry->target_txid) 476 | continue; // bogus packet 477 | 478 | dns_reply(buffer + 8, n, entry); 479 | 480 | close(entry->fd); 481 | free(entry); 482 | } 483 | } 484 | } 485 | 486 | return 1; 487 | } 488 | 489 | static int 490 | hex_char(uint8_t *out, char in) { 491 | if (in >= '0' && in <= '9') { 492 | *out = in - '0'; 493 | return 1; 494 | } else if (in >= 'a' && in <= 'f') { 495 | *out = 10 + (in - 'a'); 496 | return 1; 497 | } else if (in >= 'A' && in <= 'F') { 498 | *out = 10 + (in - 'A'); 499 | return 1; 500 | } else { 501 | return 0; 502 | } 503 | } 504 | 505 | static int 506 | hex_decode(uint8_t *dest, const char *src) { 507 | while (*src) { 508 | uint8_t v1, v2; 509 | if (!hex_char(&v1, *src++)) 510 | return 0; 511 | if (!hex_char(&v2, *src++)) 512 | return 0; 513 | 514 | *dest++ = (v1 << 4) | v2; 515 | } 516 | 517 | return 1; 518 | } 519 | 520 | static int 521 | usage(const char *argv0) { 522 | fprintf(stderr, "Usage: %s \n", argv0); 523 | return 1; 524 | } 525 | 526 | int 527 | main(int argc, char **argv) { 528 | if (argc != 2) return usage(argv[0]); 529 | 530 | if (!ip_parse(&global_target_address, argv[1])) 531 | return usage(argv[0]); 532 | 533 | global_urandom_fd = open("/dev/urandom", O_RDONLY); 534 | if (global_urandom_fd < 0) { 535 | perror("Opening /dev/urandom"); 536 | return 1; 537 | } 538 | 539 | dns_random_init(); 540 | 541 | if (!getenv("DNSCURVE_PRIVATE_KEY")) { 542 | fprintf(stderr, "$DNSCURVE_PRIVATE_KEY must be set\n"); 543 | return 1; 544 | } 545 | 546 | if (strlen(getenv("DNSCURVE_PRIVATE_KEY")) != 64) { 547 | fprintf(stderr, "$DNSCURVE_PRIVATE_KEY must 64 bytes long\n"); 548 | return 1; 549 | } 550 | 551 | if (!hex_decode(global_secret_key, getenv("DNSCURVE_PRIVATE_KEY"))) { 552 | fprintf(stderr, "$DNSCURVE_PRIVATE_KEY invalid\n"); 553 | return 1; 554 | } 555 | 556 | global_secret_key[0] &= 248; 557 | global_secret_key[31] &= 127; 558 | global_secret_key[31] |= 64; 559 | 560 | return curve_worker(); 561 | } 562 | -------------------------------------------------------------------------------- /forward/ip_parse.c: -------------------------------------------------------------------------------- 1 | #define _BSD_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | ip_parse(uint32_t *out, const char *in) { 9 | struct in_addr addr; 10 | 11 | if (!inet_aton(in, &addr)) { 12 | return 0; 13 | } else { 14 | *out = addr.s_addr; 15 | return 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /forward/ip_parse.h: -------------------------------------------------------------------------------- 1 | #ifndef IP_PARSE_H 2 | #define IP_PARSE_H 3 | 4 | int ip_parse(uint32_t *out, const char *in); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /forward/randombytes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern int global_urandom_fd; 7 | 8 | void 9 | randombytes(unsigned char *x, unsigned long long xlen) { 10 | int i; 11 | 12 | while (xlen > 0) { 13 | if (xlen < 1048576) i = xlen; else i = 1048576; 14 | 15 | i = read(global_urandom_fd, x, i); 16 | if (i < 1) { 17 | sleep(1); 18 | continue; 19 | } 20 | 21 | x += i; 22 | xlen -= i; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /forward/udpserver.c: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // udpserver: start a child process with a UDP socket bound on fd 3 3 | // 4 | // % udpserver 0.0.0.0 53 my-dns-server 5 | // 6 | // Since binding to ports < 1024 is a priviledged operation, it's good to 7 | // separate it from the process that will end up using the socket in question. 8 | // Thus a pipeline like: 9 | // 10 | // % udpserver 0.0.0.0 53 setuidgid nonroot my-dns-server 11 | // 12 | // Can be used to ensure that my-dns-server doesn't need root to run. 13 | // 14 | // The child process must expect the UDP socket to be installed on fd 3. 15 | // ----------------------------------------------------------------------------- 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "ip_parse.h" 27 | 28 | static int 29 | usage(const char *argv0) { 30 | fprintf(stderr, "Usage: %s \n", 31 | argv0); 32 | return 1; 33 | } 34 | 35 | int 36 | main(int argc, char **argv) { 37 | if (argc < 4) 38 | return usage(argv[0]); 39 | 40 | uint32_t bind_ip; 41 | if (!ip_parse(&bind_ip, argv[1])) 42 | return usage(argv[0]); 43 | 44 | char *endptr; 45 | unsigned long port = strtoul(argv[2], &endptr, 10); 46 | if (*endptr) 47 | return usage(argv[0]); 48 | 49 | if (port == 0 || port > 65535) { 50 | fprintf(stderr, "Port number out of range (1..65535)\n"); 51 | return 1; 52 | } 53 | 54 | const int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 55 | if (sock < 0) { 56 | perror("socket"); 57 | return 1; 58 | } 59 | 60 | struct sockaddr_in sin; 61 | memset(&sin, 0, sizeof(sin)); 62 | sin.sin_family = AF_INET; 63 | sin.sin_addr.s_addr = bind_ip; 64 | sin.sin_port = htons(port); 65 | 66 | int n; 67 | do { 68 | n = bind(sock, (struct sockaddr *) &sin, sizeof(sin)); 69 | if (n) { 70 | if (errno == EADDRINUSE || errno == ENOMEM) { 71 | sleep(1); 72 | continue; 73 | } 74 | perror("bind"); 75 | return 1; 76 | } 77 | } while (n); 78 | 79 | if (sock != 3) { 80 | dup2(sock, 3); 81 | close(sock); 82 | } 83 | 84 | execvp(argv[3], &argv[3]); 85 | perror("execvp"); 86 | 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /nacl-python.patch: -------------------------------------------------------------------------------- 1 | Index: nacl-20080914/cpucycles/do 2 | =================================================================== 3 | --- nacl-20080914.orig/cpucycles/do 2008-09-14 12:42:13.000000000 -0700 4 | +++ nacl-20080914/cpucycles/do 2008-09-18 15:33:22.000000000 -0700 5 | @@ -38,6 +38,7 @@ 6 | ./test || continue 7 | echo "=== `date` === Success. Using $n.c." >&2 8 | mkdir -p lib/$abi 9 | + mkdir -p lib/$abi-pic 10 | mv cpucycles-impl.o lib/$abi/cpucycles.o 11 | mkdir -p include/$abi 12 | mv cpucycles-impl.h include/$abi/cpucycles.h 13 | Index: nacl-20080914/do 14 | =================================================================== 15 | --- nacl-20080914.orig/do 2008-09-14 12:42:13.000000000 -0700 16 | +++ nacl-20080914/do 2008-09-18 15:41:57.000000000 -0700 17 | @@ -139,6 +139,7 @@ 18 | rm -rf "$work" 19 | mkdir -p "$work" 20 | mkdir -p "$work/best" 21 | + mkdir -p "$work/best-pic" 22 | 23 | # for each operation primitive abi, loop over implementations 24 | find "$o/$p" -follow -name "api.h" \ 25 | @@ -259,8 +260,23 @@ 26 | && cp -p "$op.h" "../$op.h" \ 27 | && cp -p "$o.h" "../$o.h" \ 28 | && cp -p measure ../best/measure \ 29 | + && ok=1 \ 30 | + && for f in $cfiles $sfiles 31 | + do 32 | + $compiler -fPIC \ 33 | + -I. -I"$include" -I"$include/$abi" \ 34 | + -c "$f" >../errors 2>&1 \ 35 | + || ok=0 36 | + done \ 37 | + && [ "$ok" = 1 ] \ 38 | + && rm -f ../best-pic/*.o \ 39 | + && for f in *.o 40 | + do 41 | + cp -p "$f" "../best-pic/${opi}-$f" 42 | + done \ 43 | || : 44 | done 45 | + 46 | ) 47 | done 48 | 49 | @@ -273,6 +289,11 @@ 50 | && [ -f "$o/$p/selected" ] \ 51 | && cp -p "$work/$o.h" "$include/$abi/$o.h" \ 52 | || : 53 | + 54 | + # Build shared libraries 55 | + cp -p "$work/best-pic/"*.o "$lib/$abi-pic" \ 56 | + && linking_cc=$("$bin/okc-$abi" | head -n 1) \ 57 | + && $linking_cc -o "$lib/$abi-pic/libnacl.so" -shared "$lib/$abi-pic"/*.o 58 | done 59 | done 60 | done 61 | Index: nacl-20080914/crypto_smult/curve25519/donna/smult.c 62 | =================================================================== 63 | --- nacl-20080914.orig/crypto_smult/curve25519/donna/smult.c 2008-09-14 12:42:13.000000000 -0700 64 | +++ nacl-20080914/crypto_smult/curve25519/donna/smult.c 2008-09-18 15:33:22.000000000 -0700 65 | @@ -77,7 +77,7 @@ 66 | * xprime zprime: short form, destroyed 67 | * qmqp: short form, preserved 68 | */ 69 | -void 70 | +void __attribute__((visibility ("hidden"))) 71 | fmonty(felem *x2, /* output 2Q */ 72 | felem *x3, /* output Q + Q' */ 73 | felem *x, /* input Q */ 74 | Index: nacl-20080914/bindings/python/generate.sh 75 | =================================================================== 76 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 77 | +++ nacl-20080914/bindings/python/generate.sh 2008-09-18 16:04:17.000000000 -0700 78 | @@ -0,0 +1,11 @@ 79 | +echo -n > methods.h 80 | +echo -n > includes.h 81 | + 82 | +for family in hash auth auth1 stream secretbox smult box; do 83 | + for x in `ls -1 /usr/include/nacl/crypto_${family}_*.h`; do 84 | + func=$(basename $x | sed -e "s/crypto_$family\([_a-zA-Z0-9]*\).h/\1/") 85 | + func=${func:1} 86 | + echo "#include " >> includes.h 87 | + echo "function_${family}($func)" >> methods.h 88 | + done 89 | +done 90 | Index: nacl-20080914/bindings/python/nacl.c 91 | =================================================================== 92 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 93 | +++ nacl-20080914/bindings/python/nacl.c 2008-09-18 16:23:28.000000000 -0700 94 | @@ -0,0 +1,159 @@ 95 | +#include 96 | + 97 | +#include 98 | +#include 99 | +#include 100 | + 101 | +#include 102 | + 103 | +#include 104 | +#include 105 | + 106 | +#include "includes.h" 107 | +#include "templates.h" 108 | + 109 | +#include 110 | +//#include 111 | +//#include 112 | +#include 113 | +#include 114 | + 115 | +typedef uint8_t u8; 116 | + 117 | +int global_urandom_fd; 118 | + 119 | +void 120 | +randombytes(unsigned char *x, unsigned long long xlen) { 121 | + int i; 122 | + 123 | + while (xlen > 0) { 124 | + if (xlen < 1048576) i = xlen; else i = 1048576; 125 | + 126 | + i = read(global_urandom_fd, x, i); 127 | + if (i < 1) { 128 | + sleep(1); 129 | + continue; 130 | + } 131 | + 132 | + x += i; 133 | + xlen -= i; 134 | + } 135 | +} 136 | + 137 | +static void __attribute__((constructor)) 138 | +randombytes_init() { 139 | + global_urandom_fd = open("/dev/urandom", O_RDONLY); 140 | + if (global_urandom_fd < 0) { 141 | + perror("opening /dev/urandom"); 142 | + abort(); 143 | + } 144 | +} 145 | + 146 | +static PyObject * 147 | +nacl_verify_16(PyObject *self, PyObject *args) { 148 | + PyStringObject *sa, *sb; 149 | + if (!PyArg_ParseTuple(args, "SS", &sa, &sb)) return NULL; 150 | + 151 | + if (PyString_Size((PyObject *) sa) != 16 || 152 | + PyString_Size((PyObject *) sb) != 16) { 153 | + PyErr_SetString(PyExc_ValueError, 154 | + "Both arguments to verify16 must be 16 bytes long"); 155 | + return NULL; 156 | + } 157 | + 158 | + const char *a = PyString_AS_STRING(sa); 159 | + const char *b = PyString_AS_STRING(sb); 160 | + 161 | + if (!crypto_verify_16((u8 *) a, (u8 *) b)) { 162 | + Py_RETURN_TRUE; 163 | + } else { 164 | + Py_RETURN_FALSE; 165 | + } 166 | +} 167 | + 168 | +static PyObject * 169 | +nacl_verify_32(PyObject *self, PyObject *args) { 170 | + PyStringObject *sa, *sb; 171 | + if (!PyArg_ParseTuple(args, "SS", &sa, &sb)) return NULL; 172 | + 173 | + if (PyString_Size((PyObject *) sa) != 32 || 174 | + PyString_Size((PyObject *) sb) != 32) { 175 | + PyErr_SetString(PyExc_ValueError, 176 | + "Both arguments to verify32 must be 32 bytes long"); 177 | + return NULL; 178 | + } 179 | + 180 | + const char *a = PyString_AS_STRING(sa); 181 | + const char *b = PyString_AS_STRING(sb); 182 | + 183 | + if (!crypto_verify_32((u8 *) a, (u8 *) b)) { 184 | + Py_RETURN_TRUE; 185 | + } else { 186 | + Py_RETURN_FALSE; 187 | + } 188 | +} 189 | + 190 | +#define function_auth1(x) // not wrapped yet 191 | + 192 | +#define function_hash(x) HASHFUNC(_##x) 193 | +#define function_auth(x) AUTHFUNC(,_##x) 194 | +#define function_onetimeauth(x) AUTHFUNC(onetime,_##x) 195 | +#define function_stream(x) STREAMXORFUNC(_##x) 196 | +#define function_secretbox(x) SECRETBOXFUNC(_##x) 197 | +#define function_smult(x) SMULTFUNC(_##x) 198 | +#define function_box(x) BOXFUNC(_##x) 199 | +#include "methods.h" 200 | +#undef function_box 201 | +#undef function_smult 202 | +#undef function_secretbox 203 | +#undef function_stream 204 | +#undef function_onetimeauth 205 | +#undef function_auth 206 | +#undef function_hash 207 | + 208 | +// Default implementations 209 | +HASHFUNC() 210 | +//AUTHFUNC(,) 211 | +//AUTHFUNC(onetime,) 212 | +STREAMXORFUNC() 213 | + 214 | +static PyMethodDef NaClMethods[] = { 215 | + {"verify16", nacl_verify_16, METH_VARARGS, "Verify two 16-byte strings are equal"}, 216 | + {"verify32", nacl_verify_32, METH_VARARGS, "Verify two 32-byte strings are equal"}, 217 | +#define function_hash(x) \ 218 | + {"hash_" #x, nacl_hash_##x, METH_VARARGS, "Hash a string with " #x}, 219 | +#define function_auth(x) \ 220 | + {"auth_" #x, nacl_auth_##x, METH_VARARGS, "Authenticate a string with " #x}, 221 | +#define function_onetimeauth(x) \ 222 | + {"onetimeauth_" #x, nacl_onetimeauth_##x, METH_VARARGS, "Authenticate a string with " #x}, 223 | +#define function_stream(x) \ 224 | + {"stream_" #x "_xor", nacl_stream_##x##_xor, METH_VARARGS, "Encrypt a string with " #x}, 225 | +#define function_secretbox(x) \ 226 | + {"secretbox_" #x, nacl_secretbox_##x, METH_VARARGS, "Protect a string with " #x}, 227 | +#define function_smult(x) \ 228 | + {"smult_" #x, nacl_smult_##x, METH_VARARGS, "Scalar multiplication with " #x}, \ 229 | + {"smult_" #x "_base", nacl_smult_##x##_base, METH_VARARGS, "Scalar multiplication with " #x}, 230 | +#define function_box(x) \ 231 | + {"box_" #x, nacl_box_##x, METH_VARARGS, "Build a cryptographic box using " #x}, \ 232 | + {"box_" #x "_open", nacl_box_##x##_open, METH_VARARGS, "Open a cryptographic box using " #x}, \ 233 | + {"box_" #x "_keypair", nacl_box_##x##_keypair, METH_VARARGS, "Generate a public/private keypair " #x}, 234 | +#include "methods.h" 235 | +#undef function_box 236 | +#undef function_smult 237 | +#undef function_secretbox 238 | +#undef function_stream 239 | +#undef function_onetimeauth 240 | +#undef function_auth 241 | +#undef function_hash 242 | + {"hash", nacl_hash, METH_VARARGS, "Hash a string"}, 243 | + //{"auth", nacl_auth, METH_VARARGS, "Authenticate a string"}, 244 | + //{"onetimeauth", nacl_onetimeauth, METH_VARARGS, "Authenticate a string"}, 245 | + {"stream_xor", nacl_stream_xor, METH_VARARGS, "Encrypt a string"}, 246 | + 247 | + {NULL, NULL, 0, NULL} 248 | +}; 249 | + 250 | +PyMODINIT_FUNC 251 | +initnacl(void) { 252 | + (void) Py_InitModule("nacl", NaClMethods); 253 | +} 254 | Index: nacl-20080914/bindings/python/setup.py 255 | =================================================================== 256 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 257 | +++ nacl-20080914/bindings/python/setup.py 2008-09-18 15:33:22.000000000 -0700 258 | @@ -0,0 +1,10 @@ 259 | +from distutils.core import setup, Extension 260 | + 261 | +naclmod = Extension('nacl', 262 | + sources = ['nacl.c'], 263 | + libraries = ['nacl']) 264 | + 265 | +setup (name = 'NaCl', 266 | + version = '0.1', 267 | + description = 'A wrapping of the NaCl crypto library', 268 | + ext_modules = [naclmod]) 269 | Index: nacl-20080914/bindings/python/templates.h 270 | =================================================================== 271 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 272 | +++ nacl-20080914/bindings/python/templates.h 2008-09-18 16:22:23.000000000 -0700 273 | @@ -0,0 +1,337 @@ 274 | +#ifndef NACL_PY_TEMPLATES_H 275 | +#define NACL_PY_TEMPLATES_H 276 | + 277 | +#define HASHFUNC(x) \ 278 | +static PyObject * \ 279 | +nacl_hash##x(PyObject *self, PyObject *args) { \ 280 | + PyStringObject *a; \ 281 | + u8 digest[crypto_hash##x##_BYTES]; \ 282 | +\ 283 | + if (!PyArg_ParseTuple(args, "S", &a)) return NULL; \ 284 | + const unsigned long long a_len = PyString_Size((PyObject *) a); \ 285 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 286 | +\ 287 | + crypto_hash##x(digest, (const u8 *) abytes, a_len); \ 288 | + return PyString_FromStringAndSize((const char *) digest, sizeof(digest)); \ 289 | +} 290 | + 291 | +#define AUTHFUNC(type, x) \ 292 | +static PyObject * \ 293 | +nacl_##type##auth##x(PyObject *self, PyObject *args) { \ 294 | + PyStringObject *a, *key; \ 295 | + u8 digest[crypto_##type##auth##x##_BYTES]; \ 296 | + \ 297 | + if (!PyArg_ParseTuple(args, "SS", &a, &key)) return NULL; \ 298 | + \ 299 | + if (PyString_Size((PyObject *) key) != crypto_##type##auth##x##_KEYBYTES) { \ 300 | + PyErr_Format(PyExc_ValueError, \ 301 | + "Key must be %d bytes long", \ 302 | + crypto_##type##auth##x##_KEYBYTES); \ 303 | + return NULL; \ 304 | + } \ 305 | + \ 306 | + const char *keybytes = PyString_AS_STRING((PyObject *) key); \ 307 | + const unsigned long long a_len = PyString_Size((PyObject *) a); \ 308 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 309 | + \ 310 | + crypto_##type##auth##x(digest, (const u8 *) abytes, a_len, (u8 *) keybytes); \ 311 | + return PyString_FromStringAndSize((const char *) digest, sizeof(digest)); \ 312 | +} 313 | + 314 | +#define STREAMXORFUNC(x) \ 315 | +static PyObject * \ 316 | +nacl_stream##x##_xor(PyObject *self, PyObject *args) { \ 317 | + PyStringObject *a, *key, *nonce; \ 318 | + u8 *output; \ 319 | +\ 320 | + if (!PyArg_ParseTuple(args, "SSS", &a, &nonce, &key)) return NULL; \ 321 | +\ 322 | + if (PyString_Size((PyObject *) key) != crypto_stream##x##_KEYBYTES) { \ 323 | + PyErr_Format(PyExc_ValueError, \ 324 | + "Key must be %d bytes long", \ 325 | + crypto_stream##x##_KEYBYTES); \ 326 | + return NULL; \ 327 | + } \ 328 | +\ 329 | + if (PyString_Size((PyObject *) nonce) != crypto_stream##x##_NONCEBYTES) { \ 330 | + PyErr_Format(PyExc_ValueError, \ 331 | + "Nonce must be %d bytes long", \ 332 | + crypto_stream##x##_NONCEBYTES); \ 333 | + return NULL; \ 334 | + } \ 335 | +\ 336 | + const char *k = PyString_AS_STRING(key); \ 337 | + const char *n = PyString_AS_STRING(nonce); \ 338 | + const unsigned long long a_len = PyString_Size((PyObject *) a); \ 339 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 340 | +\ 341 | + if (posix_memalign((void **) &output, 16, a_len)) { \ 342 | + PyErr_NoMemory(); \ 343 | + return NULL; \ 344 | + } \ 345 | +\ 346 | + crypto_stream##x##_xor(output, (const u8 *) abytes, a_len, (const u8 *) n, \ 347 | + (const u8 *) k); \ 348 | + PyObject *ret = PyString_FromStringAndSize((const char *) output, a_len); \ 349 | + free(output); \ 350 | + return ret; \ 351 | +} 352 | + 353 | +#define SECRETBOXFUNC(x) \ 354 | +static PyObject * \ 355 | +nacl_secretbox##x(PyObject *self, PyObject *args) { \ 356 | + PyStringObject *a, *key, *nonce; \ 357 | + u8 *output, *input; \ 358 | +\ 359 | + if (!PyArg_ParseTuple(args, "SSS", &a, &nonce, &key)) return NULL; \ 360 | +\ 361 | + if (PyString_Size((PyObject *) key) != crypto_secretbox##x##_KEYBYTES) { \ 362 | + PyErr_Format(PyExc_ValueError, \ 363 | + "Key must be %d bytes long", \ 364 | + crypto_secretbox##x##_KEYBYTES); \ 365 | + return NULL; \ 366 | + } \ 367 | +\ 368 | + if (PyString_Size((PyObject *) nonce) != crypto_secretbox##x##_NONCEBYTES) { \ 369 | + PyErr_Format(PyExc_ValueError, \ 370 | + "Nonce must be %d bytes long", \ 371 | + crypto_secretbox##x##_NONCEBYTES); \ 372 | + return NULL; \ 373 | + } \ 374 | +\ 375 | + const char *k = PyString_AS_STRING(key); \ 376 | + const char *n = PyString_AS_STRING(nonce); \ 377 | + const unsigned long long a_len = PyString_Size((PyObject *) a); \ 378 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 379 | +\ 380 | + if (posix_memalign((void **) &output, 16, a_len + \ 381 | + crypto_secretbox##x##_ZEROBYTES)) { \ 382 | + PyErr_NoMemory(); \ 383 | + return NULL; \ 384 | + } \ 385 | +\ 386 | + if (posix_memalign((void **) &input, 16, a_len + \ 387 | + crypto_secretbox##x##_ZEROBYTES)) { \ 388 | + free(output); \ 389 | + PyErr_NoMemory(); \ 390 | + return NULL; \ 391 | + } \ 392 | + memcpy(input + crypto_secretbox##x##_ZEROBYTES, abytes, a_len); \ 393 | + memset(input, 0, crypto_secretbox##x##_ZEROBYTES); \ 394 | +\ 395 | + crypto_secretbox##x(output, input, a_len + crypto_secretbox##x##_ZEROBYTES, \ 396 | + (const u8 *) n, (const u8 *) k); \ 397 | + free(input); \ 398 | + PyObject *ret = \ 399 | + PyString_FromStringAndSize((const char *) output + crypto_secretbox##x##_BOXZEROBYTES, \ 400 | + a_len + crypto_secretbox##x##_ZEROBYTES - crypto_secretbox##x##_BOXZEROBYTES); \ 401 | + free(output); \ 402 | + return ret; \ 403 | +} 404 | + 405 | +#define SMULTFUNC(x) \ 406 | +static PyObject * \ 407 | +nacl_smult##x(PyObject *self, PyObject *args) { \ 408 | + PyStringObject *a, *b; \ 409 | + \ 410 | + if (!PyArg_ParseTuple(args, "SS", &a, &b)) return NULL; \ 411 | + \ 412 | + if (PyString_Size((PyObject *) a) != crypto_smult##x##_SCALARBYTES) { \ 413 | + PyErr_Format(PyExc_ValueError, \ 414 | + "Scalar value must be %d bytes long", \ 415 | + crypto_smult##x##_SCALARBYTES); \ 416 | + return NULL; \ 417 | + } \ 418 | + \ 419 | + if (PyString_Size((PyObject *) b) != crypto_smult##x##_BYTES) { \ 420 | + PyErr_Format(PyExc_ValueError, \ 421 | + "Group element must be %d bytes long", \ 422 | + crypto_smult##x##_BYTES); \ 423 | + return NULL; \ 424 | + } \ 425 | + \ 426 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 427 | + const char *bbytes = PyString_AS_STRING((PyObject *) b); \ 428 | + unsigned char result[crypto_smult##x##_BYTES]; \ 429 | + \ 430 | + crypto_smult##x(result, (const u8 *) abytes, (const u8 *) bbytes); \ 431 | + PyObject *ret = PyString_FromStringAndSize((const char *) result, \ 432 | + crypto_smult##x##_BYTES); \ 433 | + \ 434 | + return ret; \ 435 | +} \ 436 | +\ 437 | +static PyObject * \ 438 | +nacl_smult##x##_base(PyObject *self, PyObject *args) { \ 439 | + PyStringObject *a; \ 440 | + \ 441 | + if (!PyArg_ParseTuple(args, "S", &a)) return NULL; \ 442 | + \ 443 | + if (PyString_Size((PyObject *) a) != crypto_smult##x##_SCALARBYTES) { \ 444 | + PyErr_Format(PyExc_ValueError, \ 445 | + "Scalar value must be %d bytes long", \ 446 | + crypto_smult##x##_SCALARBYTES); \ 447 | + return NULL; \ 448 | + } \ 449 | + \ 450 | + const char *abytes = PyString_AS_STRING((PyObject *) a); \ 451 | + unsigned char result[crypto_smult##x##_BYTES]; \ 452 | + \ 453 | + crypto_smult##x##_base(result, (const u8 *) abytes); \ 454 | + PyObject *ret = PyString_FromStringAndSize((const char *) result, \ 455 | + crypto_smult##x##_BYTES); \ 456 | + \ 457 | + return ret; \ 458 | +} 459 | + 460 | +#define BOXFUNC(x) \ 461 | +static PyObject * \ 462 | +nacl_box##x##_keypair(PyObject *self, PyObject *args) { \ 463 | + if (!PyArg_ParseTuple(args, "")) return NULL; \ 464 | +\ 465 | + uint8_t pk[crypto_box##x##_PUBLICKEYBYTES]; \ 466 | + uint8_t sk[crypto_box##x##_PUBLICKEYBYTES]; \ 467 | +\ 468 | + crypto_box##x##_keypair(pk, sk); \ 469 | +\ 470 | + PyObject *a = PyString_FromStringAndSize((const char *) pk, sizeof(pk)); \ 471 | + if (!a) \ 472 | + return NULL; \ 473 | + PyObject *b = PyString_FromStringAndSize((const char *) sk, sizeof(sk)); \ 474 | + if (!b) { \ 475 | + Py_DECREF(a); \ 476 | + return NULL; \ 477 | + } \ 478 | +\ 479 | + return PyTuple_Pack(2, a, b); \ 480 | +} \ 481 | +\ 482 | +static PyObject * \ 483 | +nacl_box##x(PyObject *self, PyObject *args) { \ 484 | + PyStringObject *m, *nonce, *pk, *sk; \ 485 | +\ 486 | + if (!PyArg_ParseTuple(args, "SSSS", &m, &nonce, &pk, &sk)) return NULL; \ 487 | +\ 488 | + if (PyString_Size((PyObject *) pk) != crypto_box##x##_PUBLICKEYBYTES) { \ 489 | + PyErr_Format(PyExc_ValueError, \ 490 | + "Public key value must be %d bytes long", \ 491 | + crypto_box##x##_PUBLICKEYBYTES); \ 492 | + return NULL; \ 493 | + } \ 494 | +\ 495 | + if (PyString_Size((PyObject *) sk) != crypto_box##x##_SECRETKEYBYTES) { \ 496 | + PyErr_Format(PyExc_ValueError, \ 497 | + "Secret key value must be %d bytes long", \ 498 | + crypto_box##x##_SECRETKEYBYTES); \ 499 | + return NULL; \ 500 | + } \ 501 | +\ 502 | + if (PyString_Size((PyObject *) nonce) != crypto_box##x##_NONCEBYTES) { \ 503 | + PyErr_Format(PyExc_ValueError, \ 504 | + "Nonce value must be %d bytes long", \ 505 | + crypto_box##x##_NONCEBYTES); \ 506 | + return NULL; \ 507 | + } \ 508 | +\ 509 | + const char *pkbytes = PyString_AS_STRING(pk); \ 510 | + const char *skbytes = PyString_AS_STRING(sk); \ 511 | + const char *noncebytes = PyString_AS_STRING(nonce); \ 512 | + const unsigned long long m_len = PyString_Size((PyObject *) m); \ 513 | + const char *mbytes = PyString_AS_STRING((PyObject *) m); \ 514 | +\ 515 | + u8 *output, *input; \ 516 | +\ 517 | + if (posix_memalign((void **) &output, 16, \ 518 | + m_len + crypto_box##x##_ZEROBYTES)) { \ 519 | + PyErr_NoMemory(); \ 520 | + return NULL; \ 521 | + } \ 522 | +\ 523 | + if (posix_memalign((void **) &input, 16, \ 524 | + m_len + crypto_box##x##_ZEROBYTES)) { \ 525 | + free(output); \ 526 | + PyErr_NoMemory(); \ 527 | + return NULL; \ 528 | + } \ 529 | + memcpy(input + crypto_box##x##_ZEROBYTES, mbytes, m_len); \ 530 | + memset(input, 0, crypto_box##x##_ZEROBYTES); \ 531 | +\ 532 | + crypto_box##x(output, input, m_len + crypto_box##x##_ZEROBYTES, (uint8_t *) noncebytes, \ 533 | + (uint8_t *) pkbytes, (uint8_t *) skbytes); \ 534 | + free(input); \ 535 | +\ 536 | + PyObject *ret = \ 537 | + PyString_FromStringAndSize((const char *) output + crypto_box##x##_BOXZEROBYTES, \ 538 | + m_len + crypto_box##x##_ZEROBYTES - crypto_box##x##_BOXZEROBYTES); \ 539 | + free(output); \ 540 | + return ret; \ 541 | +} \ 542 | +\ 543 | +static PyObject * \ 544 | +nacl_box##x##_open(PyObject *self, PyObject *args) { \ 545 | + PyStringObject *m, *nonce, *pk, *sk; \ 546 | +\ 547 | + if (!PyArg_ParseTuple(args, "SSSS", &m, &nonce, &pk, &sk)) return NULL; \ 548 | +\ 549 | + if (PyString_Size((PyObject *) pk) != crypto_box##x##_PUBLICKEYBYTES) { \ 550 | + PyErr_Format(PyExc_ValueError, \ 551 | + "Public key value must be %d bytes long", \ 552 | + crypto_box##x##_PUBLICKEYBYTES); \ 553 | + return NULL; \ 554 | + } \ 555 | +\ 556 | + if (PyString_Size((PyObject *) sk) != crypto_box##x##_SECRETKEYBYTES) { \ 557 | + PyErr_Format(PyExc_ValueError, \ 558 | + "Secret key value must be %d bytes long", \ 559 | + crypto_box##x##_SECRETKEYBYTES); \ 560 | + return NULL; \ 561 | + } \ 562 | +\ 563 | + if (PyString_Size((PyObject *) nonce) != crypto_box##x##_NONCEBYTES) { \ 564 | + PyErr_Format(PyExc_ValueError, \ 565 | + "Nonce value must be %d bytes long", \ 566 | + crypto_box##x##_NONCEBYTES); \ 567 | + return NULL; \ 568 | + } \ 569 | +\ 570 | + const char *pkbytes = PyString_AS_STRING(pk); \ 571 | + const char *skbytes = PyString_AS_STRING(sk); \ 572 | + const char *noncebytes = PyString_AS_STRING(nonce); \ 573 | + const unsigned long long m_len = PyString_Size((PyObject *) m); \ 574 | + const char *mbytes = PyString_AS_STRING((PyObject *) m); \ 575 | +\ 576 | + u8 *output, *input; \ 577 | +\ 578 | + if (posix_memalign((void **) &output, 16, \ 579 | + m_len + crypto_box##x##_BOXZEROBYTES)) { \ 580 | + PyErr_NoMemory(); \ 581 | + return NULL; \ 582 | + } \ 583 | +\ 584 | + if (posix_memalign((void **) &input, 16, \ 585 | + m_len + crypto_box##x##_BOXZEROBYTES)) { \ 586 | + free(output); \ 587 | + PyErr_NoMemory(); \ 588 | + return NULL; \ 589 | + } \ 590 | + memcpy(input + crypto_box##x##_BOXZEROBYTES, mbytes, m_len); \ 591 | + memset(input, 0, crypto_box##x##_BOXZEROBYTES); \ 592 | +\ 593 | + if (crypto_box##x##_open(output, input, m_len + crypto_box##x##_BOXZEROBYTES, \ 594 | + (uint8_t *) noncebytes, \ 595 | + (uint8_t *) pkbytes, (uint8_t *) skbytes) == -1) { \ 596 | + free(output); \ 597 | + free(input); \ 598 | + PyErr_Format(PyExc_ValueError, "Box contents corrupt"); \ 599 | + return NULL; \ 600 | + }\ 601 | + free(input); \ 602 | +\ 603 | + PyObject *ret = \ 604 | + PyString_FromStringAndSize((const char *) output + crypto_box##x##_ZEROBYTES, \ 605 | + m_len + crypto_box##x##_BOXZEROBYTES - crypto_box##x##_ZEROBYTES); \ 606 | + free(output); \ 607 | + return ret; \ 608 | +} 609 | + 610 | +#endif // NACL_PY_TEMPLATES_H 611 | Index: nacl-20080914/crypto_auth1/poly1305/amd64/constants.s 612 | =================================================================== 613 | --- nacl-20080914.orig/crypto_auth1/poly1305/amd64/constants.s 2008-09-18 15:54:57.000000000 -0700 614 | +++ nacl-20080914/crypto_auth1/poly1305/amd64/constants.s 2008-09-18 15:57:47.000000000 -0700 615 | @@ -27,6 +27,27 @@ 616 | .globl crypto_auth1_poly1305_amd64_hoffset3 617 | .globl crypto_auth1_poly1305_amd64_rounding 618 | 619 | +.hidden _crypto_auth1_poly1305_amd64_constants 620 | +.hidden crypto_auth1_poly1305_amd64_constants 621 | +.hidden crypto_auth1_poly1305_amd64_scale 622 | +.hidden crypto_auth1_poly1305_amd64_two32 623 | +.hidden crypto_auth1_poly1305_amd64_two64 624 | +.hidden crypto_auth1_poly1305_amd64_two96 625 | +.hidden crypto_auth1_poly1305_amd64_alpha32 626 | +.hidden crypto_auth1_poly1305_amd64_alpha64 627 | +.hidden crypto_auth1_poly1305_amd64_alpha96 628 | +.hidden crypto_auth1_poly1305_amd64_alpha130 629 | +.hidden crypto_auth1_poly1305_amd64_doffset0 630 | +.hidden crypto_auth1_poly1305_amd64_doffset1 631 | +.hidden crypto_auth1_poly1305_amd64_doffset2 632 | +.hidden crypto_auth1_poly1305_amd64_doffset3 633 | +.hidden crypto_auth1_poly1305_amd64_doffset3minustwo128 634 | +.hidden crypto_auth1_poly1305_amd64_hoffset0 635 | +.hidden crypto_auth1_poly1305_amd64_hoffset1 636 | +.hidden crypto_auth1_poly1305_amd64_hoffset2 637 | +.hidden crypto_auth1_poly1305_amd64_hoffset3 638 | +.hidden crypto_auth1_poly1305_amd64_rounding 639 | + 640 | _crypto_auth1_poly1305_amd64_constants: 641 | crypto_auth1_poly1305_amd64_constants: 642 | crypto_auth1_poly1305_amd64_scale: 643 | Index: nacl-20080914/crypto_auth1/poly1305/x86/constants.s 644 | =================================================================== 645 | --- nacl-20080914.orig/crypto_auth1/poly1305/x86/constants.s 2008-09-18 16:01:51.000000000 -0700 646 | +++ nacl-20080914/crypto_auth1/poly1305/x86/constants.s 2008-09-18 16:02:09.000000000 -0700 647 | @@ -27,6 +27,27 @@ 648 | .globl crypto_auth1_poly1305_x86_hoffset3 649 | .globl crypto_auth1_poly1305_x86_rounding 650 | 651 | +.hidden _crypto_auth1_poly1305_x86_constants 652 | +.hidden crypto_auth1_poly1305_x86_constants 653 | +.hidden crypto_auth1_poly1305_x86_scale 654 | +.hidden crypto_auth1_poly1305_x86_two32 655 | +.hidden crypto_auth1_poly1305_x86_two64 656 | +.hidden crypto_auth1_poly1305_x86_two96 657 | +.hidden crypto_auth1_poly1305_x86_alpha32 658 | +.hidden crypto_auth1_poly1305_x86_alpha64 659 | +.hidden crypto_auth1_poly1305_x86_alpha96 660 | +.hidden crypto_auth1_poly1305_x86_alpha130 661 | +.hidden crypto_auth1_poly1305_x86_doffset0 662 | +.hidden crypto_auth1_poly1305_x86_doffset1 663 | +.hidden crypto_auth1_poly1305_x86_doffset2 664 | +.hidden crypto_auth1_poly1305_x86_doffset3 665 | +.hidden crypto_auth1_poly1305_x86_doffset3minustwo128 666 | +.hidden crypto_auth1_poly1305_x86_hoffset0 667 | +.hidden crypto_auth1_poly1305_x86_hoffset1 668 | +.hidden crypto_auth1_poly1305_x86_hoffset2 669 | +.hidden crypto_auth1_poly1305_x86_hoffset3 670 | +.hidden crypto_auth1_poly1305_x86_rounding 671 | + 672 | _crypto_auth1_poly1305_x86_constants: 673 | crypto_auth1_poly1305_x86_constants: 674 | crypto_auth1_poly1305_x86_scale: 675 | -------------------------------------------------------------------------------- /slownacl/__init__.py: -------------------------------------------------------------------------------- 1 | from util import xor, randombytes 2 | from verify import verify16, verify32 3 | from salsa20 import stream_salsa20, stream_salsa20_xor 4 | from poly1305 import onetimeauth_poly1305, onetimeauth_poly1305_verify 5 | from hash import hash_sha512, auth_hmacsha512, auth_hmacsha512_verify 6 | from curve25519 import smult_curve25519, smult_curve25519_base 7 | 8 | 9 | def secretbox_salsa20hmacsha512(m, n, k): 10 | s = stream_salsa20(len(m) + 32, n, k) 11 | c = xor(m, s[32:]) 12 | a = auth_hmacsha512(c, s[:32]) 13 | return a + c 14 | 15 | def secretbox_salsa20hmacsha512_open(c, n, k): 16 | if len(c) < 32: raise ValueError('Too short for Salsa20HMACSHA512 box') 17 | s = stream_salsa20(32, n, k) 18 | if not auth_hmacsha512_verify(c[:32], c[32:], s): 19 | raise ValueError('Bad authenticator for Salsa20HMACSHA512 box') 20 | s = stream_salsa20(len(c), n, k) 21 | return xor(c[32:], s[32:]) 22 | 23 | 24 | def box_curve25519salsa20hmacsha512_keypair(): 25 | sk = randombytes(32) 26 | pk = smult_curve25519_base(sk) 27 | return (pk, sk) 28 | 29 | def box_curve25519salsa20hmacsha512(m, n, pk, sk): 30 | k = hash_sha512(smult_curve25519(sk, pk))[:32] 31 | return secretbox_salsa20hmacsha512(m, n, k) 32 | 33 | def box_curve25519salsa20hmacsha512_open(c, n, pk, sk): 34 | k = hash_sha512(smult_curve25519(sk, pk))[:32] 35 | return secretbox_salsa20hmacsha512_open(c, n, k) 36 | -------------------------------------------------------------------------------- /slownacl/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/__init__.pyc -------------------------------------------------------------------------------- /slownacl/curve25519.py: -------------------------------------------------------------------------------- 1 | __all__ = ['smult_curve25519_base', 'smult_curve25519'] 2 | 3 | P = 2 ** 255 - 19 4 | A = 486662 5 | 6 | def expmod(b, e, m): 7 | if e == 0: return 1 8 | t = expmod(b, e / 2, m) ** 2 % m 9 | if e & 1: t = (t * b) % m 10 | return t 11 | 12 | def inv(x): 13 | return expmod(x, P - 2, P) 14 | 15 | # Addition and doubling formulas taken from Appendix D of "Curve25519: 16 | # new Diffie-Hellman speed records". 17 | 18 | def add((xn,zn), (xm,zm), (xd,zd)): 19 | x = 4 * (xm * xn - zm * zn) ** 2 * zd 20 | z = 4 * (xm * zn - zm * xn) ** 2 * xd 21 | return (x % P, z % P) 22 | 23 | def double((xn,zn)): 24 | x = (xn ** 2 - zn ** 2) ** 2 25 | z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2) 26 | return (x % P, z % P) 27 | 28 | def curve25519(n, base): 29 | one = (base,1) 30 | two = double(one) 31 | # f(m) evaluates to a tuple containing the mth multiple and the 32 | # (m+1)th multiple of base. 33 | def f(m): 34 | if m == 1: return (one, two) 35 | (pm, pm1) = f(m / 2) 36 | if (m & 1): 37 | return (add(pm, pm1, one), double(pm1)) 38 | return (double(pm), add(pm, pm1, one)) 39 | ((x,z), _) = f(n) 40 | return (x * inv(z)) % P 41 | 42 | def unpack(s): 43 | if len(s) != 32: raise ValueError('Invalid Curve25519 argument') 44 | return sum(ord(s[i]) << (8 * i) for i in range(32)) 45 | 46 | def pack(n): 47 | return ''.join([chr((n >> (8 * i)) & 255) for i in range(32)]) 48 | 49 | def clamp(n): 50 | n &= ~7 51 | n &= ~(128 << 8 * 31) 52 | n |= 64 << 8 * 31 53 | return n 54 | 55 | def smult_curve25519(n, p): 56 | n = clamp(unpack(n)) 57 | p = unpack(p) 58 | return pack(curve25519(n, p)) 59 | 60 | def smult_curve25519_base(n): 61 | n = clamp(unpack(n)) 62 | return pack(curve25519(n, 9)) 63 | -------------------------------------------------------------------------------- /slownacl/curve25519.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/curve25519.pyc -------------------------------------------------------------------------------- /slownacl/hash.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from util import xor 3 | from verify import verify32 4 | 5 | __all__ = ['hash_sha512', 'auth_hmacsha512'] 6 | 7 | # Python has an hmac module, but at least as of 2.5.1, it assumed a 8 | # block size of 64 bytes regardless of hash function, whereas SHA-512 9 | # uses a block size of 128 bytes. 10 | 11 | def hash_sha512(m): 12 | return hashlib.sha512(m).digest() 13 | 14 | def auth_hmacsha512(m, k): 15 | if len(k) != 32: raise ValueError('Invalid key size for HMACSHA512') 16 | def pad(c): return xor(chr(c) * 128, k + '\0' * 96) 17 | m = hash_sha512(pad(0x36) + m) 18 | m = hash_sha512(pad(0x5c) + m) 19 | return m[:32] 20 | 21 | def auth_hmacsha512_verify(a, m, k): 22 | return verify32(a, auth_hmacsha512(m, k)) 23 | -------------------------------------------------------------------------------- /slownacl/hash.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/hash.pyc -------------------------------------------------------------------------------- /slownacl/poly1305.py: -------------------------------------------------------------------------------- 1 | from verify import verify16 2 | 3 | __all__ = ['onetimeauth_poly1305', 'onetimeauth_poly1305_verify'] 4 | 5 | P = 2 ** 130 - 5 6 | 7 | def limb(s): 8 | return unpack(s) + (1 << 8 * len(s)) 9 | 10 | def unpack(s): 11 | return sum(ord(s[i]) << 8 * i for i in range(len(s))) 12 | 13 | def pack(n): 14 | return ''.join([chr(n >> 8 * i & 255) for i in range(16)]) 15 | 16 | def onetimeauth_poly1305(m, kr): 17 | if len(kr) != 32: raise ValueError('Invalid Poly1305 key') 18 | k = unpack(kr[:16]) 19 | r = unpack(kr[16:]) 20 | 21 | h = 0 22 | for i in range(0, len(m), 16): 23 | c = limb(m[i:i+16]) 24 | h = (h + c) * r % P 25 | h += k 26 | 27 | return pack(h) 28 | 29 | def onetimeauth_poly1305_verify(a, m, k): 30 | return verify16(a, onetimeauth_poly1305(m, k)) 31 | -------------------------------------------------------------------------------- /slownacl/poly1305.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/poly1305.pyc -------------------------------------------------------------------------------- /slownacl/salsa20.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from util import xor 3 | 4 | __all__ = ['stream_salsa20', 'stream_salsa20_xor'] 5 | 6 | def rotate(x, n): 7 | x &= 0xffffffff 8 | return ((x << n) | (x >> (32 - n))) & 0xffffffff 9 | 10 | def step(s, i, j, k, r): 11 | s[i] ^= rotate(s[j] + s[k],r) 12 | 13 | def quarterround(s, i0, i1, i2, i3): 14 | step(s, i1, i0, i3, 7) 15 | step(s, i2, i1, i0, 9) 16 | step(s, i3, i2, i1, 13) 17 | step(s, i0, i3, i2, 18) 18 | 19 | def rowround(s): 20 | quarterround(s, 0, 1, 2, 3) 21 | quarterround(s, 5, 6, 7, 4) 22 | quarterround(s, 10, 11, 8, 9) 23 | quarterround(s, 15, 12, 13, 14) 24 | 25 | def columnround(s): 26 | quarterround(s, 0, 4, 8, 12) 27 | quarterround(s, 5, 9, 13, 1) 28 | quarterround(s, 10, 14, 2, 6) 29 | quarterround(s, 15, 3, 7, 11) 30 | 31 | def doubleround(s): 32 | columnround(s) 33 | rowround(s) 34 | 35 | def rounds(s, n): 36 | s1 = list(s) 37 | while n >= 2: 38 | doubleround(s1) 39 | n -= 2 40 | for i in range(16): s[i] = (s[i] + s1[i]) & 0xffffffff 41 | 42 | o = struct.unpack('<4I', 'expand 32-byte k') 43 | 44 | def block(i, n, k): 45 | i = (i & 0xffffffff, i >> 32) 46 | s = [0] * 16 47 | s[::5] = o 48 | s[1:5] = k[:4] 49 | s[6:10] = n + i 50 | s[11:15] = k[4:] 51 | rounds(s, 20) 52 | return struct.pack('<16I', *s) 53 | 54 | def stream_salsa20(l, n, k): 55 | output = [] 56 | n = struct.unpack('<2I', n) 57 | k = struct.unpack('<8I', k) 58 | for i in xrange(0, l, 64): 59 | output.append(block(i // 64, n, k)) 60 | return ''.join(output)[:l] 61 | 62 | def stream_salsa20_xor(m, n, k): 63 | return xor(m, stream_salsa20(len(m), n, k)) 64 | -------------------------------------------------------------------------------- /slownacl/salsa20.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/salsa20.pyc -------------------------------------------------------------------------------- /slownacl/test.py: -------------------------------------------------------------------------------- 1 | # This is not part of the slownacl library, it's just a unittest to verify a 2 | # few things against the Python wrapping of NaCl. 3 | 4 | import slownacl 5 | import nacl 6 | import random 7 | 8 | def check_funcs(its, a, b, arglens): 9 | '''Checks that two functions are a same by calling each with random strings 10 | where the lengths of the random strings are given in @arglens (list of 11 | int). The entries of @arglens may also be a range tuple''' 12 | 13 | def r(x): 14 | if type(x) == int: 15 | return slownacl.randombytes(x) 16 | elif type(x) == tuple: 17 | length = random.randint(*x) 18 | return slownacl.randombytes(length) 19 | 20 | for i in range(its): 21 | args = [r(x) for x in arglens] 22 | if a(*args) != b(*args): 23 | print 24 | print 25 | print 'failed after %d tests. Failing input:' % i 26 | print args 27 | print 28 | print repr(a(*args)) 29 | print repr(b(*args)) 30 | return False 31 | 32 | return True 33 | 34 | def check(its, name, arglens): 35 | print ('Checking %s...' % name), 36 | if check_funcs(its, getattr(nacl, name), getattr(slownacl, name), arglens): 37 | print 'ok' 38 | else: 39 | print 'FAILED' 40 | 41 | if __name__ == '__main__': 42 | check(1024, 'hash_sha512', [(1, 100)]) 43 | check(1024, 'auth_hmacsha512', [(1, 100), 32]) 44 | check(256, 'smult_curve25519_base', [32]) 45 | check(128, 'stream_salsa20_xor', [(0, 1024), 8, 32]) 46 | check(64, 'smult_curve25519', [32, 32]) 47 | -------------------------------------------------------------------------------- /slownacl/util.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def xor(s, t): 4 | output = [] 5 | if len(s) != len(t): raise ValueError('Cannot xor strings of unequal length') 6 | for i in range(len(s)): 7 | output.append(chr(ord(s[i]) ^ ord(t[i]))) 8 | return ''.join(output) 9 | 10 | def randombytes(n): 11 | return open('/dev/urandom').read(n) 12 | -------------------------------------------------------------------------------- /slownacl/util.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/util.pyc -------------------------------------------------------------------------------- /slownacl/verify.py: -------------------------------------------------------------------------------- 1 | def verify16(a, b): 2 | if len(a) != 16 or len(b) != 16: 3 | raise ValueError('Not 16 bytes') 4 | return 0 == reduce(lambda x, y: x ^ y, [ord(a) ^ ord(b) for (a,b) in zip(a,b)]) 5 | 6 | def verify32(a, b): 7 | if len(a) != 32 or len(b) != 32: 8 | raise ValueError('Not 32 bytes') 9 | return 0 == reduce(lambda x, y: x ^ y, [ord(a) ^ ord(b) for (a,b) in zip(a,b)]) 10 | -------------------------------------------------------------------------------- /slownacl/verify.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agl/dnscurve/d069c503cabfbdb7657e73a9798b9c21593ce715/slownacl/verify.pyc -------------------------------------------------------------------------------- /tools/base32.py: -------------------------------------------------------------------------------- 1 | def encode(s): 2 | k = '0123456789abcdefghijklmnopqrstuv' 3 | 4 | v = 0 5 | vbits = 0 6 | output = [] 7 | 8 | for c in s: 9 | v |= ord(c) << vbits 10 | vbits += 8 11 | 12 | while vbits >= 5: 13 | output.append(k[v & 31]) 14 | v >>= 5 15 | vbits -= 5 16 | 17 | if vbits: 18 | output.append(k[v]) 19 | 20 | return ''.join(output) 21 | 22 | 23 | def decode(s): 24 | v = 0 25 | vbits = 0 26 | output = [] 27 | 28 | for c in s.lower(): 29 | if c >= '0' and c <= '9': 30 | u = ord(c) - ord('0') 31 | elif c >= 'a' and c <= 'v': 32 | u = ord(c) - ord('a') + 10 33 | else: 34 | raise ValueError('Invalid base-32 input') 35 | 36 | v |= u << vbits 37 | vbits += 5 38 | 39 | if vbits >= 8: 40 | output.append(chr(v & 255)) 41 | v >>= 8 42 | vbits -= 8 43 | 44 | if vbits >= 5 or v: 45 | raise ValueError('Invalid base-32 input') 46 | 47 | return ''.join(output) 48 | -------------------------------------------------------------------------------- /tools/dns-make-query.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import dns 3 | 4 | if __name__ == '__main__': 5 | sys.stdout.write(dns.dns_build_query(sys.argv[1], sys.argv[2])) 6 | -------------------------------------------------------------------------------- /tools/dns-print.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import dns 3 | 4 | if __name__ == '__main__': 5 | packet = sys.stdin.read() 6 | dns.dns_print(packet) 7 | -------------------------------------------------------------------------------- /tools/dns.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import binascii 3 | 4 | qtypes = {1: 'A', 5 | 2: 'NS', 6 | 5: 'CNAME', 7 | 6: 'SOA', 8 | 12: 'PTR', 9 | 15: 'MX', 10 | 16: 'TXT', 11 | 28: 'AAAA', 12 | 33: 'SRV', 13 | 255: 'ANY' 14 | } 15 | 16 | qclasses = {1: 'IN'} 17 | 18 | def dns_name_read(rest, p): 19 | output = [] 20 | firstcompress = None 21 | 22 | while True: 23 | b = ord(rest[0]) 24 | if b == 0: 25 | rest = rest[1:] 26 | break 27 | elif b < 64: 28 | output.append(rest[1:1+b]) 29 | output.append('.') 30 | rest = rest[1+b:] 31 | continue 32 | elif b >= 192: 33 | b2 = ord(rest[1]) 34 | pos = 256 * (b - 192) + b2 35 | if firstcompress is None: 36 | firstcompress = rest[2:] 37 | rest = p[pos:] 38 | continue 39 | else: 40 | raise ValueError('Bad DNS name') 41 | 42 | if firstcompress is not None: 43 | return (''.join(output), firstcompress) 44 | return (''.join(output), rest) 45 | 46 | def dns_query_read(rest, p): 47 | (name, rest) = dns_name_read(rest, p) 48 | (qtype, qclass) = struct.unpack('>HH', rest[:4]) 49 | return ((name, qtypes.get(qtype, '??'), qclasses.get(qclass, '??')), rest[4:]) 50 | 51 | def dns_result_read(rest, p): 52 | (name, rest) = dns_name_read(rest, p) 53 | (qtype, qclass, ttl, rdlen) = struct.unpack('>HHIH', rest[:10]) 54 | rest = rest[10:] 55 | data = rest[:rdlen] 56 | return ((name, qtypes.get(qtype, '??'), qclasses.get(qclass, '??'), ttl, data), rest[rdlen:]) 57 | 58 | def dns_pretty_rdata(type, qclass, data, p): 59 | if qclass == 'IN': 60 | if type == 'A': 61 | return '%d.%d.%d.%d' % struct.unpack('>4B', data) 62 | if type == 'NS' or type == 'PTR' or type == 'CNAME': 63 | (name, rest) = dns_name_read(data, p) 64 | if len(rest): raise ValueError('Bad DNS record data') 65 | return name 66 | if type == 'MX': 67 | (pref,) = struct.unpack('>H', data[:2]) 68 | (name, rest) = dns_name_read(data[2:], p) 69 | if len(rest): raise ValueError('Bad DNS record data') 70 | return '%d\t%s' % (pref, name) 71 | if type == 'SOA': 72 | (mname, rest) = dns_name_read(data, p) 73 | (rname, rest) = dns_name_read(rest, p) 74 | (serial, refresh, retry, expire, minimum) = struct.unpack('>5I', rest) 75 | return '%s\t%s\t%d\t%d\t%d\t%d\t%d' % (mname, rname, serial, refresh, retry, expire, minimum) 76 | if type == 'AAAA': 77 | return '%x:%x:%x:%x:%x:%x:%x:%x' % struct.unpack('>8H', data) 78 | if type == 'SRV': 79 | (pref, weight, port) = struct.unpack('>HHH', data[:6]) 80 | (name, rest) = dns_name_read(data[6:], None) 81 | if len(rest): raise ValueError('Bad DNS record data') 82 | return '%d\t%d\t%d\t%s' % (pref, weight, port, name) 83 | 84 | res = [] 85 | for c in data: 86 | if ord(c) >= 33 and ord(c) <= 126 and c != '\\': 87 | res.append(c) 88 | else: 89 | res.append('\\%03o' % (ord(c),)) 90 | return ''.join(res) 91 | 92 | def dns_print(p): 93 | (id, f1, f2, nquery, nans, nauth, nadd) = struct.unpack('>HBBHHHH', p[:12]) 94 | 95 | flags = [] 96 | if f1 & 0x80: 97 | flags.append('response') 98 | else: 99 | flags.append('query') 100 | 101 | if f1 & 0x78: 102 | flags.append('weird-op') 103 | if f1 & 4: 104 | flags.append('authoriative') 105 | if f1 & 2: 106 | flags.append('truncated') 107 | if f1 & 1: 108 | flags.append('recursion-requested') 109 | 110 | if f2 & 0x80: 111 | flags.append('recursion-avail') 112 | if f2 & 0x70: 113 | flags.append('weird-z') 114 | 115 | rcode = f2 & 15; 116 | errors = {0: 'Success', 117 | 1: 'Format error', 118 | 2: 'Server failure', 119 | 3: 'Name error', 120 | 4: 'Not implemented', 121 | 5: 'Refused'} 122 | 123 | status = errors.get(rcode, 'Unknown') 124 | 125 | print ';; DNS packet:', ' '.join(flags) 126 | print ';; Status:', status 127 | print ';; QUERY: %d, ANSWER: %d, AUTHORITY: %d, ADDITIONAL: %d' % (nquery, nans, nauth, nadd) 128 | print 129 | 130 | print ';; QUESTION SECTION' 131 | rest = p[12:] 132 | for n in range(nquery): 133 | (query, rest) = dns_query_read(rest, p) 134 | print ';%s\t\t\t%s\t%s' % query 135 | 136 | for (section, count) in [('ANSWER', nans), ('AUTHORITY', nauth), 137 | ('ADDITIONAL', nadd)]: 138 | print 139 | print ';; %s SECTION' % section 140 | for n in range(count): 141 | ((name, type, qclass, ttl, data), rest) = dns_result_read(rest, p) 142 | print '%s\t\t%d\t%s\t%s\t%s' % (name, ttl, type, qclass, dns_pretty_rdata(type, qclass, data, p)) 143 | 144 | def dns_build_query(type, host): 145 | output = [] 146 | 147 | output.append('\x42\x76\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00') 148 | 149 | name = host.split('.') 150 | for n in name: 151 | if len(n): 152 | output.append(chr(len(n))) 153 | output.append(n) 154 | output.append(chr(0)) 155 | 156 | try: 157 | n = qtypes.keys()[qtypes.values().index(type.upper())] 158 | except: 159 | n = int(type) 160 | 161 | output.append(struct.pack('>H', n)) 162 | output.append('\x00\x01') 163 | 164 | return ''.join(output) 165 | -------------------------------------------------------------------------------- /tools/dnscurve.py: -------------------------------------------------------------------------------- 1 | import base32 2 | 3 | def dnscurve_getpubkey(name): 4 | for s in name: 5 | if len(s) == 54 and s[:3].lower() == 'uz5': 6 | try: 7 | return base32.decode(s[3:] + '0') 8 | except ValueError, e: 9 | pass 10 | return None 11 | 12 | 13 | def dnscurve_encode_queryname(nonce, box, pubkey, zone): 14 | if len(nonce) != 8: 15 | raise ValueError('Invalid nonce') 16 | if len(pubkey) != 32 or ord(pubkey[31]) >= 128: 17 | raise ValueError('Invalid public key') 18 | 19 | data = base32.encode(nonce + box) 20 | output = chunk(data, 50) 21 | output.append('x1a' + base32.encode(pubkey)[:51]) 22 | output.extend(zone) 23 | 24 | return output 25 | 26 | def dnscurve_decode_queryname(name): 27 | output = [] 28 | 29 | for s in name: 30 | if len(s) > 50: break 31 | output.append(s) 32 | 33 | if len(s) != 54 or s[:3].lower() != 'x1a': 34 | raise ValueError('Not a DNSCurve query') 35 | 36 | key = base32.decode(s[3:] + '0') 37 | r = base32.decode(''.join(output)) 38 | if r < 8: raise ValueError('Not a DNSCurve query') 39 | 40 | return (key, r[:8], r[8:]) 41 | 42 | 43 | def dnscurve_encode_rdata(nonce, box): 44 | if len(nonce) != 8: raise ValueError('Invalid nonce') 45 | data = nonce + box 46 | return chunk(data, 255) 47 | 48 | def dnscurve_decode_rdata(rdata): 49 | data = ''.join(rdata) 50 | if len(data) < 8: raise ValueError('Invalid DNSCurve response') 51 | return (data[:8], data[8:]) 52 | 53 | 54 | # Split 's' into a list of strings with length no greater than 'n'. 55 | def chunk(s, n): 56 | return [s[i:i+n] for i in range(0, len(s), n)] 57 | -------------------------------------------------------------------------------- /tools/nacl-box-open.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import nacl 4 | import netstring 5 | 6 | def main(): 7 | sk = netstring.read(sys.stdin) 8 | pk = netstring.read(sys.stdin) 9 | nonce = netstring.read(sys.stdin) 10 | packet = netstring.read(sys.stdin) 11 | 12 | sys.stdout.write(nacl.box_curve25519salsa20hmacsha512_open(packet, nonce, pk, sk)) 13 | 14 | if __name__ == '__main__': 15 | main() 16 | -------------------------------------------------------------------------------- /tools/nacl-box.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import nacl 4 | import netstring 5 | 6 | def main(): 7 | sk = netstring.read(sys.stdin) 8 | pk = netstring.read(sys.stdin) 9 | nonce = netstring.read(sys.stdin) 10 | packet = sys.stdin.read() 11 | 12 | netstring.write(sys.stdout, nacl.box_curve25519salsa20hmacsha512(packet, nonce, pk, sk)) 13 | 14 | if __name__ == '__main__': 15 | main() 16 | -------------------------------------------------------------------------------- /tools/nacl-keypair.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import nacl 4 | import netstring 5 | 6 | def main(): 7 | (pk, sk) = nacl.box_curve25519salsa20hmacsha512_keypair() 8 | netstring.write(sys.stdout, sk) 9 | netstring.write(sys.stdout, pk) 10 | 11 | if __name__ == '__main__': 12 | main() 13 | -------------------------------------------------------------------------------- /tools/netstring.py: -------------------------------------------------------------------------------- 1 | def read(f): 2 | length = '' 3 | while len(length) < 16: 4 | c = f.read(1) 5 | if c == ':': 6 | break 7 | if c not in '0123456789': 8 | raise ValueError('Invalid netstring input') 9 | length += c 10 | 11 | if len(length) == 16: 12 | raise ValueError('Invalid netstring input') 13 | 14 | length = int(length) 15 | data = f.read(length) 16 | f.read(1) # chomp ',' 17 | return data 18 | 19 | def write(f, s): 20 | f.write('%d:' % len(s)) 21 | f.write(s) 22 | f.write(',') 23 | --------------------------------------------------------------------------------