/* * example_kem.c * * Minimal example of a Diffie-Hellman-style post-quantum key encapsulation * implemented in liboqs. * */ #include #include #include #include #include /* Cleaning up memory etc */ void cleanup_stack(uint8_t *secret_key, size_t secret_key_len, uint8_t *shared_secret_e, uint8_t *shared_secret_d, size_t shared_secret_len); void cleanup_heap(uint8_t *secret_key, uint8_t *shared_secret_e, uint8_t *shared_secret_d, uint8_t *public_key, uint8_t *ciphertext, OQS_KEM *kem); /* This function gives an example of the operations performed by both * the decapsulator and the encapsulator in a single KEM session, * using only compile-time macros and allocating variables * statically on the stack, calling a specific algorithm's functions * directly. * * The macros OQS_KEM_frodokem_640_aes_length_* and the functions * OQS_KEM_frodokem_640_aes_* are only defined if the algorithm * FrodoKEM-640-AES was enabled at compile-time which must be * checked using the OQS_ENABLE_KEM_frodokem_640_aes macro. * * , which is included in , contains macros * indicating which algorithms were enabled when this instance of liboqs * was compiled. */ OQS_STATUS example_stack() { #ifndef OQS_ENABLE_KEM_frodokem_640_aes // if FrodoKEM-640-AES was not enabled at compile-time printf("[example_stack] OQS_KEM_frodokem_640_aes was not enabled at " "compile-time.\n"); return OQS_ERROR; #else uint8_t public_key[OQS_KEM_frodokem_640_aes_length_public_key]; uint8_t secret_key[OQS_KEM_frodokem_640_aes_length_secret_key]; uint8_t ciphertext[OQS_KEM_frodokem_640_aes_length_ciphertext]; uint8_t shared_secret_e[OQS_KEM_frodokem_640_aes_length_shared_secret]; uint8_t shared_secret_d[OQS_KEM_frodokem_640_aes_length_shared_secret]; OQS_STATUS rc = OQS_KEM_frodokem_640_aes_keypair(public_key, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_keypair failed!\n"); cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, shared_secret_e, shared_secret_d, OQS_KEM_frodokem_640_aes_length_shared_secret); return OQS_ERROR; } rc = OQS_KEM_frodokem_640_aes_encaps(ciphertext, shared_secret_e, public_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_encaps failed!\n"); cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, shared_secret_e, shared_secret_d, OQS_KEM_frodokem_640_aes_length_shared_secret); return OQS_ERROR; } rc = OQS_KEM_frodokem_640_aes_decaps(shared_secret_d, ciphertext, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_frodokem_640_aes_decaps failed!\n"); cleanup_stack(secret_key, OQS_KEM_frodokem_640_aes_length_secret_key, shared_secret_e, shared_secret_d, OQS_KEM_frodokem_640_aes_length_shared_secret); return OQS_ERROR; } printf("[example_stack] OQS_KEM_frodokem_640_aes operations completed.\n"); return OQS_SUCCESS; // success! #endif } /* This function gives an example of the operations performed by both * the decapsulator and the encapsulator in a single KEM session, * allocating variables dynamically on the heap and calling the generic * OQS_KEM object. * * This does not require the use of compile-time macros to check if the * algorithm in question was enabled at compile-time; instead, the caller * must check that the OQS_KEM object returned is not NULL. */ OQS_STATUS example_heap() { OQS_KEM *kem = NULL; uint8_t *public_key = NULL; uint8_t *secret_key = NULL; uint8_t *ciphertext = NULL; uint8_t *shared_secret_e = NULL; uint8_t *shared_secret_d = NULL; kem = OQS_KEM_new(OQS_KEM_alg_frodokem_640_aes); if (kem == NULL) { printf("[example_heap] OQS_KEM_frodokem_640_aes was not enabled at " "compile-time.\n"); return OQS_ERROR; } public_key = malloc(kem->length_public_key); secret_key = malloc(kem->length_secret_key); ciphertext = malloc(kem->length_ciphertext); shared_secret_e = malloc(kem->length_shared_secret); shared_secret_d = malloc(kem->length_shared_secret); if ((public_key == NULL) || (secret_key == NULL) || (ciphertext == NULL) || (shared_secret_e == NULL) || (shared_secret_d == NULL)) { fprintf(stderr, "ERROR: malloc failed!\n"); cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, ciphertext, kem); return OQS_ERROR; } OQS_STATUS rc = OQS_KEM_keypair(kem, public_key, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_keypair failed!\n"); cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, ciphertext, kem); return OQS_ERROR; } rc = OQS_KEM_encaps(kem, ciphertext, shared_secret_e, public_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_encaps failed!\n"); cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, ciphertext, kem); return OQS_ERROR; } rc = OQS_KEM_decaps(kem, shared_secret_d, ciphertext, secret_key); if (rc != OQS_SUCCESS) { fprintf(stderr, "ERROR: OQS_KEM_decaps failed!\n"); cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, ciphertext, kem); return OQS_ERROR; } printf("[example_heap] OQS_KEM_frodokem_640_aes operations completed.\n"); cleanup_heap(secret_key, shared_secret_e, shared_secret_d, public_key, ciphertext, kem); return OQS_SUCCESS; // success } int main(void) { if (example_stack() == OQS_SUCCESS && example_heap() == OQS_SUCCESS) { return EXIT_SUCCESS; } else { return EXIT_FAILURE; } } void cleanup_stack(uint8_t *secret_key, size_t secret_key_len, uint8_t *shared_secret_e, uint8_t *shared_secret_d, size_t shared_secret_len) { OQS_MEM_cleanse(secret_key, secret_key_len); OQS_MEM_cleanse(shared_secret_e, shared_secret_len); OQS_MEM_cleanse(shared_secret_d, shared_secret_len); } void cleanup_heap(uint8_t *secret_key, uint8_t *shared_secret_e, uint8_t *shared_secret_d, uint8_t *public_key, uint8_t *ciphertext, OQS_KEM *kem) { if (kem != NULL) { OQS_MEM_secure_free(secret_key, kem->length_secret_key); OQS_MEM_secure_free(shared_secret_e, kem->length_shared_secret); OQS_MEM_secure_free(shared_secret_d, kem->length_shared_secret); } OQS_MEM_insecure_free(public_key); OQS_MEM_insecure_free(ciphertext); OQS_KEM_free(kem); }