diff options
-rw-r--r-- | content/posts/2023-10-07-c11-fips203ipd.md | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/content/posts/2023-10-07-c11-fips203ipd.md b/content/posts/2023-10-07-c11-fips203ipd.md new file mode 100644 index 0000000..cacd82e --- /dev/null +++ b/content/posts/2023-10-07-c11-fips203ipd.md @@ -0,0 +1,193 @@ +--- +slug: C11 Implementation of FIPS 203 IPD +title: "C11 FIPS 203" +date: "2023-10-07T12:19:48-04:00" +--- +I created a [C11][] implementation of the KEM512, KEM768, and KEM1024 +parameter sets from the [FIPS 203 initial public draft +(IPD)][fips203ipd]. + +[FIPS 203][fips203ipd] is (or will be) [NIST's][nist] standardized +version of [Kyber][], a post-quantum [key encapsulation mechanism +(KEM)][kem]. + +### Features + +* Full implementation of all three parameter sets from the [FIPS 203 + initial public draft][fips203ipd] +* [C11][], no external dependencies +* Test suite w/ common sanitizers enabled (`make test`) +* API documentation (`fips203ipd.h`) +* short example application (`examples/0-hello-kem/`). + +[Git Repository][github] + +**Note:** This is an initial release based on the draft standard with no +real optimization; it is slow and memory-intensive. + +**Another Note:** Worth reading before relying on any [Kyber][] +implementation: [2020.10.03: The inability to count +correctly][djb-kyber], by [Dan Bernstein (djb)][djb]. + +## Example + +This example application is also included in the [git +repository][github] as `examples/0-hello-kem/`. + +### Source + +```c +// +// hello.c: minimal example of a two parties "alice" and "bob" +// generating a shared secret with KEM512. +// +// Build by typing `make` and run by typing `./hello`. +// + +#include <stdio.h> // fputs() +#include <string.h> // memcmp() +#include "hex.h" // hex_write() +#include "rand-bytes.h" // rand_bytes() +#include "fips203ipd.h" // fips203ipd_*() + +int main(void) { + // + // alice: generate keypair + // + uint8_t ek[FIPS203IPD_KEM512_EK_SIZE] = { 0 }; // encapsulation key + uint8_t dk[FIPS203IPD_KEM512_DK_SIZE] = { 0 }; // decapsulation key + { + // alice: get 64 random bytes for keygen() + uint8_t keygen_seed[64] = { 0 }; + rand_bytes(keygen_seed, sizeof(keygen_seed)); + + fputs("alice: keygen random (64 bytes) = ", stdout); + hex_write(stdout, keygen_seed, sizeof(keygen_seed)); + fputs("\n", stdout); + + // alice: generate encapsulation/decapsulation key pair + fips203ipd_kem512_keygen(ek, dk, keygen_seed); + } + fputs("alice: generated encapsulation key `ek` and decapsulation key `dk`:\n", stdout); + printf("alice: ek (%d bytes) = ", FIPS203IPD_KEM512_EK_SIZE); + hex_write(stdout, ek, sizeof(ek)); + printf("\nalice: dk (%d bytes) = ", FIPS203IPD_KEM512_DK_SIZE); + hex_write(stdout, dk, sizeof(dk)); + fputs("\n", stdout); + + // alice send `ek` to bob + fputs("alice: sending encapsulation key `ek` to bob\n\n", stdout); + + // + // bob: generate shared secret and ciphertext + // + uint8_t b_key[32] = { 0 }; // shared secret + uint8_t ct[FIPS203IPD_KEM512_CT_SIZE] = { 0 }; // ciphertext + { + // bob: get 32 random bytes for encaps() + uint8_t encaps_seed[32] = { 0 }; + rand_bytes(encaps_seed, sizeof(encaps_seed)); + + fputs("bob: encaps random (32 bytes) = ", stdout); + hex_write(stdout, encaps_seed, sizeof(encaps_seed)); + fputs("\n", stdout); + + // bob: + // 1. get encapsulation key `ek` from alice. + // 2. generate random shared secret. + // 3. use `ek` from step #1 to encapsulate the shared secret from step #2. + // 3. store the shared secret in `b_key`. + // 4. store the encapsulated shared secret (ciphertext) in `ct`. + fips203ipd_kem512_encaps(b_key, ct, ek, encaps_seed); + } + + fputs("bob: generated secret `b_key` and ciphertext `ct`:\nbob: b_key (32 bytes) = ", stdout); + hex_write(stdout, b_key, sizeof(b_key)); + printf("\nbob: ct (%d bytes) = ", FIPS203IPD_KEM512_CT_SIZE); + hex_write(stdout, ct, sizeof(ct)); + fputs("\n", stdout); + + // bob sends ciphertext `ct` to alice + fputs("bob: sending ciphertext `ct` to alice\n\n", stdout); + + // + // alice: decapsulate shared secret + // + + // alice: + // 1. get ciphertext `ct` from bob. + // 2. use decapsultion key `dk` to decapsulate shared secret from `ct`. + // 2. store shared secret in `a_key`. + uint8_t a_key[32] = { 0 }; + fips203ipd_kem512_decaps(a_key, ct, dk); + + fputs("alice: used `dk` to decapsulate secret from `ct` into `a_key`:\nalice: a_key (32 bytes) = ", stdout); + hex_write(stdout, a_key, sizeof(a_key)); + fputs("\n\n", stdout); + + // check result + if (!memcmp(a_key, b_key, sizeof(a_key))) { + // success: alice and bob have the same shared secret + fputs("SUCCESS! alice secret `a_key` and bob secret `b_key` match.\n", stdout); + return 0; + } else { + // failure: alice and bob do not have the same shared secret + fputs("FAILURE! alice secret `a_key` and bob secret `b_key` do not match.\n", stdout); + return -1; + } +} +``` + +### Output + +Output of `./hello` with longer lines truncated for brevity: + +```sh +alice: keygen random (64 bytes) = d656012a9eb09aa50e77a205188f0156e98276a584dcc11c2dfef0c06003ca38b233fab93e9f8dd5adec32278c8d091190112285b7389510bd610ec7b23376b2 +alice: generated encapsulation key `ek` and decapsulation key `dk`: +alice: ek (800 bytes) = af3b0497f6 ... (omitted) ... 31f0f62cbd +alice: dk (1632 bytes) = e598a49eb0 ... (omitted) ... c06003ca38 +alice: sending encapsulation key `ek` to bob + +bob: encaps random (32 bytes) = 0db6c39742ba8cb8d9a1c437d62fed4c7fa04e944a47a73a94426dd3c33e6213 +bob: generated secret `b_key` and ciphertext `ct`: +bob: b_key (32 bytes) = 32c9eb490db7e8500d9b209d78a9367fd73a967d8d58edff8655273c8d4ce8d5 +bob: ct (768 bytes) = bd39ae1157 ... (omitted) ... 9b5751fc34 +bob: sending ciphertext `ct` to alice + +alice: used `dk` to decapsulate secret from `ct` into `a_key`: +alice: a_key (32 bytes) = 32c9eb490db7e8500d9b209d78a9367fd73a967d8d58edff8655273c8d4ce8d5 + +SUCCESS! alice secret `a_key` and bob secret `b_key` match. +``` + +### + +[c11]: https://en.wikipedia.org/wiki/C11_(C_standard_revision) + "ISO/IEC 9899:2011" +[SHA-3]: https://en.wikipedia.org/wiki/SHA-3 + "Secure Hash Algorithm 3" +[sha3-mine]: https://github.com/pablotron/sha3 + "My FIPS 202 (SHA-3) implementation." +[fips203ipd]: https://csrc.nist.gov/pubs/fips/203/ipd + "FIPS 203 (Initial Public Draft): Module-Lattice-Based Key-Encapsulation Mechanism Standard" +[fips202]: https://csrc.nist.gov/pubs/fips/202/final + "SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions" +[pqc-forum-decode-comment]: https://groups.google.com/a/list.nist.gov/d/msgid/pqc-forum/ZRQvPT7kQ51NIRyJ%40disp3269 + "pqc-forum mailing list discussion about reducing coefficients modulo Q during deserialization." +[nist]: https://nist.gov/ + "National Institutes of Science and Technology" +[kyber]: https://pq-crystals.org/kyber/ + "Kyber: post-quantum key encapsulation mechanism based on the hardness of the module learning with errors (m-LWE) problem." +[kem]: https://en.wikipedia.org/wiki/Key_encapsulation_mechanism + "Key encapsulation mechanism." +[gcc]: https://en.wikipedia.org/wiki/GNU_Compiler_Collection + "GNU Compiler Collection." +[clang]: https://en.wikipedia.org/wiki/Clang + "LLVM compiler front end." +[github]: https://github.com/pablotron/fips203ipd + "fips203ipd github repository." +[djb-kyber]: https://blog.cr.yp.to/20231003-countcorrectly.html + "2023.10.03: The inability to count correctly, by Dan Bernstein." +[djb]: https://en.wikipedia.org/wiki/Daniel_J._Bernstein + "Daniel J. Bernstein" |