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.
 
 
 
 
 
 

453 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. if (flags & FLAG_NO_DATA) return 0;
  194. return strobe_duplex(strobe, flags, inside, len);
  195. }
  196. ssize_t __attribute__((noinline)) strobe_operate (
  197. strobe_s *__restrict__ strobe,
  198. uint32_t flags,
  199. uint8_t *inside,
  200. ssize_t len
  201. ) {
  202. #if STROBE_SUPPORT_FLAG_POST
  203. int ret;
  204. TRY(( ret = strobe_operate_0(strobe, flags, inside, len) ));
  205. if (flags & FLAG_POST_RATCHET) {
  206. assert(!(flags & FLAG_MORE));
  207. strobe_operate_0(strobe, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  208. }
  209. if (flags & FLAG_POST_MAC) {
  210. assert(!(flags & FLAG_MORE));
  211. control_word_t cwmac = MAC | (flags & (FLAG_I | FLAG_META_I | FLAG_META_T));
  212. TRY( strobe_operate_0(strobe, cwmac, NULL, STROBE_INTEROP_MAC_BYTES) );
  213. }
  214. return ret;
  215. #else
  216. /* Not supporting FLAG_POST_RATCHET or FLAG_POST_MAC */
  217. return strobe_operate_0(strobe, flags, inside, len);
  218. #endif
  219. }
  220. static ssize_t cb_buffer_write(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) {
  221. uint8_t *a = ctx->a, *b = ctx->b;
  222. ssize_t avail = b-a;
  223. if (size < 0 || size > avail) return -1;
  224. ctx->a = a+size;
  225. *buffer = a;
  226. return avail;
  227. }
  228. static ssize_t cb_buffer_dont_write(strobe_io_ctx_s *ctx, uint8_t **buffer, ssize_t size) {
  229. (void)ctx;
  230. *buffer = NULL;
  231. if (size) return -1;
  232. return 0;
  233. }
  234. const strobe_io_callbacks_s strobe_io_cb_buffer = {
  235. (ssize_t (*)(strobe_io_ctx_s *, const uint8_t **, ssize_t))cb_buffer_write, cb_buffer_write
  236. }, strobe_io_cb_const_buffer = {
  237. (ssize_t (*)(strobe_io_ctx_s *, const uint8_t **, ssize_t))cb_buffer_write, cb_buffer_dont_write
  238. };
  239. void strobe_init (
  240. struct strobe_s *__restrict__ strobe,
  241. const uint8_t *description,
  242. size_t desclen
  243. ) {
  244. const uint8_t proto[18] = {
  245. 1,RATE+PAD_BYTES,
  246. 1,0, /* Empty NIST perso string */
  247. 1,12*8, /* 12 = strlen("STROBEvX.Y.Z") */
  248. 'S','T','R','O','B','E',
  249. 'v',
  250. '0'+STROBE_INTEROP_V_MAJOR,'.',
  251. '0'+STROBE_INTEROP_V_MINOR,'.',
  252. '0'+STROBE_INTEROP_V_PATCH,
  253. /* Rest is 0s, which is already there because we memset it */
  254. };
  255. memset(strobe,0,sizeof(*strobe));
  256. memcpy(strobe,proto,sizeof(proto));
  257. keccak_f(&strobe->state);
  258. strobe_duplex(strobe,FLAG_A|FLAG_M,(uint8_t*)description,desclen);
  259. }
  260. #if STROBE_SUPPORT_PRNG
  261. #if STROBE_SINGLE_THREAD
  262. static strobe_t tl_prng = {{{{0}},0,0,0,NULL,{NULL,NULL
  263. #if STROBE_IO_CTX_HAS_FD
  264. ,0
  265. #endif
  266. }}};
  267. #else
  268. static _Thread_local strobe_t tl_prng = {{{{0}},0,0,0,NULL,{NULL,NULL
  269. #if STROBE_IO_CTX_HAS_FD
  270. ,0
  271. #endif
  272. }}};
  273. #endif
  274. #define FLAG_PRNG_INITED (1<<4)
  275. #define FLAG_PRNG_SEEDED (1<<5)
  276. int strobe_randomize(uint8_t *data, ssize_t len) {
  277. if (!(tl_prng->flags & FLAG_PRNG_SEEDED)) {
  278. return -1;
  279. }
  280. #if STROBE_SUPPORT_POST_FLAGS
  281. strobe_get(tl_prng,HASH|FLAG_POST_RATCHET,data,len);
  282. #else
  283. strobe_get(tl_prng,HASH,data,len);
  284. strobe_operate(tl_prng, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  285. #endif
  286. return 0;
  287. }
  288. void strobe_seed_prng(const uint8_t *data, ssize_t len) {
  289. if (!(tl_prng->flags & FLAG_PRNG_INITED)) {
  290. strobe_init(tl_prng,(const uint8_t *)"prng",4);
  291. }
  292. #if STROBE_SUPPORT_POST_FLAGS
  293. strobe_put(tl_prng,SYM_KEY|FLAG_POST_RATCHET,data,len);
  294. #else
  295. strobe_put(tl_prng,SYM_KEY,data,len);
  296. strobe_operate(tl_prng, RATCHET, NULL, STROBE_INTEROP_RATCHET_BYTES);
  297. #endif
  298. tl_prng->flags |= (FLAG_PRNG_INITED | FLAG_PRNG_SEEDED);
  299. }
  300. #endif
  301. #if X25519_SUPPORT_VERIFY
  302. int strobe_session_verify (
  303. strobe_t strobe,
  304. const uint8_t their_pubkey[EC_PUBLIC_BYTES]
  305. ) {
  306. uint8_t nonce[EC_PUBLIC_BYTES], chal[EC_CHALLENGE_BYTES], resp[EC_PRIVATE_BYTES];
  307. /* TODO: use SIG_SCHEME to identify the signature scheme */
  308. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), their_pubkey, EC_PUBLIC_BYTES);
  309. TRY( strobe_get(strobe, SIG_EPH, nonce, EC_PUBLIC_BYTES) );
  310. strobe_get(strobe, SIG_CHALLENGE, chal, EC_CHALLENGE_BYTES);
  311. TRY( strobe_get(strobe, SIG_RESPONSE, resp, EC_PRIVATE_BYTES) );
  312. return x25519_verify_p2(resp, chal, nonce, their_pubkey);
  313. }
  314. #if STROBE_SUPPORT_CERT_VERIFY
  315. int strobe_session_dont_verify (
  316. strobe_t strobe,
  317. const uint8_t their_pubkey[EC_PUBLIC_BYTES]
  318. ) {
  319. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), their_pubkey, EC_PUBLIC_BYTES);
  320. TRY( strobe_get(strobe, SIG_EPH, NULL, EC_PUBLIC_BYTES) );
  321. strobe_get(strobe, SIG_CHALLENGE, NULL, EC_CHALLENGE_BYTES);
  322. return strobe_get(strobe, SIG_RESPONSE, NULL, EC_PRIVATE_BYTES);
  323. }
  324. #endif
  325. #endif
  326. #if X25519_SUPPORT_SIGN
  327. int strobe_session_sign (
  328. strobe_t strobe,
  329. const uint8_t my_seckey[EC_PRIVATE_BYTES],
  330. const uint8_t my_pubkey[EC_PUBLIC_BYTES]
  331. ) {
  332. uint8_t nonce[EC_PUBLIC_BYTES], chal[EC_CHALLENGE_BYTES], resp[EC_UNIFORM_BYTES];
  333. uint8_t *const eph_secret = resp;
  334. /* The eph secret is put into resp; responding to it conveniently overwrites that. */
  335. /* FUTURE: an option not to put in public key, eg if it's already known to be
  336. * in the session log
  337. */
  338. strobe_put(strobe, MAKE_IMPLICIT(PUBLIC_KEY), my_pubkey, EC_PUBLIC_BYTES);
  339. /* OK, sample the randomness */
  340. #if X25519_DETERMINISTIC_SIGS
  341. {
  342. strobe_t too;
  343. memcpy(too,strobe,sizeof(too));
  344. strobe_put(too,SYM_KEY,my_seckey,EC_PRIVATE_BYTES);
  345. strobe_get(too,HASH,eph_secret,EC_UNIFORM_BYTES);
  346. strobe_destroy(too);
  347. }
  348. #else
  349. TRY( strobe_randomize(eph_secret,EC_PRIVATE_BYTES) );
  350. #endif
  351. /* Nonce = g^eph */
  352. x25519_base_uniform(nonce,resp);
  353. TRY( strobe_put(strobe, SIG_EPH, nonce, EC_PUBLIC_BYTES) );
  354. /* Get the challenge */
  355. strobe_get(strobe, SIG_CHALLENGE, chal, EC_CHALLENGE_BYTES);
  356. /* Respond */
  357. x25519_sign_p2 (resp, chal, eph_secret, my_seckey);
  358. TRY( strobe_put(strobe, SIG_RESPONSE, resp, EC_PRIVATE_BYTES) );
  359. #if EC_UNIFORM_BYTES > EC_PRIVATE_BYTES
  360. /* Doesn't happen for Curve25519, but clear the high bytes of the nonce
  361. * if they're not overwritten. */
  362. memset(resp,0,sizeof(resp));
  363. #endif
  364. return 0;
  365. }
  366. #endif
  367. #if STROBE_CONVENIENCE_ECDH
  368. int strobe_eph_ecdh (
  369. strobe_t strobe,
  370. int i_go_first
  371. ) {
  372. uint8_t e_pub[EC_PUBLIC_BYTES], e_sec[EC_PRIVATE_BYTES], e_oth[EC_PUBLIC_BYTES];
  373. /* SEND EPH */
  374. TRY( strobe_randomize(e_sec,sizeof(e_sec)) );
  375. x25519_base(e_pub,e_sec,1);
  376. if (i_go_first)
  377. TRY( strobe_put(strobe, KEM_EPH, e_pub, sizeof(e_pub)) );
  378. /* RECV EPH */
  379. TRY( strobe_get(strobe, KEM_EPH, e_oth, sizeof(e_oth)) );
  380. /* SEND EPH */
  381. if (!i_go_first)
  382. TRY( strobe_put(strobe, KEM_EPH, e_pub, sizeof(e_pub)) );
  383. /* ECDH */
  384. TRY( x25519(e_pub, e_sec, e_oth, 1) );
  385. strobe_operate(strobe, KEM_RESULT, e_pub, sizeof(e_pub));
  386. return 0;
  387. }
  388. #endif // STROBE_CONVENIENCE_ECDH