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.
 
 
 
 
 
 

472 lines
13 KiB

  1. /**
  2. * @cond internal
  3. * @file strobe.c
  4. * @copyright
  5. * Copyright (c) 2015-2016 Cryptography Research, Inc. \n
  6. * Released under the MIT License. See LICENSE.txt for license information.
  7. * @author Mike Hamburg
  8. * @brief Strobe protocol code.
  9. */
  10. #define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */
  11. #include <assert.h>
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <limits.h> /* for INT_MAX */
  15. #include "strobe.h"
  16. #if X25519_SUPPORT_SIGN || X25519_SUPPORT_VERIFY || STROBE_CONVENIENCE_ECDH
  17. #include "x25519.h"
  18. #endif
  19. /* Sets the security level at 128 bits (but this holds even
  20. * when the attacker has lots of data).
  21. */
  22. #define CAPACITY_BITS (2*STROBE_INTEROP_SECURITY_BITS)
  23. /* Internal rate is 2 bytes less than sponge's "rate" */
  24. #define PAD_BYTES 2
  25. #define RATE_INNER ((25*sizeof(kword_t)-CAPACITY_BITS/8))
  26. #define RATE (RATE_INNER-PAD_BYTES)
  27. /* Pull in a Keccak-F implementation. Use the target-specific
  28. * asm one if available.
  29. */
  30. #include "keccak_f.c.inc"
  31. /* These padding bytes are applied before F. They are
  32. * required for parseability. Their values are chosen
  33. * for compatibilty with cSHAKE.
  34. */
  35. #define SHAKE_XOR_RATE 0x80
  36. #define SHAKE_XOR_MARK 0x04
  37. #ifndef MIN
  38. #define MIN(x,y) (((x)<(y)) ? (x) : (y))
  39. #endif
  40. /* Mark current position and state, and run F.
  41. * Should be compatible with CSHAKE.
  42. */
  43. static void
  44. _run_f (strobe_s *strobe, unsigned int p) {
  45. strobe->state.b[p] ^= strobe->pos_begin;
  46. strobe->pos_begin = 0;
  47. strobe->state.b[p+1] ^= SHAKE_XOR_MARK;
  48. strobe->state.b[RATE+1] ^= SHAKE_XOR_RATE;
  49. keccak_f(&strobe->state);
  50. }
  51. /* Place a "mark" in the hash, which is distinct from the effect of writing any byte
  52. * into the hash. Then write the new mode into the hash.
  53. */
  54. static inline void
  55. _strobe_mark(strobe_s *strobe, unsigned int * pptr, uint8_t flags) {
  56. unsigned int p = *pptr;
  57. /* This flag (in the param flags byte) indicates that the
  58. * object's role (as initiator or responder) has already
  59. * been determined.
  60. */
  61. const uint8_t FLAG_HAVE_ROLE = 1<<2;
  62. /* Mark the state */
  63. strobe->state.b[p++] ^= strobe->pos_begin;
  64. strobe->pos_begin = p;
  65. if (p >= RATE) { _run_f(strobe,p); p = 0; }
  66. /* Adjust the direction based on transport */
  67. if (flags & FLAG_T) {
  68. if (!(strobe->flags & FLAG_HAVE_ROLE)) {
  69. /* Set who is initiator and who is responder */
  70. strobe->flags |= FLAG_HAVE_ROLE | (flags & FLAG_I);
  71. }
  72. strobe->state.b[p] ^= strobe->flags & FLAG_I;
  73. }
  74. /* Absorb the rest of the mode marker */
  75. strobe->state.b[p++] ^= flags;
  76. uint8_t flags_that_cause_runf = FLAG_C;
  77. if (p >= RATE || (flags & flags_that_cause_runf)) { _run_f(strobe,p); p = 0; }
  78. *pptr = p;
  79. }
  80. /* The core duplex mode */
  81. ssize_t strobe_duplex (
  82. strobe_s *strobe,
  83. control_word_t flags,
  84. uint8_t *inside,
  85. ssize_t len
  86. ) {
  87. /* Sanity check */
  88. assert(strobe->position < RATE);
  89. if (len < 0) {
  90. assert(0);
  91. /* In production mode, no assert, but at least signal an error */
  92. return -1;
  93. }
  94. #if STROBE_SANITY_CHECK_FLAGS
  95. /* Sanity check flags against what flags we know and are implementing. */
  96. control_word_t known_flags = FLAG_I|FLAG_A|FLAG_C|FLAG_T|FLAG_M;
  97. known_flags|= FLAG_META_I|FLAG_META_A|FLAG_META_C|FLAG_META_T|FLAG_META_M;
  98. known_flags|= CW_LENGTH_BYTES(0xF);
  99. known_flags|= 0xFF00;
  100. known_flags|= FLAG_MORE|FLAG_NO_DATA;
  101. #if STROBE_SUPPORT_FLAG_POST
  102. known_flags|= FLAG_POST_RATCHET|FLAG_POST_MAC;
  103. #endif
  104. if (flags &~ known_flags) {
  105. assert(0);
  106. /* In production mode, no assert, but at least signal an error */
  107. return -1;
  108. }
  109. #endif
  110. ssize_t len2 = len, ret = 0;
  111. uint8_t cumul = 0;
  112. uint8_t s2s = -1;
  113. uint8_t s2o = (flags & FLAG_C) ? -1 : 0;
  114. if ((flags & FLAG_I) || !(flags & FLAG_T)) s2s ^= s2o; // duplex <-> unduplex
  115. unsigned int p = strobe->position;
  116. assert (p < RATE);
  117. if (!(flags & FLAG_MORE))
  118. {
  119. /* Mark the beginning of the operation in the strobe state */
  120. _strobe_mark(strobe, &p, flags);
  121. }
  122. /* Figure out where to write input and output */
  123. const uint8_t *in = NULL;
  124. uint8_t *out = NULL;
  125. ssize_t avail = 0;
  126. if (!(flags & FLAG_A)) {
  127. inside = NULL;
  128. }
  129. if (flags & FLAG_I) {
  130. out = inside;
  131. } else {
  132. in = inside;
  133. }
  134. while (len > 0) {
  135. /* First iteration will just skip to read section ... */
  136. len -= avail;
  137. for (; avail; avail--) {
  138. assert (p < RATE);
  139. uint8_t s = strobe->state.b[p], i = in ? *in++ : 0, o;
  140. o = i ^ (s&s2o);
  141. strobe->state.b[p++] = i ^ (s & s2s);
  142. cumul |= o;
  143. if (out) *out++ = o;
  144. if (p >= RATE) {
  145. _run_f(strobe,p);
  146. p = 0;
  147. }
  148. }
  149. /* Get more data */
  150. if (strobe->io == NULL || !(flags & FLAG_T)) {
  151. /* Nothing to write; leave output as NULL */
  152. avail = len;
  153. } else if ((flags & FLAG_I) && len > 0) {
  154. /* Read from wire */
  155. avail = strobe->io->read(&strobe->io_ctx, &in, len);
  156. } else {
  157. /* Write to wire. On the last iteration, len=0. */
  158. avail = strobe->io->write(&strobe->io_ctx, &out, len);
  159. }
  160. if (avail < 0) {
  161. /* IO fail! */
  162. strobe->position = p;
  163. return -1;
  164. } else if (avail > len) {
  165. avail = len;
  166. }
  167. }
  168. if ((flags & (0xF | FLAG_I)) == (TYPE_MAC | FLAG_I)) {
  169. /* Check MAC */
  170. ret = cumul ? -1 : len2;
  171. } else {
  172. ret = len2;
  173. }
  174. strobe->position = p;
  175. return ret;
  176. }
  177. /* Outer duplex mode: this one handles control words and reading/writing lengths. */
  178. static ssize_t strobe_operate_0 (
  179. strobe_s *__restrict__ strobe,
  180. uint32_t flags,
  181. uint8_t *inside,
  182. ssize_t len
  183. ) {
  184. unsigned int length_bytes = STROBE_CW_GET_LENGTH_BYTES(flags);
  185. control_word_t cwf = GET_META_FLAGS(flags);
  186. int more = flags & FLAG_MORE;
  187. int receiving_the_length = (cwf & FLAG_I) && length_bytes > 0 && !more;
  188. if (len < 0 && !receiving_the_length) {
  189. assert(((void)"strobe_operate length < 0, but not receiving the length",0));
  190. /* In case assertions are off... */
  191. return -1;
  192. }
  193. /* Read/write the control word */
  194. strobe_serialized_control_t str = {
  195. GET_CONTROL_TAG(flags),
  196. receiving_the_length ? 0 : eswap_htole_sl(len)
  197. };
  198. if (!more) {
  199. TRY(strobe_duplex(strobe, cwf, (uint8_t *)&str, sizeof(str.control) + length_bytes));
  200. }
  201. str.len = eswap_letoh_sl(str.len);
  202. // Check received control word and length
  203. if ( str.control != GET_CONTROL_TAG(flags)
  204. || str.len > INT_MAX
  205. || ((ssize_t)(len + str.len) > 0 && (ssize_t)str.len != len)
  206. ) {
  207. return -1;
  208. }
  209. len = str.len;
  210. if (flags & FLAG_NO_DATA) return 0;
  211. return strobe_duplex(strobe, flags, inside, len);
  212. }
  213. ssize_t __attribute__((noinline)) strobe_operate (
  214. strobe_s *__restrict__ strobe,
  215. uint32_t flags,
  216. uint8_t *inside,
  217. ssize_t len
  218. ) {
  219. #if STROBE_SUPPORT_FLAG_POST
  220. int ret;
  221. TRY(( ret = strobe_operate_0(strobe, flags, inside, len) ));
  222. if (flags & FLAG_POST_RATCHET) {
  223. assert(!(flags & FLAG_MORE));
  224. strobe_operate_0(strobe, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  225. }
  226. if (flags & FLAG_POST_MAC) {
  227. assert(!(flags & FLAG_MORE));
  228. control_word_t cwmac = MAC | (flags & (FLAG_I | FLAG_META_I | FLAG_META_T));
  229. TRY( strobe_operate_0(strobe, cwmac, NULL, STROBE_INTEROP_MAC_BYTES) );
  230. }
  231. return ret;
  232. #else
  233. /* Not supporting FLAG_POST_RATCHET or FLAG_POST_MAC */
  234. return strobe_operate_0(strobe, flags, inside, len);
  235. #endif
  236. }
  237. static ssize_t cb_buffer_write(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) {
  238. uint8_t *a = ctx->a, *b = ctx->b;
  239. ssize_t avail = b-a;
  240. if (size < 0 || size > avail) return -1;
  241. ctx->a = a+size;
  242. *buffer = a;
  243. return avail;
  244. }
  245. static ssize_t cb_buffer_dont_write(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) {
  246. (void)ctx;
  247. *buffer = NULL;
  248. if (size) return -1;
  249. return 0;
  250. }
  251. const strobe_io_callbacks_s strobe_io_cb_buffer = {
  252. (ssize_t (*)(strobe_io_ctx_s *, const uint8_t **, ssize_t))cb_buffer_write, cb_buffer_write
  253. }, strobe_io_cb_const_buffer = {
  254. (ssize_t (*)(strobe_io_ctx_s *, const uint8_t **, ssize_t))cb_buffer_write, cb_buffer_dont_write
  255. };
  256. void strobe_init (
  257. struct strobe_s *__restrict__ strobe,
  258. const uint8_t *description,
  259. size_t desclen
  260. ) {
  261. const uint8_t proto[18] = {
  262. 1,RATE+PAD_BYTES,
  263. 1,0, /* Empty NIST perso string */
  264. 1,12*8, /* 12 = strlen("STROBEvX.Y.Z") */
  265. 'S','T','R','O','B','E',
  266. 'v',
  267. '0'+STROBE_INTEROP_V_MAJOR,'.',
  268. '0'+STROBE_INTEROP_V_MINOR,'.',
  269. '0'+STROBE_INTEROP_V_PATCH,
  270. /* Rest is 0s, which is already there because we memset it */
  271. };
  272. memset(strobe,0,sizeof(*strobe));
  273. memcpy(strobe,proto,sizeof(proto));
  274. keccak_f(&strobe->state);
  275. strobe_duplex(strobe,FLAG_A|FLAG_M,(uint8_t*)description,desclen);
  276. }
  277. #if STROBE_SUPPORT_PRNG
  278. #if STROBE_SINGLE_THREAD
  279. static strobe_t tl_prng = {{{{0}},0,0,0,NULL,{NULL,NULL
  280. #if STROBE_IO_CTX_HAS_FD
  281. ,0
  282. #endif
  283. }}};
  284. #else
  285. static _Thread_local strobe_t tl_prng = {{{{0}},0,0,0,NULL,{NULL,NULL
  286. #if STROBE_IO_CTX_HAS_FD
  287. ,0
  288. #endif
  289. }}};
  290. #endif
  291. #define FLAG_PRNG_INITED (1<<4)
  292. #define FLAG_PRNG_SEEDED (1<<5)
  293. int strobe_randomize(uint8_t *data, ssize_t len) {
  294. if (!(tl_prng->flags & FLAG_PRNG_SEEDED)) {
  295. return -1;
  296. }
  297. #if STROBE_SUPPORT_POST_FLAGS
  298. strobe_get(tl_prng,HASH|FLAG_POST_RATCHET,data,len);
  299. #else
  300. strobe_get(tl_prng,HASH,data,len);
  301. strobe_operate(tl_prng, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  302. #endif
  303. return 0;
  304. }
  305. void strobe_seed_prng(const uint8_t *data, ssize_t len) {
  306. if (!(tl_prng->flags & FLAG_PRNG_INITED)) {
  307. strobe_init(tl_prng,(const uint8_t *)"prng",4);
  308. }
  309. #if STROBE_SUPPORT_POST_FLAGS
  310. strobe_put(tl_prng,SYM_KEY|FLAG_POST_RATCHET,data,len);
  311. #else
  312. strobe_put(tl_prng,SYM_KEY,data,len);
  313. strobe_operate(tl_prng, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  314. #endif
  315. tl_prng->flags |= (FLAG_PRNG_INITED | FLAG_PRNG_SEEDED);
  316. }
  317. #endif
  318. #if X25519_SUPPORT_VERIFY
  319. int strobe_session_verify (
  320. strobe_t strobe,
  321. const uint8_t their_pubkey[EC_PUBLIC_BYTES]
  322. ) {
  323. uint8_t nonce[EC_PUBLIC_BYTES], chal[EC_CHALLENGE_BYTES], resp[EC_PRIVATE_BYTES];
  324. /* TODO: use SIG_SCHEME to identify the signature scheme */
  325. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), their_pubkey, EC_PUBLIC_BYTES);
  326. TRY( strobe_get(strobe, SIG_EPH, nonce, EC_PUBLIC_BYTES) );
  327. strobe_get(strobe, SIG_CHALLENGE, chal, EC_CHALLENGE_BYTES);
  328. TRY( strobe_get(strobe, SIG_RESPONSE, resp, EC_PRIVATE_BYTES) );
  329. return x25519_verify_p2(resp, chal, nonce, their_pubkey);
  330. }
  331. #if STROBE_SUPPORT_CERT_VERIFY
  332. int strobe_session_dont_verify (
  333. strobe_t strobe,
  334. const uint8_t their_pubkey[EC_PUBLIC_BYTES]
  335. ) {
  336. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), their_pubkey, EC_PUBLIC_BYTES);
  337. TRY( strobe_get(strobe, SIG_EPH, NULL, EC_PUBLIC_BYTES) );
  338. strobe_get(strobe, SIG_CHALLENGE, NULL, EC_CHALLENGE_BYTES);
  339. return strobe_get(strobe, SIG_RESPONSE, NULL, EC_PRIVATE_BYTES);
  340. }
  341. #endif
  342. #endif
  343. #if X25519_SUPPORT_SIGN
  344. int strobe_session_sign (
  345. strobe_t strobe,
  346. const uint8_t my_seckey[EC_PRIVATE_BYTES],
  347. const uint8_t my_pubkey[EC_PUBLIC_BYTES]
  348. ) {
  349. uint8_t nonce[EC_PUBLIC_BYTES], chal[EC_CHALLENGE_BYTES], resp[EC_UNIFORM_BYTES];
  350. uint8_t *const eph_secret = resp;
  351. /* The eph secret is put into resp; responding to it conveniently overwrites that. */
  352. /* FUTURE: an option not to put in public key, eg if it's already known to be
  353. * in the session log
  354. */
  355. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), my_pubkey, EC_PUBLIC_BYTES);
  356. /* OK, sample the randomness */
  357. #if X25519_DETERMINISTIC_SIGS
  358. {
  359. strobe_t too;
  360. memcpy(too,strobe,sizeof(too));
  361. strobe_put(too,SYM_KEY,my_seckey,EC_PRIVATE_BYTES);
  362. strobe_get(too,HASH,eph_secret,EC_UNIFORM_BYTES);
  363. strobe_destroy(too);
  364. }
  365. #else
  366. TRY( strobe_randomize(eph_secret,EC_PRIVATE_BYTES) );
  367. #endif
  368. /* Nonce = g^eph */
  369. x25519_base_uniform(nonce,resp);
  370. TRY( strobe_put(strobe, SIG_EPH, nonce, EC_PUBLIC_BYTES) );
  371. /* Get the challenge */
  372. strobe_get(strobe, SIG_CHALLENGE, chal, EC_CHALLENGE_BYTES);
  373. /* Respond */
  374. x25519_sign_p2 (resp, chal, eph_secret, my_seckey);
  375. TRY( strobe_put(strobe, SIG_RESPONSE, resp, EC_PRIVATE_BYTES) );
  376. #if EC_UNIFORM_BYTES > EC_PRIVATE_BYTES
  377. /* Doesn't happen for Curve25519, but clear the high bytes of the nonce
  378. * if they're not overwritten. */
  379. memset(resp,0,sizeof(resp));
  380. #endif
  381. return 0;
  382. }
  383. #endif
  384. #if STROBE_CONVENIENCE_ECDH
  385. int strobe_eph_ecdh (
  386. strobe_t strobe,
  387. int i_go_first
  388. ) {
  389. uint8_t e_pub[EC_PUBLIC_BYTES], e_sec[EC_PRIVATE_BYTES], e_oth[EC_PUBLIC_BYTES];
  390. /* SEND EPH */
  391. TRY( strobe_randomize(e_sec,sizeof(e_sec)) );
  392. x25519_base(e_pub,e_sec,1);
  393. if (i_go_first)
  394. TRY( strobe_put(strobe, KEM_EPH, e_pub, sizeof(e_pub)) );
  395. /* RECV EPH */
  396. TRY( strobe_get(strobe, KEM_EPH, e_oth, sizeof(e_oth)) );
  397. /* SEND EPH */
  398. if (!i_go_first)
  399. TRY( strobe_put(strobe, KEM_EPH, e_pub, sizeof(e_pub)) );
  400. /* ECDH */
  401. TRY( x25519(e_pub, e_sec, e_oth, 1) );
  402. strobe_operate(strobe, KEM_RESULT, e_pub, sizeof(e_pub));
  403. return 0;
  404. }
  405. #endif // STROBE_CONVENIENCE_ECDH