1.. _module-pw_crypto: 2 3========= 4pw_crypto 5========= 6.. pigweed-module:: 7 :name: pw_crypto 8 9A set of safe (read: easy to use, hard to misuse) crypto APIs. 10 11The following crypto services are provided by this module. 12 131. Hashing a message with `SHA256`_. 142. Verifying a digital signature signed with `ECDSA`_ over the NIST P256 curve. 153. Many more to come ... 16 17------ 18SHA256 19------ 201. Obtaining a oneshot digest. 21 22.. code-block:: cpp 23 24 #include "pw_crypto/sha256.h" 25 26 std::byte digest[32]; 27 if (!pw::crypto::sha256::Hash(message, digest).ok()) { 28 // Handle errors. 29 } 30 31 // The content can also come from a pw::stream::Reader. 32 if (!pw::crypto::sha256::Hash(reader, digest).ok()) { 33 // Handle errors. 34 } 35 362. Hashing a long, potentially non-contiguous message. 37 38.. code-block:: cpp 39 40 #include "pw_crypto/sha256.h" 41 42 std::byte digest[32]; 43 44 if (!pw::crypto::sha256::Sha256() 45 .Update(chunk1).Update(chunk2).Update(chunk...) 46 .Final().ok()) { 47 // Handle errors. 48 } 49 50----- 51ECDSA 52----- 531. Verifying a digital signature signed with ECDSA over the NIST P256 curve. 54 55.. code-block:: cpp 56 57 #include "pw_crypto/sha256.h" 58 59 std::byte digest[32]; 60 if (!pw::crypto::sha256::Hash(message, digest).ok()) { 61 // handle errors. 62 } 63 64 if (!pw::crypto::ecdsa::VerifyP256Signature(public_key, digest, 65 signature).ok()) { 66 // handle errors. 67 } 68 692. Verifying a digital signature signed with ECDSA over the NIST P256 curve, 70 with a long and/or non-contiguous message. 71 72.. code-block:: cpp 73 74 #include "pw_crypto/sha256.h" 75 76 std::byte digest[32]; 77 78 if (!pw::crypto::sha256::Sha256() 79 .Update(chunk1).Update(chunk2).Update(chunkN) 80 .Final(digest).ok()) { 81 // Handle errors. 82 } 83 84 if (!pw::crypto::ecdsa::VerifyP256Signature(public_key, digest, 85 signature).ok()) { 86 // Handle errors. 87 } 88 89--- 90AES 91--- 92 931. Computing the AES-CMAC of a potentially long and/or non-contiguous message. 94 This is similar to a hash or digest except that the operation takes a secret 95 key as an input, so the MAC can be used to verify integrity and 96 authentication. 97 98.. code-block:: cpp 99 100 #include "pw_crypto/aes.h" 101 102 std::byte mac[16]; 103 104 if (!pw::crypto::aes_cmac::Cmac(key).Update(chunk1).Update(chunk2) 105 .Update(chunk...).Final().ok()) { 106 // Handle errors. 107 } 108 1092. Encrypting a single AES 128-bit block. 110 111.. warning:: 112 This is a low-level operation. Users should know exactly what they are doing 113 and must ensure that this operation does not violate any safety bounds that 114 more refined operations usually ensure. 115 116.. code-block:: cpp 117 118 #include "pw_crypto/aes.h" 119 120 std::byte encrypted[16]; 121 122 if (!pw::crypto::unsafe::aes::EncryptBlock(key, message, encrypted).ok()) { 123 // Handle errors. 124 } 125 126------------- 127Configuration 128------------- 129The crypto services offered by pw_crypto can be backed by different backend 130crypto libraries. 131 132Mbed TLS 133======== 134The `Mbed TLS project <https://www.trustedfirmware.org/projects/mbed-tls/>`_ 135is a mature and full-featured crypto library that implements cryptographic 136primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. 137 138The project also has good support for interfacing to cryptographic accelerators. 139 140The small code footprint makes the project suitable and popular for embedded 141systems. 142 143To select the Mbed TLS backend, the MbedTLS library needs to be installed and 144configured. If using GN, do, 145 146.. code-block:: sh 147 148 # Install and configure MbedTLS 149 pw package install mbedtls 150 gn gen out --args=' 151 dir_pw_third_party_mbedtls=getenv("PW_PACKAGE_ROOT")+"/mbedtls" 152 pw_crypto_SHA256_BACKEND="//pw_crypto:sha256_mbedtls_v3" 153 pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_mbedtls_v3" 154 pw_crypto_AES_BACKEND="//pw_crypto:aes_mbedtls_v3" 155 ' 156 157 ninja -C out 158 159If using Bazel, add the Mbed TLS repository to your WORKSPACE and select 160appropriate backends by adding them to your project's `platform 161<https://bazel.build/extending/platforms>`_: 162 163.. code-block:: python 164 165 platform( 166 name = "my_platform", 167 flags = [ 168 "@pigweed//pw_crypto:sha256_backend=@pigweed//pw_crypto:sha256_mbedtls_backend", 169 "@pigweed//pw_crypto:ecdsa_backend=@pigweed//pw_crypto:ecdsa_mbedtls_backend", 170 "@pigweed//pw_crypto:aes_backend=@pigweed//pw_crypto:aes_mbedtls_backend", 171 # ... other flags 172 ], 173 ) 174 175For optimal code size and/or performance, the Mbed TLS library can be configured 176per product. Mbed TLS configuration is achieved by turning on and off MBEDTLS_* 177options in a config.h file. See //third_party/mbedtls for how this is done. 178 179``pw::crypto::sha256`` does not need any special configuration as it uses the 180mbedtls_sha256_* APIs directly. However you can optionally turn on 181``MBEDTLS_SHA256_SMALLER`` to further reduce the code size to from 3KiB to 182~1.8KiB at a ~30% slowdown cost (Cortex-M4). 183 184.. code-block:: c 185 186 #define MBEDTLS_SHA256_SMALLER 187 188``pw::crypto::ecdsa`` requires the following minimum configurations which yields 189a code size of ~12KiB. 190 191.. code-block:: c 192 193 #define MBEDTLS_BIGNUM_C 194 #define MBEDTLS_ECP_C 195 #define MBEDTLS_ECDSA_C 196 // The ASN1 options are needed only because mbedtls considers and verifies 197 // them (in check_config.h) as dependencies of MBEDTLS_ECDSA_C. 198 #define MBEDTLS_ASN1_WRITE_C 199 #define MBEDTLS_ASN1_PARSE_C 200 #define MBEDTLS_ECP_NO_INTERNAL_RNG 201 #define MBEDTLS_ECP_DP_SECP256R1_ENABLED 202 203.. _module-pw_crypto-boringssl: 204 205BoringSSL 206========= 207The BoringSSL project (`source 208<https://cs.opensource.google/boringssl/boringssl>`_, `GitHub mirror 209<https://github.com/google/boringssl>`_) is a fork of OpenSSL maintained by 210Google. It is not especially designed to be embedded-friendly, but it is used as 211the SSL library in Chrome, Android, and other apps. It is likely better to use 212another backend such as Mbed-TLS for embedded targets unless your project needs 213BoringSSL specifically. 214 215To use the BoringSSL backend with a GN project, it needs to be installed and 216configured. To do that: 217 218.. code-block:: sh 219 220 # Install and configure BoringSSL 221 pw package install boringssl 222 gn gen out --args=' 223 dir_pw_third_party_boringssl=getenv("PW_PACKAGE_ROOT")+"/boringssl" 224 pw_crypto_AES_BACKEND="//pw_crypto:aes_boringssl" 225 ' 226 227 ninja -C out 228 229If using Bazel, add the BoringSSL repository to your WORKSPACE or MODULE.bazel 230and select appropriate backends by adding them to your project's `platform 231<https://bazel.build/extending/platforms>`_: 232 233.. code-block:: python 234 235 platform( 236 name = "my_platform", 237 constraint_values = [ 238 "@pigweed//pw_aes:aes_boringssl_backend", 239 # ... other constraint_values 240 ], 241 ) 242 243------------ 244Size Reports 245------------ 246Below are size reports for each crypto service. These vary across 247configurations. 248 249.. TODO: b/388905812 - Re-enable the size report. 250.. .. include:: size_report 251.. include:: ../size_report_notice 252 253------------- 254API reference 255------------- 256.. doxygenfunction:: pw::crypto::ecdsa::VerifyP256Signature(ConstByteSpan public_key, ConstByteSpan digest, ConstByteSpan signature) 257.. doxygenfunction:: pw::crypto::sha256::Hash(ConstByteSpan message, ByteSpan out_digest) 258.. doxygenfunction:: pw::crypto::sha256::Hash(stream::Reader& reader, ByteSpan out_digest) 259.. doxygenvariable:: pw::crypto::sha256::kDigestSizeBytes 260.. doxygenfunction:: pw::crypto::sha256::Sha256::Final(ByteSpan out_digest) 261.. doxygenfunction:: pw::crypto::sha256::Sha256::Update(ConstByteSpan data) 262.. doxygenenum:: pw::crypto::sha256::Sha256State 263