Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

453 linhas
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