Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

373 lines
10 KiB

  1. /**
  2. * @cond internal
  3. * @file test_strobe.c
  4. * @copyright
  5. * Copyright (c) 2016 Cryptography Research, Inc. \n
  6. * Released under the MIT License. See LICENSE.txt for license information.
  7. * @author Mike Hamburg
  8. * @brief Test/example code for STROBE.
  9. */
  10. #define _GNU_SOURCE 1
  11. #define _XOPEN_SOURCE 700
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #include <sys/time.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <errno.h>
  19. #include "x25519.h"
  20. #include "strobe.h"
  21. #include <sys/socket.h>
  22. #include <arpa/inet.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. /* FUTURE: should these go into header? */
  26. static inline __attribute__((unused))
  27. ssize_t strobe_put_and_steg_mac (
  28. strobe_t strobe,
  29. control_word_t cw,
  30. const uint8_t *data,
  31. ssize_t len,
  32. uint16_t pad
  33. ) {
  34. TRY( strobe_put(strobe, cw|FLAG_META_C|FLAG_C, data, len) );
  35. TRY( strobe_put(strobe, MAC|FLAG_META_T|FLAG_META_C, NULL, pad + STROBE_INTEROP_MAC_BYTES) );
  36. return len;
  37. }
  38. static inline __attribute__((unused))
  39. ssize_t strobe_get_and_steg_mac (
  40. strobe_t strobe,
  41. control_word_t cw,
  42. uint8_t *data,
  43. ssize_t len
  44. ) {
  45. ssize_t len2;
  46. TRY( len = strobe_get(strobe, cw|FLAG_META_C|FLAG_C, data, len) );
  47. TRY( len2 = strobe_get(strobe, MAC|FLAG_META_T|FLAG_META_C, NULL, -(1<<14)) );
  48. if (len2 < STROBE_INTEROP_MAC_BYTES) return -1;
  49. return len;
  50. }
  51. int strobe_x_mksocket_client (
  52. uint16_t port
  53. ) {
  54. struct sockaddr_in addr;
  55. int sock = socket(AF_INET , SOCK_STREAM , 0);
  56. if (sock == -1) { return -1; }
  57. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  58. addr.sin_family = AF_INET;
  59. addr.sin_port = htons( port );
  60. if (connect(sock , (struct sockaddr *)&addr , sizeof(addr)) < 0) {
  61. close(sock);
  62. return -1;
  63. }
  64. return sock;
  65. }
  66. int strobe_x_mksocket_server (
  67. uint16_t port
  68. ) {
  69. struct sockaddr_in addr;
  70. int option = 1;
  71. int sock = socket(AF_INET , SOCK_STREAM , 0);
  72. if (sock == -1) { return -1; }
  73. if(setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,(const char*)&option,sizeof(option)) < 0)
  74. return -1;
  75. addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  76. addr.sin_family = AF_INET;
  77. addr.sin_port = htons( port );
  78. if (bind(sock , (struct sockaddr *)&addr , sizeof(addr)) < 0) {
  79. close(sock);
  80. return -1;
  81. }
  82. if (listen(sock,1)) return -1;
  83. int sock2 = accept(sock,NULL,NULL);
  84. close(sock);
  85. return sock2;
  86. }
  87. // FUTURE: combine sending.
  88. static ssize_t cb_recv(strobe_io_ctx_s *ctx, const uint8_t **buffer, ssize_t size) {
  89. uint8_t *a = ctx->a, *b = ctx->b;
  90. if (size < 0) {
  91. return -1;
  92. } else if (size == 0) {
  93. return 0;
  94. } else if (size > b-a) {
  95. size = b-a;
  96. }
  97. *buffer = a;
  98. ssize_t avail = recv(ctx->fd, a, size, MSG_WAITALL);
  99. if (avail == 0) avail = -1; // Cause an error on end of file
  100. return avail;
  101. }
  102. static ssize_t cb_send(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) {
  103. (void)size; /* don't care how many bytes you're gonna write */
  104. uint8_t *a = ctx->a, *b = ctx->b;
  105. ssize_t ret;
  106. if (*buffer > a && *buffer <= b) {
  107. TRY(( ret = send(ctx->fd, a, *buffer-a, 0) ));
  108. if (ret != *buffer-a) return -1;
  109. }
  110. *buffer = a;
  111. return b-a;
  112. }
  113. const strobe_io_callbacks_s strobe_x_cb_socket = { cb_recv, cb_send };
  114. static double now(void) {
  115. struct timeval tv;
  116. gettimeofday(&tv, NULL);
  117. return tv.tv_sec + tv.tv_usec/1000000.0;
  118. }
  119. int hexchar(char x) {
  120. if (x>= '0' && x <= '9') return x-'0';
  121. if (x>= 'a' && x <= 'f') return 10 + x-'a';
  122. if (x>= 'A' && x <= 'F') return 10 + x-'A';
  123. return -1;
  124. }
  125. int hex2bin(unsigned char *bin, size_t len, const char *hex) {
  126. if (strlen(hex) != len*2) return -1;
  127. unsigned int i;
  128. int res = 0;
  129. for (i=0; i<2*len; i++) {
  130. int c = hexchar(hex[i]);
  131. if (c<0) return -1;
  132. res = 16*res+c;
  133. if (i%2 == 1) {
  134. *(bin++) = res;
  135. res = 0;
  136. }
  137. }
  138. return 0;
  139. }
  140. static const char *descr = "toy protocol";
  141. uint8_t g_buffer[1024];
  142. static void strobe_x_attach_socket(strobe_t strobe, int sock, uint8_t *buffer, size_t size) {
  143. strobe->io = &strobe_x_cb_socket;
  144. strobe->io_ctx.a = buffer;
  145. strobe->io_ctx.b = buffer + size;
  146. strobe->io_ctx.fd = sock;
  147. }
  148. int strobe_toy_client (
  149. strobe_t strobe,
  150. const uint8_t their_pubkey[32],
  151. int sock
  152. ) {
  153. strobe_init(strobe, (const uint8_t *)descr, strlen(descr));
  154. strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer));
  155. TRY( strobe_eph_ecdh(strobe, 1) );
  156. TRY( strobe_session_verify(strobe, their_pubkey) );
  157. return 0;
  158. }
  159. int strobe_sym_client_server (
  160. strobe_t strobe,
  161. int sock
  162. ) {
  163. const char *descr0="hello", *key="my key";
  164. strobe_init(strobe, (const uint8_t *)descr0, strlen(descr0));
  165. strobe_put(strobe, SYM_KEY, (const uint8_t *)key, strlen(key));
  166. strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer));
  167. return 0;
  168. }
  169. int strobe_toy_server (
  170. strobe_t strobe,
  171. const uint8_t my_seckey[32],
  172. int sock
  173. ) {
  174. strobe_init(strobe, (const uint8_t *)descr, strlen(descr));
  175. strobe_x_attach_socket(strobe,sock,g_buffer,sizeof(g_buffer));
  176. TRY( strobe_eph_ecdh(strobe, 0) );
  177. uint8_t my_pubkey[32];
  178. x25519_base(my_pubkey, my_seckey,0);
  179. TRY( strobe_session_sign(strobe, my_seckey, my_pubkey) );
  180. return 0;
  181. }
  182. #ifdef TEST_KECCAK
  183. void dokeccak(strobe_t sponge, uint8_t xor);
  184. #endif
  185. int echo_server(strobe_t strobe) {
  186. int ret=0;
  187. ssize_t get = 0;
  188. const char *s_ = "I got your message! It was: ";
  189. size_t off = strlen(s_);
  190. unsigned char buffer[1024+1+off];
  191. memset(buffer, 0, sizeof(buffer));
  192. memcpy(buffer,s_,off);
  193. while (ret >= 0) {
  194. get = strobe_get(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,&buffer[off],-(int)sizeof(buffer)-off);
  195. if (get < 0) { ret = get; break; }
  196. buffer[get+off] = 0;
  197. printf("Received %zd %s\n", get, &buffer[off]);
  198. printf("Sending %zd %s\n", get+off, buffer);
  199. ret = strobe_put(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,buffer,get+off);
  200. }
  201. return ret;
  202. }
  203. int echo_client(strobe_t strobe) {
  204. char *linep = NULL;
  205. size_t linep_size = 0;
  206. int ret=0;
  207. ssize_t get;
  208. unsigned char buffer[1024];
  209. memset(buffer, 0, sizeof(buffer));
  210. while (ret >= 0) {
  211. get = getline(&linep, &linep_size, stdin);
  212. //printf("GET %d\n", get);
  213. if (get <= 0) { ret = get; break; }
  214. if (get > 1024) { ret = -1; break; }
  215. if ((uint16_t)get != (size_t)get) { return -1; }
  216. ret = strobe_put(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,(uint8_t*)linep,get-1);
  217. if (ret < 0) break;
  218. get = strobe_get(strobe,APP_CIPHERTEXT|FLAG_POST_MAC,buffer,1-(int)sizeof(buffer));
  219. if (get < 0) { ret = get; break; }
  220. buffer[get] = 0;
  221. printf("Received %zd %s\n", get, buffer);
  222. }
  223. free(linep);
  224. return ret;
  225. }
  226. int main(int argc, char **argv) {
  227. int ret = 0, sock = 0;
  228. uint8_t pub[32], sec[32], seed[32]={0};
  229. strobe_t strobe;
  230. int randfd = open("/dev/urandom",O_RDONLY);
  231. if (randfd < 0) {
  232. printf("Can't open /dev/urandom: %s\n", strerror(errno));
  233. return -1;
  234. } else if ((ret = read(randfd,seed,sizeof(seed))) != sizeof(seed)) {
  235. printf("Can't read /dev/urandom: %s\n", strerror(errno));
  236. return -1;
  237. }
  238. strobe_seed_prng(seed,sizeof(seed));
  239. if (argc == 3 && !strcmp(argv[1],"--client")) {
  240. if (hex2bin(pub,sizeof(pub),argv[2])) {
  241. printf("bad hex\n");
  242. return -1;
  243. }
  244. sock = strobe_x_mksocket_client(4444);
  245. if (sock < 0) ret = sock;
  246. else ret = strobe_toy_client(strobe,pub,sock);
  247. if (ret >= 0) ret = echo_client(strobe);
  248. } else if (argc == 2 && !strcmp(argv[1],"--sym-client")) {
  249. sock = strobe_x_mksocket_client(4444);
  250. if (sock < 0) ret = sock;
  251. else ret = strobe_sym_client_server(strobe,sock);
  252. if (ret >= 0) ret = echo_client(strobe);
  253. } else if (argc == 2 && !strcmp(argv[1],"--sym-server")) {
  254. sock = strobe_x_mksocket_server(4444);
  255. if (sock < 0) ret = sock;
  256. else ret = strobe_sym_client_server(strobe,sock);
  257. if (ret >= 0) ret = echo_server(strobe);
  258. } else if (argc == 3 && !strcmp(argv[1],"--server")) {
  259. if (hex2bin(sec,sizeof(sec),argv[2])) {
  260. printf("bad hex\n");
  261. return -1;
  262. }
  263. sock = strobe_x_mksocket_server(4444);
  264. if (sock < 0) ret = sock;
  265. else ret = strobe_toy_server(strobe,sec,sock);
  266. if (ret >= 0) ret = echo_server(strobe);
  267. } else if (argc == 2 && !strcmp(argv[1],"--keygen")) {
  268. uint8_t pub[32],sec[32];
  269. if (( ret = strobe_randomize(sec,sizeof(sec)) ) >= 0 ) {
  270. int i;
  271. printf("%s --server ", argv[0]);
  272. for (i=0; i<32; i++) printf("%02x",sec[i]);
  273. printf("\n");
  274. x25519_base(pub,sec,0);
  275. printf("%s --client ", argv[0]);
  276. for (i=0; i<32; i++) printf("%02x",pub[i]);
  277. printf("\n");
  278. return 0;
  279. }
  280. } else if (argc == 2 && !strcmp(argv[1],"--bench")) {
  281. const int BYTES = 10000, ROUNDS = 100;
  282. uint8_t buffer[BYTES];
  283. uint8_t buffer2[BYTES+4];
  284. memset(buffer,0,sizeof(buffer));
  285. strobe_init(strobe,(const unsigned char *)"benching",5);
  286. double t = now();
  287. for (int i=0; i<ROUNDS; i++) {
  288. strobe_attach_buffer(strobe,buffer2,sizeof(buffer2));
  289. int ret = strobe_operate(strobe,APP_CIPHERTEXT,buffer,sizeof(buffer));
  290. if (ret<0) return -1;
  291. }
  292. t = now()-t;
  293. printf("%dB/%0.3fs = %0.3fkB/s\n", BYTES*ROUNDS, t, BYTES*ROUNDS/t/1000);
  294. return 0;
  295. #ifdef TEST_KECCAK
  296. } else if (argc == 2 && !strcmp(argv[1],"--tv")) {
  297. memset(strobe,0,sizeof(strobe));
  298. dokeccak(strobe,0);
  299. for (int i=0; i<25*4; i++)
  300. printf("%02x ", strobe->state->b[i]);
  301. printf("\n");
  302. #endif
  303. } else {
  304. printf(
  305. "Usage: %s --keygen\n"
  306. " %s --client key\n"
  307. " %s --server key\n"
  308. " %s --client-too key\n"
  309. " %s --server-too key\n"
  310. " %s --bench\n",
  311. argv[0],argv[0],argv[0],
  312. argv[0],argv[0],argv[0]
  313. );
  314. return -1;
  315. }
  316. if (sock) close(sock);
  317. printf("ret = %d\n", ret);
  318. return 0;
  319. }