1 /* 2 * Copyright (c) 2017-2024, Texas Instruments Incorporated 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of Texas Instruments Incorporated nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 /*!**************************************************************************** 33 * @file ECDH.h 34 * 35 * @brief TI Driver for Elliptic Curve Diffie-Hellman key agreement scheme. 36 * 37 * @anchor ti_drivers_ECDH_Overview 38 * # Overview # 39 * 40 * Elliptic Curve Diffie-Hellman (ECDH) is a key agreement scheme between 41 * two parties based on the Diffie-Hellman key exchange protocol. 42 * 43 * It provides a means of generating a shared secret and derived symmetric key 44 * between the two parties over an insecure channel. 45 * 46 * It does not provide authentication. As such, it does not guarantee that the 47 * party you are exchanging keys with is truly the party you wish to establish a 48 * secured channel with. 49 * 50 * The two parties each generate a private key and a public key. The private key 51 * is a random integer in the interval [1, n - 1], where n is the order of a 52 * previously agreed upon curve. The public key is generated 53 * by multiplying the private key by the generator point of a previously agreed 54 * upon elliptic curve such as NISTP256 or Curve 25519. The public key is itself 55 * a point upon the elliptic curve. Each public key is then transmitted to the 56 * other party over a potentially insecure channel. The other party's public key 57 * is then multiplied with the private key, generating a shared secret. This 58 * shared secret is also a point on the curve. However, the entropy in the secret 59 * is not spread evenly throughout the shared secret. In order to generate one or more 60 * shared symmetric keys, the shared secret must be run through a key derivation 61 * function (KDF) that was previously agreed upon. Usually, only the X coordinate 62 * is processed in this way as it contains all the entropy of the shared secret and 63 * some curve implementations only provide the X coordinate. The key derivation function 64 * can take many forms, from simply hashing the X coordinate of the shared secret 65 * with SHA2 and truncating the result to generating multiple symmetric keys with 66 * HKDF, an HMAC based KDF. 67 * 68 * Key derivation functions in the context of symmetric key generation after 69 * elliptic curve based key exchange differ from KDFs used to generate keys from 70 * passwords a user provides in a login. Those KDFs such as bcrypt purposefully 71 * add additional computation to increase a system's resistance against brute 72 * force or dictionary attacks. 73 * 74 * @anchor ti_drivers_ECDH_Usage 75 * # Usage # 76 * 77 * ## Before starting an ECDH operation # 78 * 79 * Before starting an ECDH operation, the application must do the following: 80 * - Call ECDH_init() to initialize the driver 81 * - Call ECDH_Params_init() to initialize the ECDH_Params to default values. 82 * - Modify the ECDH_Params as desired 83 * - Call ECDH_open() to open an instance of the driver 84 * 85 * ## Generating your public-private key pair # 86 * To generate a public-private key pair for an agreed upon curve, the application 87 * must do the following: 88 * - Generate the keying material for the private key. This keying material must 89 * be an integer in the interval [1, n - 1], where n is the order of the curve. 90 * It can be stored in big-endian or little-endian format. 91 * The array should be the same length as the curve parameters of the curve used. 92 * The driver validates private keys against the provided curve by default. 93 * - Initialize the private key CryptoKey. CryptoKeys are opaque data structures and representations 94 * of keying material and its storage. Depending on how the keying material 95 * is stored (RAM or flash, key store), the CryptoKey must be 96 * initialized differently. The ECDH API can handle all types of CryptoKey. 97 * However, not all device-specific implementations support all types of CryptoKey. 98 * Devices without a key store will not support CryptoKeys with keying material 99 * stored in a key store for example. 100 * All devices support plaintext CryptoKeys. 101 * - Initialize a blank CryptoKey for the public key. The CryptoKey will keep track 102 * of where the keying material for the public key should be copied and how 103 * long it is. SEC 1-based big-endian format public keys should have key material twice the length 104 * of the private key plus one. Little-endian format public keys should have key material the 105 * length of the private key for Montgomery curve X-only public keys or have key material twice 106 * the length of the private for other curves 107 * - Initialize the ECDH_OperationGeneratePublicKey struct and then populate it. By 108 * default, big-endian public keys will be generated. 109 * - If using RFC 7748-style public keys, initialize the operation's public key 110 * data format to be ECDH_LITTLE_ENDIAN_KEY. 111 * - Call ECDH_generatePublicKey(). The generated keying material will be copied 112 * according the the CryptoKey passed in as the public key parameter. The CryptoKey 113 * will no longer be considered 'blank' after the operation. 114 * 115 * ## Calculating a shared secret # 116 * After trading public keys with the other party, the application should do the following 117 * to calculate the shared secret: 118 * - Initialize a CryptoKey as public key with the keying material received from the other 119 * party. 120 * - Initialize the private key CryptoKey with the key used to generate your 121 * public key. CryptoKeys are opaque data structures and representations 122 * of keying material and its storage. Depending on how the keying material 123 * is stored (RAM or flash, key store), the CryptoKey must be 124 * initialized differently. The ECDH API can handle all types of CryptoKey. 125 * However, not all device-specific implementations support all types of CryptoKey. 126 * Devices without a key store will not support CryptoKeys with keying material 127 * stored in a key store for example. 128 * All devices support plaintext CryptoKeys. 129 * - Initialize a blank CryptoKey with the same size as the previously initialized 130 * public key. 131 * - Initialize the ECDH_OperationComputeSharedSecret struct and then populate it. By 132 * default, big-endian input keys will be assumed and big-endian shared secrets 133 * will be generated. 134 * - If importing RFC 7748-style public keys, initialize the operation's key material 135 * endianess to be ECDH_LITTLE_ENDIAN_KEY. 136 * - Call ECDH_computeSharedSecret(). The shared secret will be copied to a location 137 * according to the shared secret CryptoKey passed to the function call. The driver 138 * will validate the supplied public key and reject invalid ones. 139 * 140 * ## Creating one or more symmetric keys from the shared secret # 141 * After calculating the shared secret between the application and the other party, 142 * the entropy in the shared secret must be evened out and stretched as needed. There are 143 * uncountable methods and algorithms to stretch an original seed entropy (the share secret) 144 * to generate symmetric keys. 145 * - Run the X coordinate of the resulting entropy through a key derivation function (KDF) 146 * 147 * ## After a key exchange # 148 * After the ECDH key exchange completes, the application should either start another operation 149 * or close the driver by calling ECDH_close() 150 * 151 * ## General usage # 152 * The API expects elliptic curves as defined in ti/drivers/cryptoutils/ecc/ECCParams.h. 153 * Several commonly used curves are provided. Check the device-specific ECDH documentation 154 * for curve type (short Weierstrass, Montgomery, Edwards) support for your device. 155 * ECDH support for a curve type on a device does not imply curve-type support for 156 * other ECC schemes. 157 * 158 * ## Key Formatting 159 * By default, the ECDH API expects the private and public keys to be formatted in 160 * big-endian format. The details of octet string formatting can be found in 161 * SEC 1: Elliptic Curve Cryptography. 162 * 163 * Private keys can be formatted as big-endian or little-endian integers of the same 164 * length as the curve length. 165 * 166 * Public keys and shared secrets are points on an elliptic curve. These points can 167 * be expressed in several ways. The most common one is in affine coordinates as an 168 * X,Y pair. 169 * This API uses points expressed in uncompressed affine coordinates by default. 170 * The big-endian format requires a formatting byte in the first byte of the 171 * public key. When using uncompressed affine coordinates, this is the value 172 * 0x04. 173 * The point itself is stored as a concatenated array of X followed by Y. 174 * X and Y maybe in big-endian or little-endian. Some implementations do not require or 175 * yield the Y coordinate for ECDH on certain curves. It is recommended that the full 176 * keying material buffer of twice the curve param length is used to facilitate 177 * code-reuse. Implementations that do not use the Y coordinate will zero-out 178 * the Y-coordinate whenever they write a point to the CryptoKey. 179 * 180 * If device-supported, Montgomery curves can be stored as their X-only format 181 * based on the RFC-7748 specification. Here, only the X coordinate is packed 182 * in little-endian integers of the same length as the curve length. 183 * 184 * This API accepts and returns the keying material of public keys according 185 * to the following table: 186 * 187 * | Curve Type | Keying Material Array | Array Length | 188 * |--------------------|-----------------------|----------------------------| 189 * | Short Weierstrass | [0x04, X, Y] | 1 + 2 * Curve Param Length | 190 * | Montgomery | [0x04, X, Y] | 1 + 2 * Curve Param Length | 191 * | Montgomery | [X] | Curve Param Length | 192 * | Edwards | [0x04, X, Y] | 1 + 2 * Curve Param Length | 193 * 194 * Note: This driver will automatically prune the private key according to 195 * RFC 7748 for the following curve: 196 * X25519 197 * 198 * @anchor ti_drivers_ECDH_Synopsis 199 * ## Synopsis 200 * @anchor ti_drivers_ECDH_Synopsis_Code 201 * @code 202 * // Import ECDH Driver definitions 203 * #include <ti/drivers/ECDH.h> 204 * 205 * ECDH_init(); 206 * 207 * // Since we are using default ECDH_Params, we just pass in NULL for that parameter. 208 * ecdhHandle = ECDH_open(0, NULL); 209 * 210 * // Initialize myPrivateKey and myPublicKey 211 * CryptoKeyPlaintext_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial)); 212 * CryptoKeyPlaintext_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial)); 213 * 214 * ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey); 215 * operationGeneratePublicKey.curve = &ECCParams_NISTP256; 216 * operationGeneratePublicKey.myPrivateKey = &myPrivateKey; 217 * operationGeneratePublicKey.myPublicKey = &myPublicKey; 218 * 219 * // Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial 220 * operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey); 221 * 222 * // Now send the content of myPublicKeyingMaterial to the other party, 223 * // receive their public key, and copy their public keying material to theirPublicKeyingMaterial 224 * 225 * // Initialize their public CryptoKey and the shared secret CryptoKey 226 * CryptoKeyPlaintext_initKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial)); 227 * CryptoKeyPlaintext_initBlankKey(&sharedSecret, sharedSecretKeyingMaterial, sizeof(sharedSecretKeyingMaterial)); 228 * 229 * // The ECC_NISTP256 struct is provided in ti/drivers/types/EccParams.h and the corresponding device-specific 230 * implementation ECDH_OperationComputeSharedSecret_init(&operationComputeSharedSecret); 231 * operationComputeSharedSecret.curve = &ECCParams_NISTP256; 232 * operationComputeSharedSecret.myPrivateKey = &myPrivateKey; 233 * operationComputeSharedSecret.theirPublicKey = &theirPublicKey; 234 * operationComputeSharedSecret.sharedSecret = &sharedSecret; 235 * 236 * // Compute the shared secret and copy it to sharedSecretKeyingMaterial 237 * operationResult = ECDH_computeSharedSecret(ecdhHandle, &operationComputeSharedSecret); 238 * 239 * // Close the driver 240 * ECDH_close(ecdhHandle); 241 * 242 * @endcode 243 * 244 * ## Synopsis for X25519 X-only key exchange 245 * @anchor ti_drivers_ECDH_X25519_Code 246 * @code 247 * // Import ECDH Driver definitions 248 * #include <ti/drivers/ECDH.h> 249 * 250 * ECDH_init(); 251 * 252 * // Since we are using default ECDH_Params, we just pass in NULL for that parameter. 253 * ecdhHandle = ECDH_open(0, NULL); 254 * 255 * // For CC27XX devices only, 256 * // Since the ECDH driver for CC27XX relies on one HW engine (the HSM) for all of its operations 257 * // If the HSM boot up sequence fails, ECDH_open() will return NULL. 258 * if (!ecdhHandle) { 259 * // Handle error 260 * } 261 * 262 * 263 * // Initialize myPrivateKey and myPublicKey 264 * CryptoKeyPlaintext_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial)); 265 * // Note that the public key size is only 32 bytes 266 * CryptoKeyPlaintext_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial)); 267 * 268 * ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey); 269 * operationGeneratePublicKey.curve = &ECCParams_Curve25519; 270 * operationGeneratePublicKey.myPrivateKey = &myPrivateKey; 271 * operationGeneratePublicKey.myPublicKey = &myPublicKey; 272 * // If generating public key in little-endian format, we use the following format: 273 * operationGeneratePublicKey.keyMaterialEndianness = ECDH_LITTLE_ENDIAN_KEY; 274 * 275 * // Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial 276 * operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey); 277 * 278 * // Now send the content of myPublicKeyingMaterial to the other party, 279 * // receive their public key, and copy their public keying material to theirPublicKeyingMaterial 280 * 281 * // Initialize their public CryptoKey and the shared secret CryptoKey 282 * CryptoKeyPlaintext_initKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial)); 283 * CryptoKeyPlaintext_initBlankKey(&sharedSecret, sharedSecretKeyingMaterial, sizeof(sharedSecretKeyingMaterial)); 284 * 285 * // The ECC_NISTP256 struct is provided in ti/drivers/types/EccParams.h and the corresponding device-specific 286 * implementation ECDH_OperationComputeSharedSecret_init(&operationComputeSharedSecret); 287 * operationComputeSharedSecret.curve = &ECCParams_Curve25519; 288 * operationComputeSharedSecret.myPrivateKey = &myPrivateKey; 289 * operationComputeSharedSecret.theirPublicKey = &theirPublicKey; 290 * operationComputeSharedSecret.sharedSecret = &sharedSecret; 291 * // If receiving and generating keys in little-endian format, we use the following format: 292 * operationComputeSharedSecret.keyMaterialEndianness = ECDH_LITTLE_ENDIAN_KEY; 293 * 294 * // Compute the shared secret and copy it to sharedSecretKeyingMaterial 295 * operationResult = ECDH_computeSharedSecret(ecdhHandle, &operationComputeSharedSecret); 296 * 297 * // Close the driver 298 * ECDH_close(ecdhHandle); 299 * 300 * @endcode 301 * 302 * @anchor ti_drivers_ECDH_Examples 303 * # Examples # 304 * 305 * ## ECDH exchange with plaintext CryptoKeys # 306 * 307 * @code 308 * 309 * #include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h> 310 * #include <ti/drivers/ECDH.h> 311 * 312 * #define CURVE_LENGTH 32 313 * 314 * ... 315 * 316 * // Our private key is 0x0000000000000000000000000000000000000000000000000000000000000001 317 * // In practice, this value should come from a TRNG, PRNG, PUF, or device-specific pre-seeded key 318 * uint8_t myPrivateKeyingMaterial[CURVE_LENGTH] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 319 * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 320 * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 321 * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; 322 * uint8_t myPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0}; 323 * uint8_t theirPublicKeyingMaterial[2 * CURVE_LENGTH + 1] = {0}; 324 * uint8_t sharedSecretKeyingMaterial[2 * CURVE_LENGTH + 1] = {0}; 325 * uint8_t symmetricKeyingMaterial[16] = {0}; 326 * 327 * CryptoKey myPrivateKey; 328 * CryptoKey myPublicKey; 329 * CryptoKey theirPublicKey; 330 * CryptoKey sharedSecret; 331 * CryptoKey symmetricKey; 332 * 333 * ECDH_Handle ecdhHandle; 334 * 335 * int_fast16_t operationResult; 336 * 337 * ECDH_OperationGeneratePublicKey operationGeneratePublicKey; 338 * 339 * // Since we are using default ECDH_Params, we just pass in NULL for that parameter. 340 * ecdhHandle = ECDH_open(0, NULL); 341 * 342 * if (!ecdhHandle) { 343 * // Handle error 344 * } 345 * 346 * // Initialize myPrivateKey and myPublicKey 347 * CryptoKeyPlaintext_initKey(&myPrivateKey, myPrivateKeyingMaterial, sizeof(myPrivateKeyingMaterial)); 348 * CryptoKeyPlaintext_initBlankKey(&myPublicKey, myPublicKeyingMaterial, sizeof(myPublicKeyingMaterial)); 349 * 350 * ECDH_OperationGeneratePublicKey_init(&operationGeneratePublicKey); 351 * operationGeneratePublicKey.curve = &ECCParams_NISTP256; 352 * operationGeneratePublicKey.myPrivateKey = &myPrivateKey; 353 * operationGeneratePublicKey.myPublicKey = &myPublicKey; 354 * 355 * // Generate the keying material for myPublicKey and store it in myPublicKeyingMaterial 356 * operationResult = ECDH_generatePublicKey(ecdhHandle, &operationGeneratePublicKey); 357 * 358 * if (operationResult != ECDH_STATUS_SUCCESS) { 359 * // Handle error 360 * } 361 * 362 * // Now send the content of myPublicKeyingMaterial to the other party, 363 * // receive their public key, and copy their public keying material and the 364 * // 0x04 byte to theirPublicKeyingMaterial 365 * 366 * // Initialise their public CryptoKey and the shared secret CryptoKey 367 * CryptoKeyPlaintext_initKey(&theirPublicKey, theirPublicKeyingMaterial, sizeof(theirPublicKeyingMaterial)); 368 * CryptoKeyPlaintext_initBlankKey(&sharedSecret, sharedSecretKeyingMaterial, sizeof(sharedSecretKeyingMaterial)); 369 * 370 * // The ECC_NISTP256 struct is provided in ti/drivers/types/EccParams.h and the corresponding device-specific 371 * implementation ECDH_OperationComputeSharedSecret_init(&operationComputeSharedSecret); 372 * operationComputeSharedSecret.curve = &ECCParams_NISTP256; 373 * operationComputeSharedSecret.myPrivateKey = &myPrivateKey; 374 * operationComputeSharedSecret.theirPublicKey = &theirPublicKey; 375 * operationComputeSharedSecret.sharedSecret = &sharedSecret; 376 * 377 * // Compute the shared secret and copy it to sharedSecretKeyingMaterial 378 * operationResult = ECDH_computeSharedSecret(ecdhHandle, &operationComputeSharedSecret); 379 * 380 * if (operationResult != ECDH_STATUS_SUCCESS) { 381 * // Handle error 382 * } 383 * 384 * CryptoKeyPlaintext_initBlankKey(&symmetricKey, symmetricKeyingMaterial, sizeof(symmetricKeyingMaterial)); 385 * 386 * // Set up a KDF such as HKDF and open the requisite cryptographic primitive driver to implement it 387 * // HKDF and SHA2 were chosen as an example and may not be available directly 388 * 389 * // At this point, you and the other party have both created the content within symmetricKeyingMaterial without 390 * // someone else listening to your communication channel being able to do so 391 * 392 * @endcode 393 * 394 * 395 */ 396 397 #ifndef ti_drivers_ECDH__include 398 #define ti_drivers_ECDH__include 399 400 #include <stdbool.h> 401 #include <stddef.h> 402 #include <stdint.h> 403 404 #include <ti/drivers/cryptoutils/cryptokey/CryptoKey.h> 405 #include <ti/drivers/cryptoutils/ecc/ECCParams.h> 406 407 #ifdef __cplusplus 408 extern "C" { 409 #endif 410 411 /*! 412 * Common ECDH status code reservation offset. 413 * ECC driver implementations should offset status codes with 414 * ECDH_STATUS_RESERVED growing negatively. 415 * 416 * Example implementation specific status codes: 417 * @code 418 * #define ECCXYZ_STATUS_ERROR0 ECDH_STATUS_RESERVED - 0 419 * #define ECCXYZ_STATUS_ERROR1 ECDH_STATUS_RESERVED - 1 420 * #define ECCXYZ_STATUS_ERROR2 ECDH_STATUS_RESERVED - 2 421 * @endcode 422 */ 423 #define ECDH_STATUS_RESERVED (-32) 424 425 /*! 426 * @brief Successful status code. 427 * 428 * Functions return ECDH_STATUS_SUCCESS if the function was executed 429 * successfully. 430 */ 431 #define ECDH_STATUS_SUCCESS (0) 432 433 /*! 434 * @brief Generic error status code. 435 * 436 * Functions return ECDH_STATUS_ERROR if the function was not executed 437 * successfully. 438 */ 439 #define ECDH_STATUS_ERROR (-1) 440 441 /*! 442 * @brief An error status code returned if the hardware or software resource 443 * is currently unavailable. 444 * 445 * ECC driver implementations may have hardware or software limitations on how 446 * many clients can simultaneously perform operations. This status code is returned 447 * if the mutual exclusion mechanism signals that an operation cannot currently be performed. 448 */ 449 #define ECDH_STATUS_RESOURCE_UNAVAILABLE (-2) 450 451 /*! 452 * @brief The result of the operation is the point at infinity. 453 * 454 * The operation yielded the point at infinity on this curve. This point is 455 * not permitted for further use in ECC operations. 456 */ 457 #define ECDH_STATUS_POINT_AT_INFINITY (-3) 458 459 /*! 460 * @brief The private key passed in is larger or equal to the order of the curve. 461 * 462 * Private keys must be integers in the interval [1, n - 1], where n is the 463 * order of the curve. 464 */ 465 #define ECDH_STATUS_PRIVATE_KEY_LARGER_EQUAL_ORDER (-4) 466 467 /*! 468 * @brief The private key passed in is zero. 469 * 470 * Private keys must be integers in the interval [1, n - 1], where n is the 471 * order of the curve. 472 */ 473 #define ECDH_STATUS_PRIVATE_KEY_ZERO (-5) 474 475 /*! 476 * @brief The public key of the other party does not lie upon the curve. 477 * 478 * The public key received from the other party does not lie upon the agreed upon 479 * curve. 480 */ 481 #define ECDH_STATUS_PUBLIC_KEY_NOT_ON_CURVE (-6) 482 483 /*! 484 * @brief A coordinate of the public key of the other party is too large. 485 * 486 * A coordinate of the public key received from the other party is larger than 487 * the prime of the curve. This implies that the point was not correctly 488 * generated on that curve. 489 */ 490 #define ECDH_STATUS_PUBLIC_KEY_LARGER_THAN_PRIME (-7) 491 492 /*! 493 * @brief The ongoing operation was canceled. 494 */ 495 #define ECDH_STATUS_CANCELED (-8) 496 497 /*! 498 * @brief The provided CryptoKey does not match the expected size 499 * 500 * The driver expects the private key to have the same length as other curve 501 * parameters and the public key to have a length of twice that plus one. 502 * If the provided CryptoKeys for the public and private keys do not match this 503 * scheme, this error will be returned. 504 */ 505 #define ECDH_STATUS_INVALID_KEY_SIZE (-9) 506 507 /*! 508 * @brief Importing generated key into KeyStore failed 509 * 510 * Functions return ECDH_STATUS_KEYSTORE_ERROR if the KeyStore_PSA_importKey() 511 * did not return KEYSTORE_PSA_STATUS_SUCCESS 512 */ 513 #define ECDH_STATUS_KEYSTORE_ERROR (-10) 514 515 /*! 516 * @brief ECC Global configuration 517 * 518 * The ECDH_Config structure contains a set of pointers used to characterize 519 * the ECC driver implementation. 520 * 521 * This structure needs to be defined before calling ECDH_init() and it must 522 * not be changed thereafter. 523 * 524 * @sa ECDH_init() 525 */ 526 typedef struct 527 { 528 /*! Pointer to a driver specific data object */ 529 void *object; 530 531 /*! Pointer to a driver specific hardware attributes structure */ 532 void const *hwAttrs; 533 } ECDH_Config; 534 535 /*! 536 * @brief A handle that is returned from an ECDH_open() call. 537 */ 538 typedef ECDH_Config *ECDH_Handle; 539 540 /*! 541 * @brief The way in which ECDH function calls return after performing a 542 * public key generation or shared secret compution operation. 543 * 544 * Callback return behavior is not supported by software-backed implementations. 545 * A NULL handle will be returned when attempting to open or construct a driver 546 * instance with an unsupported return behavior. 547 * 548 * Not all ECDH operations exhibit the specified return behavior. Functions that 549 * do not require significant computation and cannot offload that computation to 550 * a background thread behave like regular functions. Which functions exhibit 551 * the specfied return behavior is not implementation dependent. Specifically, a 552 * software-backed implementation run on the same CPU as the application will 553 * emulate the return behavior while not actually offloading the computation to 554 * the background thread. 555 * 556 * ECDH functions exhibiting the specified return behavior have restrictions on 557 * the context from which they may be called. 558 * 559 * | | Task | Hwi | Swi | 560 * |--------------------------------|-------|-------|-------| 561 * |ECDH_RETURN_BEHAVIOR_CALLBACK | X | X | X | 562 * |ECDH_RETURN_BEHAVIOR_BLOCKING | X | | | 563 * |ECDH_RETURN_BEHAVIOR_POLLING | X | X | X | 564 * 565 */ 566 typedef enum 567 { 568 ECDH_RETURN_BEHAVIOR_CALLBACK = 1, /*!< The function call will return immediately while the 569 * ECC operation goes on in the background. The registered 570 * callback function is called after the operation completes. 571 * The context the callback function is called (task, HWI, SWI) 572 * is implementation-dependent. 573 */ 574 ECDH_RETURN_BEHAVIOR_BLOCKING = 2, /*!< The function call will block while ECC operation goes 575 * on in the background. ECC operation results are available 576 * after the function returns. 577 */ 578 ECDH_RETURN_BEHAVIOR_POLLING = 4, /*!< The function call will continuously poll a flag while ECC 579 * operation goes on in the background. ECC operation results 580 * are available after the function returns. 581 */ 582 } ECDH_ReturnBehavior; 583 584 typedef enum 585 { 586 ECDH_BIG_ENDIAN_KEY = 0, /*!< All ECDH key material (private key, public key, and shared secret (when used)) 587 * are in big-endian format 588 */ 589 ECDH_LITTLE_ENDIAN_KEY = 1, /*!< All ECDH key material (private key, public key, and shared secret (when used)) 590 * are in little-endian format 591 */ 592 } ECDH_KeyMaterialEndianness; 593 594 /*! 595 * @brief Struct containing the parameters required to generate a public key. 596 */ 597 typedef struct 598 { 599 const ECCParams_CurveParams *curve; /*!< A pointer to the elliptic curve parameters for myPrivateKey */ 600 const CryptoKey *myPrivateKey; /*!< A pointer to the private ECC key from which the new public 601 * key will be generated. (maybe your static key) 602 */ 603 CryptoKey *myPublicKey; /*!< A pointer to a public ECC key which has been initialized blank. 604 * Newly generated key will be placed in this location. 605 * The formatting byte will be filled in by the driver if the 606 * keyMaterialEndianness requires it. 607 */ 608 ECDH_KeyMaterialEndianness keyMaterialEndianness; /*!< All keyMaterials, including myPrivate and myPublicKey, 609 * are either in big-endian (default) or little-endian format 610 */ 611 } ECDH_OperationGeneratePublicKey; 612 613 /*! 614 * @brief Struct containing the parameters required to compute the shared secret. 615 */ 616 typedef struct 617 { 618 const ECCParams_CurveParams *curve; /*!< A pointer to the elliptic curve parameters for myPrivateKey. 619 * If ECDH_generateKey() was used, this should be the same private key. 620 */ 621 const CryptoKey *myPrivateKey; /*!< A pointer to the private ECC key which will be used in to 622 * compute the shared secret. 623 */ 624 const CryptoKey *theirPublicKey; /*!< A pointer to the public key of the party with whom the 625 * shared secret will be generated. 626 */ 627 CryptoKey *sharedSecret; /*!< A pointer to a CryptoKey which has been initialized blank. 628 * The shared secret will be placed here. 629 * The formatting byte will be filled in by the driver if the 630 * keyMaterialEndianness requires it. 631 */ 632 ECDH_KeyMaterialEndianness keyMaterialEndianness; /*!< All keyMaterials, including myPrivate, theirPublicKey, and 633 * sharedSecret are either in big-endian (default) or little- 634 * endian format 635 */ 636 } ECDH_OperationComputeSharedSecret; 637 638 /*! 639 * @brief Union containing pointers to all supported operation structs. 640 */ 641 typedef union 642 { 643 ECDH_OperationGeneratePublicKey *generatePublicKey; /*!< A pointer to an ECDH_OperationGeneratePublicKey struct */ 644 ECDH_OperationComputeSharedSecret *computeSharedSecret; /*!< A pointer to an ECDH_OperationComputeSharedSecret 645 * struct 646 */ 647 } ECDH_Operation; 648 649 /*! 650 * @brief Enum for the operation types supported by the driver. 651 */ 652 typedef enum 653 { 654 ECDH_OPERATION_TYPE_GENERATE_PUBLIC_KEY = 1, 655 ECDH_OPERATION_TYPE_COMPUTE_SHARED_SECRET = 2, 656 } ECDH_OperationType; 657 658 /*! 659 * @brief The definition of a callback function used by the ECDH driver 660 * when used in ::ECDH_RETURN_BEHAVIOR_CALLBACK 661 * 662 * @param handle Handle of the client that started the ECDH operation. 663 * 664 * @param returnStatus The result of the ECDH operation. May contain an error code 665 * if the result is the point at infinity for example. 666 * 667 * @param operation A union of pointers to operation structs. Only one type 668 * of pointer is valid per call to the callback function. Which type 669 * is currently valid is determined by /c operationType. The union 670 * allows easier access to the struct's fields without the need to 671 * typecase the result. 672 * 673 * @param operationType This parameter determined which operation the 674 * callback refers to and which type to access through /c operation. 675 */ 676 typedef void (*ECDH_CallbackFxn)(ECDH_Handle handle, 677 int_fast16_t returnStatus, 678 ECDH_Operation operation, 679 ECDH_OperationType operationType); 680 681 /*! 682 * @brief ECC Parameters 683 * 684 * ECC Parameters are used to with the ECDH_open() call. Default values for 685 * these parameters are set using ECDH_Params_init(). 686 * 687 * @sa ECDH_Params_init() 688 */ 689 typedef struct 690 { 691 ECDH_ReturnBehavior returnBehavior; /*!< Blocking, callback, or polling return behavior */ 692 ECDH_CallbackFxn callbackFxn; /*!< Callback function pointer */ 693 uint32_t timeout; /*!< Timeout of the operation */ 694 void *custom; /*!< Custom argument used by driver 695 * implementation 696 */ 697 } ECDH_Params; 698 699 /*! 700 * @brief Default ECDH_Params structure 701 * 702 * @sa ECDH_Params_init() 703 */ 704 extern const ECDH_Params ECDH_defaultParams; 705 706 /*! 707 * @brief This function initializes the ECC module. 708 * 709 * @pre The ECDH_config structure must exist and be persistent before this 710 * function can be called. This function must also be called before 711 * any other ECC driver APIs. This function call does not modify any 712 * peripheral registers. 713 */ 714 void ECDH_init(void); 715 716 /*! 717 * @brief Function to initialize the ECDH_Params struct to its defaults 718 * 719 * @param params An pointer to ECDH_Params structure for 720 * initialization 721 * 722 * Defaults values are: 723 * returnBehavior = ECDH_RETURN_BEHAVIOR_BLOCKING 724 * callbackFxn = NULL 725 * timeout = SemaphoreP_WAIT_FOREVER 726 * custom = NULL 727 */ 728 void ECDH_Params_init(ECDH_Params *params); 729 730 /*! 731 * @brief This function opens a given ECC peripheral. 732 * 733 * @pre ECC controller has been initialized using ECDH_init() 734 * 735 * @param index Logical peripheral number for the ECC indexed into 736 * the ECDH_config table 737 * 738 * @param params Pointer to an parameter block, if NULL it will use 739 * default values. 740 * 741 * @return An ECDH_Handle on success or a NULL on an error or if it has been 742 * opened already. 743 * 744 * @sa ECDH_init() 745 * @sa ECDH_close() 746 */ 747 ECDH_Handle ECDH_open(uint_least8_t index, const ECDH_Params *params); 748 749 /*! 750 * @brief Function to close an ECC peripheral specified by the ECC handle 751 * 752 * @pre ECDH_open() has to be called first. 753 * 754 * @param handle An ECC handle returned from ECDH_open() 755 * 756 * @sa ECDH_open() 757 */ 758 void ECDH_close(ECDH_Handle handle); 759 760 /*! 761 * @brief Function to initialize an ECDH_OperationGeneratePublicKey struct to its defaults 762 * 763 * @param operation A pointer to ECDH_OperationGeneratePublicKey structure for 764 * initialization 765 * 766 * Defaults values are all zeros. 767 */ 768 void ECDH_OperationGeneratePublicKey_init(ECDH_OperationGeneratePublicKey *operation); 769 770 /*! 771 * @brief Function to initialize an ECDH_OperationComputeSharedSecret struct to its defaults 772 * 773 * @param operation A pointer to ECDH_OperationComputeSharedSecret structure for 774 * initialization 775 * 776 * Defaults values are all zeros. 777 */ 778 void ECDH_OperationComputeSharedSecret_init(ECDH_OperationComputeSharedSecret *operation); 779 780 /*! 781 * @brief Generates a public key for use in key agreement. 782 * 783 * This function can be used to generate a public key from a private key. 784 * 785 * @param handle A ECDH handle returned from ECDH_open() 786 * 787 * @param operation A pointer to a struct containing the requisite 788 * parameters to execute the function. 789 * 790 * @pre Call ECDH_OperationGeneratePublicKey_init() on @c operation. 791 * 792 * @post ECDH_computeSharedSecret() 793 * 794 * @retval #ECDH_STATUS_SUCCESS The operation succeeded. 795 * @retval #ECDH_STATUS_ERROR The operation failed. 796 * @retval #ECDH_STATUS_RESOURCE_UNAVAILABLE The required hardware resource was not available. Try again 797 * later. 798 * @retval #ECDH_STATUS_CANCELED The operation was canceled. 799 * @retval #ECDH_STATUS_POINT_AT_INFINITY The computed public key is the point at infinity. 800 * @retval #ECDH_STATUS_PRIVATE_KEY_ZERO The provided private key is zero. 801 * @retval #ECDH_STATUS_PRIVATE_KEY_LARGER_EQUAL_ORDER The provided private key is larger than or equal to the order 802 * of the curve. 803 * 804 */ 805 int_fast16_t ECDH_generatePublicKey(ECDH_Handle handle, ECDH_OperationGeneratePublicKey *operation); 806 807 /*! 808 * @brief Computes a shared secret 809 * 810 * This secret can be used to generate shared keys for encryption and authentication. 811 * 812 * @param handle A ECDH handle returned from ECDH_open() 813 * 814 * @param operation A pointer to a struct containing the requisite 815 * 816 * @pre Call ECDH_OperationComputeSharedSecret_init() on \c operation. 817 * Generate a shared secret off-chip or using ECDH_generatePublicKey() 818 * 819 * @retval #ECDH_STATUS_SUCCESS The operation succeeded. 820 * @retval #ECDH_STATUS_ERROR The operation failed. 821 * @retval #ECDH_STATUS_RESOURCE_UNAVAILABLE The required hardware resource was not available. Try again 822 * later. 823 * @retval #ECDH_STATUS_CANCELED The operation was canceled. 824 * @retval #ECDH_STATUS_PUBLIC_KEY_NOT_ON_CURVE The foreign public key is not a point on the specified curve. 825 * @retval #ECDH_STATUS_PUBLIC_KEY_LARGER_THAN_PRIME One of the public key coordinates is larger the the curve's 826 * prime. 827 */ 828 int_fast16_t ECDH_computeSharedSecret(ECDH_Handle handle, ECDH_OperationComputeSharedSecret *operation); 829 830 /*! 831 * @brief Cancels an ongoing ECDH operation. 832 * 833 * Asynchronously cancels an ECDH operation. Only available when using 834 * ECDH_RETURN_BEHAVIOR_CALLBACK or ECDH_RETURN_BEHAVIOR_BLOCKING. 835 * The operation will terminate as though an error occurred. The 836 * return status code of the operation will be ECDH_STATUS_CANCELED. 837 * 838 * @param handle Handle of the operation to cancel 839 * 840 * @retval #ECDH_STATUS_SUCCESS The operation was canceled. 841 * @retval #ECDH_STATUS_ERROR The operation was not canceled. There may be no operation to cancel. 842 */ 843 int_fast16_t ECDH_cancelOperation(ECDH_Handle handle); 844 845 /** 846 * @brief Constructs a new ECDH object 847 * 848 * Unlike #ECDH_open(), #ECDH_construct() does not require the hwAttrs and 849 * object to be allocated in a #ECDH_Config array that is indexed into. 850 * Instead, the #ECDH_Config, hwAttrs, and object can be allocated at any 851 * location. This allows for relatively simple run-time allocation of temporary 852 * driver instances on the stack or the heap. 853 * The drawback is that this makes it more difficult to write device-agnostic 854 * code. If you use an ifdef with DeviceFamily, you can choose the correct 855 * object and hwAttrs to allocate. That compilation unit will be tied to the 856 * device it was compiled for at this point. To change devices, recompilation 857 * of the application with a different DeviceFamily setting is necessary. 858 * 859 * @param config #ECDH_Config describing the location of the object and hwAttrs. 860 * 861 * @param params #ECDH_Params to configure the driver instance. 862 * 863 * @return Returns a #ECDH_Handle on success or NULL on failure. 864 * 865 * @pre The object struct @c config points to must be zeroed out prior to 866 * calling this function. Otherwise, unexpected behavior may ensue. 867 */ 868 ECDH_Handle ECDH_construct(ECDH_Config *config, const ECDH_Params *params); 869 870 #ifdef __cplusplus 871 } 872 #endif 873 874 #endif /* ti_drivers_ECDH__include */ 875