/** * @cond internal * @file test_strobe.c * @copyright * Copyright (c) 2016 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg * @brief Test/example code for STROBE. */ #define _GNU_SOURCE 1 #define _XOPEN_SOURCE 700 #include #include #include #include #include #include #include #include "x25519.h" #include "strobe.h" #include #include #include #include /* FUTURE: should these go into header? */ static inline __attribute__((unused)) ssize_t strobe_put_and_steg_mac ( strobe_t strobe, control_word_t cw, const uint8_t *data, ssize_t len, uint16_t pad ) { TRY( strobe_put(strobe, cw|FLAG_META_C|FLAG_C, data, len) ); TRY( strobe_put(strobe, MAC|FLAG_META_T|FLAG_META_C, NULL, pad + STROBE_INTEROP_MAC_BYTES) ); return len; } static inline __attribute__((unused)) ssize_t strobe_get_and_steg_mac ( strobe_t strobe, control_word_t cw, uint8_t *data, ssize_t len ) { ssize_t len2; TRY( len = strobe_get(strobe, cw|FLAG_META_C|FLAG_C, data, len) ); TRY( len2 = strobe_get(strobe, MAC|FLAG_META_T|FLAG_META_C, NULL, -(1<<14)) ); if (len2 < STROBE_INTEROP_MAC_BYTES) return -1; return len; } int strobe_x_mksocket_client ( uint16_t port ) { struct sockaddr_in addr; int sock = socket(AF_INET , SOCK_STREAM , 0); if (sock == -1) { return -1; } addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_family = AF_INET; addr.sin_port = htons( port ); if (connect(sock , (struct sockaddr *)&addr , sizeof(addr)) < 0) { close(sock); return -1; } return sock; } int strobe_x_mksocket_server ( uint16_t port ) { struct sockaddr_in addr; int option = 1; int sock = socket(AF_INET , SOCK_STREAM , 0); if (sock == -1) { return -1; } if(setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,(const char*)&option,sizeof(option)) < 0) return -1; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_family = AF_INET; addr.sin_port = htons( port ); if (bind(sock , (struct sockaddr *)&addr , sizeof(addr)) < 0) { close(sock); return -1; } if (listen(sock,1)) return -1; int sock2 = accept(sock,NULL,NULL); close(sock); return sock2; } // FUTURE: combine sending. static ssize_t cb_recv(strobe_io_ctx_s *ctx, const uint8_t **buffer, ssize_t size) { uint8_t *a = ctx->a, *b = ctx->b; if (size < 0) { return -1; } else if (size == 0) { return 0; } else if (size > b-a) { size = b-a; } *buffer = a; ssize_t avail = recv(ctx->fd, a, size, MSG_WAITALL); if (avail == 0) avail = -1; // Cause an error on end of file return avail; } static ssize_t cb_send(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) { (void)size; /* don't care how many bytes you're gonna write */ uint8_t *a = ctx->a, *b = ctx->b; ssize_t ret; if (*buffer > a && *buffer <= b) { TRY(( ret = send(ctx->fd, a, *buffer-a, 0) )); if (ret != *buffer-a) return -1; } *buffer = a; return b-a; } const strobe_io_callbacks_s strobe_x_cb_socket = { cb_recv, cb_send }; static double now(void) { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec/1000000.0; } int hexchar(char x) { if (x>= '0' && x <= '9') return x-'0'; if (x>= 'a' && x <= 'f') return 10 + x-'a'; if (x>= 'A' && x <= 'F') return 10 + x-'A'; return -1; } int hex2bin(unsigned char *bin, size_t len, const char *hex) { if (strlen(hex) != len*2) return -1; unsigned int i; int res = 0; for (i=0; i<2*len; i++) { int c = hexchar(hex[i]); if (c<0) return -1; res = 16*res+c; if (i%2 == 1) { *(bin++) = res; res = 0; } } return 0; } static const char *descr = "toy protocol"; uint8_t g_buffer[1024]; static void strobe_x_attach_socket(strobe_t strobe, int sock, uint8_t *buffer, size_t size) { strobe->io = &strobe_x_cb_socket; strobe->io_ctx.a = buffer; strobe->io_ctx.b = buffer + size; strobe->io_ctx.fd = sock; } int strobe_toy_client ( strobe_t strobe, const uint8_t their_pubkey[32], int sock ) { strobe_init(strobe, (const uint8_t *)descr, strlen(descr)); strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer)); TRY( strobe_eph_ecdh(strobe, 1) ); TRY( strobe_session_verify(strobe, their_pubkey) ); return 0; } int strobe_sym_client_server ( strobe_t strobe, int sock ) { const char *descr0="hello", *key="my key"; strobe_init(strobe, (const uint8_t *)descr0, strlen(descr0)); strobe_put(strobe, SYM_KEY, (const uint8_t *)key, strlen(key)); strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer)); return 0; } int strobe_toy_server ( strobe_t strobe, const uint8_t my_seckey[32], int sock ) { strobe_init(strobe, (const uint8_t *)descr, strlen(descr)); strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer)); TRY( strobe_eph_ecdh(strobe, 0) ); uint8_t my_pubkey[32]; x25519_base(my_pubkey, my_seckey,0); TRY( strobe_session_sign(strobe, my_seckey, my_pubkey) ); return 0; } #ifdef TEST_KECCAK void dokeccak(strobe_t sponge, uint8_t xor); #endif int echo_server(strobe_t strobe) { int ret=0; ssize_t get = 0; const char *s_ = "I got your message! It was: "; size_t off = strlen(s_); unsigned char buffer[1024+1+off]; memset(buffer, 0, sizeof(buffer)); memcpy(buffer,s_,off); while (ret >= 0) { get = strobe_get(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,&buffer[off],-(int)sizeof(buffer)-off); if (get < 0) { ret = get; break; } buffer[get+off] = 0; printf("Received %zd %s\n", get, &buffer[off]); printf("Sending %zd %s\n", get+off, buffer); ret = strobe_put(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,buffer,get+off); } return ret; } int echo_client(strobe_t strobe) { char *linep = NULL; size_t linep_size = 0; int ret=0; ssize_t get; unsigned char buffer[1024]; memset(buffer, 0, sizeof(buffer)); while (ret >= 0) { get = getline(&linep, &linep_size, stdin); //printf("GET %d\n", get); if (get <= 0) { ret = get; break; } if (get > 1024) { ret = -1; break; } if ((uint16_t)get != (size_t)get) { return -1; } ret = strobe_put(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,(uint8_t*)linep,get-1); if (ret < 0) break; get = strobe_get(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,buffer,1-(int)sizeof(buffer)); if (get < 0) { ret = get; break; } buffer[get] = 0; printf("Received %zd %s\n", get, buffer); } free(linep); return ret; } int main(int argc, char **argv) { int ret = 0, sock = 0; uint8_t pub[32], sec[32], seed[32]={0}; strobe_t strobe; int randfd = open("/dev/urandom",O_RDONLY); if (randfd < 0) { printf("Can't open /dev/urandom: %s\n", strerror(errno)); return -1; } else if ((ret = read(randfd,seed,sizeof(seed))) != sizeof(seed)) { printf("Can't read /dev/urandom: %s\n", strerror(errno)); return -1; } strobe_seed_prng(seed,sizeof(seed)); if (argc == 3 && !strcmp(argv[1],"--client")) { if (hex2bin(pub,sizeof(pub),argv[2])) { printf("bad hex\n"); return -1; } sock = strobe_x_mksocket_client(4444); if (sock < 0) ret = sock; else ret = strobe_toy_client(strobe,pub,sock); if (ret >= 0) ret = echo_client(strobe); } else if (argc == 2 && !strcmp(argv[1],"--sym-client")) { sock = strobe_x_mksocket_client(4444); if (sock < 0) ret = sock; else ret = strobe_sym_client_server(strobe,sock); if (ret >= 0) ret = echo_client(strobe); } else if (argc == 2 && !strcmp(argv[1],"--sym-server")) { sock = strobe_x_mksocket_server(4444); if (sock < 0) ret = sock; else ret = strobe_sym_client_server(strobe,sock); if (ret >= 0) ret = echo_server(strobe); } else if (argc == 3 && !strcmp(argv[1],"--server")) { if (hex2bin(sec,sizeof(sec),argv[2])) { printf("bad hex\n"); return -1; } sock = strobe_x_mksocket_server(4444); if (sock < 0) ret = sock; else ret = strobe_toy_server(strobe,sec,sock); if (ret >= 0) ret = echo_server(strobe); } else if (argc == 2 && !strcmp(argv[1],"--keygen")) { uint8_t pub[32],sec[32]; if (( ret = strobe_randomize(sec,sizeof(sec)) ) >= 0 ) { int i; printf("%s --server ", argv[0]); for (i=0; i<32; i++) printf("%02x",sec[i]); printf("\n"); x25519_base(pub,sec,0); printf("%s --client ", argv[0]); for (i=0; i<32; i++) printf("%02x",pub[i]); printf("\n"); return 0; } } else if (argc == 2 && !strcmp(argv[1],"--bench")) { const int BYTES = 10000, ROUNDS = 100; uint8_t buffer[BYTES]; uint8_t buffer2[BYTES+4]; memset(buffer,0,sizeof(buffer)); strobe_init(strobe,(const unsigned char *)"benching",5); double t = now(); for (int i=0; istate->b[i]); printf("\n"); #endif } else { printf( "Usage: %s --keygen\n" " %s --client key\n" " %s --server key\n" " %s --client-too key\n" " %s --server-too key\n" " %s --bench\n", argv[0],argv[0],argv[0], argv[0],argv[0],argv[0] ); return -1; } if (sock) close(sock); printf("ret = %d\n", ret); return 0; }