Reference implementations of PQC
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.
 
 
 
 

264 lines
7.8 KiB

  1. #include "api.h"
  2. #include "randombytes.h"
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #ifndef NTESTS
  8. #define NTESTS 5
  9. #endif
  10. const uint8_t canary[8] = {
  11. 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF
  12. };
  13. /* allocate a bit more for all keys and messages and
  14. * make sure it is not touched by the implementations.
  15. */
  16. static void write_canary(uint8_t *d) {
  17. for (size_t i = 0; i < 8; i++) {
  18. d[i] = canary[i];
  19. }
  20. }
  21. static int check_canary(const uint8_t *d) {
  22. for (size_t i = 0; i < 8; i++) {
  23. if (d[i] != canary[i]) {
  24. return -1;
  25. }
  26. }
  27. return 0;
  28. }
  29. inline static void* malloc_s(size_t size) {
  30. void *ptr = malloc(size);
  31. if (ptr == NULL) {
  32. perror("Malloc failed!");
  33. exit(1);
  34. }
  35. return ptr;
  36. }
  37. // https://stackoverflow.com/a/1489985/1711232
  38. #define PASTER(x, y) x##_##y
  39. #define EVALUATOR(x, y) PASTER(x, y)
  40. #define NAMESPACE(fun) EVALUATOR(PQCLEAN_NAMESPACE, fun)
  41. #define CRYPTO_BYTES NAMESPACE(CRYPTO_BYTES)
  42. #define CRYPTO_PUBLICKEYBYTES NAMESPACE(CRYPTO_PUBLICKEYBYTES)
  43. #define CRYPTO_SECRETKEYBYTES NAMESPACE(CRYPTO_SECRETKEYBYTES)
  44. #define CRYPTO_CIPHERTEXTBYTES NAMESPACE(CRYPTO_CIPHERTEXTBYTES)
  45. #define CRYPTO_ALGNAME NAMESPACE(CRYPTO_ALGNAME)
  46. #define crypto_kem_keypair NAMESPACE(crypto_kem_keypair)
  47. #define crypto_kem_enc NAMESPACE(crypto_kem_enc)
  48. #define crypto_kem_dec NAMESPACE(crypto_kem_dec)
  49. #define RETURNS_ZERO(f) \
  50. if ((f) != 0) { \
  51. puts(#f " returned non-zero returncode"); \
  52. res = 1; \
  53. goto end; \
  54. }
  55. // https://stackoverflow.com/a/55243651/248065
  56. #define MY_TRUTHY_VALUE_X 1
  57. #define CAT(x,y) CAT_(x,y)
  58. #define CAT_(x,y) x##y
  59. #define HAS_NAMESPACE(x) CAT(CAT(MY_TRUTHY_VALUE_,CAT(PQCLEAN_NAMESPACE,CAT(_,x))),X)
  60. #if !HAS_NAMESPACE(API_H)
  61. #error "namespace not properly defined for header guard"
  62. #endif
  63. static int test_keys(void) {
  64. /*
  65. * This is most likely going to be aligned by the compiler.
  66. * 16 extra bytes for canary
  67. * 1 extra byte for unalignment
  68. */
  69. int res = 0;
  70. uint8_t *key_a_aligned = malloc_s(CRYPTO_BYTES + 16 + 1);
  71. uint8_t *key_b_aligned = malloc_s(CRYPTO_BYTES + 16 + 1);
  72. uint8_t *pk_aligned = malloc_s(CRYPTO_PUBLICKEYBYTES + 16 + 1);
  73. uint8_t *sendb_aligned = malloc_s(CRYPTO_CIPHERTEXTBYTES + 16 + 1);
  74. uint8_t *sk_a_aligned = malloc_s(CRYPTO_SECRETKEYBYTES + 16 + 1);
  75. /*
  76. * Make sure all pointers are odd.
  77. * This ensures that the implementation does not assume anything about the
  78. * data alignment. For example this would catch if an implementation
  79. * directly uses these pointers to load into vector registers using movdqa.
  80. */
  81. uint8_t *key_a = (uint8_t *) ((uintptr_t) key_a_aligned|(uintptr_t) 1);
  82. uint8_t *key_b = (uint8_t *) ((uintptr_t) key_b_aligned|(uintptr_t) 1);
  83. uint8_t *pk = (uint8_t *) ((uintptr_t) pk_aligned|(uintptr_t) 1);
  84. uint8_t *sendb = (uint8_t *) ((uintptr_t) sendb_aligned|(uintptr_t) 1);
  85. uint8_t *sk_a = (uint8_t *) ((uintptr_t) sk_a_aligned|(uintptr_t) 1);
  86. /*
  87. * Write 8 byte canary before and after the actual memory regions.
  88. * This is used to validate that the implementation does not assume
  89. * anything about the placement of data in memory
  90. * (e.g., assuming that the pk is always behind the sk)
  91. */
  92. write_canary(key_a);
  93. write_canary(key_a + CRYPTO_BYTES + 8);
  94. write_canary(key_b);
  95. write_canary(key_b + CRYPTO_BYTES + 8);
  96. write_canary(pk);
  97. write_canary(pk + CRYPTO_PUBLICKEYBYTES + 8);
  98. write_canary(sendb);
  99. write_canary(sendb + CRYPTO_CIPHERTEXTBYTES + 8);
  100. write_canary(sk_a);
  101. write_canary(sk_a + CRYPTO_SECRETKEYBYTES + 8);
  102. int i;
  103. for (i = 0; i < NTESTS; i++) {
  104. // Alice generates a public key
  105. RETURNS_ZERO(crypto_kem_keypair(pk + 8, sk_a + 8));
  106. // Bob derives a secret key and creates a response
  107. RETURNS_ZERO(crypto_kem_enc(sendb + 8, key_b + 8, pk + 8));
  108. // Alice uses Bobs response to get her secret key
  109. RETURNS_ZERO(crypto_kem_dec(key_a + 8, sendb + 8, sk_a + 8));
  110. if (memcmp(key_a + 8, key_b + 8, CRYPTO_BYTES) != 0) {
  111. printf("ERROR KEYS\n");
  112. res = 1;
  113. goto end;
  114. }
  115. // Validate that the implementation did not touch the canary
  116. if (check_canary(key_a) || check_canary(key_a + CRYPTO_BYTES + 8) ||
  117. check_canary(key_b) || check_canary(key_b + CRYPTO_BYTES + 8 ) ||
  118. check_canary(pk) || check_canary(pk + CRYPTO_PUBLICKEYBYTES + 8 ) ||
  119. check_canary(sendb) || check_canary(sendb + CRYPTO_CIPHERTEXTBYTES + 8 ) ||
  120. check_canary(sk_a) || check_canary(sk_a + CRYPTO_SECRETKEYBYTES + 8 )) {
  121. printf("ERROR canary overwritten\n");
  122. res = 1;
  123. goto end;
  124. }
  125. }
  126. end:
  127. free(key_a_aligned);
  128. free(key_b_aligned);
  129. free(pk_aligned);
  130. free(sendb_aligned);
  131. free(sk_a_aligned);
  132. return res;
  133. }
  134. static int test_invalid_sk_a(void) {
  135. uint8_t *sk_a = malloc_s(CRYPTO_SECRETKEYBYTES);
  136. uint8_t *key_a = malloc_s(CRYPTO_BYTES);
  137. uint8_t *key_b = malloc_s(CRYPTO_BYTES);
  138. uint8_t *pk = malloc_s(CRYPTO_PUBLICKEYBYTES);
  139. uint8_t *sendb = malloc_s(CRYPTO_CIPHERTEXTBYTES);
  140. int i;
  141. int returncode;
  142. int res = 0;
  143. for (i = 0; i < NTESTS; i++) {
  144. // Alice generates a public key
  145. RETURNS_ZERO(crypto_kem_keypair(pk, sk_a));
  146. // Bob derives a secret key and creates a response
  147. RETURNS_ZERO(crypto_kem_enc(sendb, key_b, pk));
  148. // Replace secret key with random values
  149. randombytes(sk_a, CRYPTO_SECRETKEYBYTES);
  150. // Alice uses Bobs response to get her secret key
  151. if ((returncode = crypto_kem_dec(key_a, sendb, sk_a)) > 0) {
  152. printf("ERROR failing crypto_kem_dec returned %d instead of "
  153. "negative or zero code\n",
  154. returncode);
  155. res = 1;
  156. goto end;
  157. }
  158. if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
  159. printf("ERROR invalid sk_a\n");
  160. res = 1;
  161. goto end;
  162. }
  163. }
  164. end:
  165. free(sk_a);
  166. free(key_a);
  167. free(key_b);
  168. free(pk);
  169. free(sendb);
  170. return res;
  171. }
  172. static int test_invalid_ciphertext(void) {
  173. uint8_t *sk_a = malloc_s(CRYPTO_SECRETKEYBYTES);
  174. uint8_t *key_a = malloc_s(CRYPTO_BYTES);
  175. uint8_t *key_b = malloc_s(CRYPTO_BYTES);
  176. uint8_t *pk = malloc_s(CRYPTO_PUBLICKEYBYTES);
  177. uint8_t *sendb = malloc_s(CRYPTO_CIPHERTEXTBYTES);
  178. int i;
  179. int returncode;
  180. int res = 0;
  181. for (i = 0; i < NTESTS; i++) {
  182. // Alice generates a public key
  183. RETURNS_ZERO(crypto_kem_keypair(pk, sk_a));
  184. // Bob derives a secret key and creates a response
  185. RETURNS_ZERO(crypto_kem_enc(sendb, key_b, pk));
  186. // Change ciphertext to random value
  187. randombytes(sendb, sizeof(sendb));
  188. // Alice uses Bobs response to get her secret key
  189. if ((returncode = crypto_kem_dec(key_a, sendb, sk_a)) > 0) {
  190. printf("ERROR crypto_kem_dec should either fail (negative "
  191. "returncode) or succeed (return 0) but returned %d\n",
  192. returncode);
  193. res = 1;
  194. goto end;
  195. }
  196. if (!memcmp(key_a, key_b, CRYPTO_BYTES)) {
  197. printf("ERROR invalid ciphertext\n");
  198. res = 1;
  199. goto end;
  200. }
  201. }
  202. end:
  203. free(sk_a);
  204. free(key_a);
  205. free(key_b);
  206. free(pk);
  207. free(sendb);
  208. return res;
  209. }
  210. int main(void) {
  211. // Check if CRYPTO_ALGNAME is printable
  212. puts(CRYPTO_ALGNAME);
  213. int result = 0;
  214. result += test_keys();
  215. result += test_invalid_sk_a();
  216. result += test_invalid_ciphertext();
  217. if (result != 0) {
  218. puts("Errors occurred");
  219. }
  220. return result;
  221. }