mirror of
				https://github.com/0xFEEDC0DE64/arduino-esp32.git
				synced 2025-10-30 13:41:40 +01:00 
			
		
		
		
	
		
			
	
	
		
			366 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			366 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ | ||
|  | 
 | ||
|  | #ifndef _UECC_H_
 | ||
|  | #define _UECC_H_
 | ||
|  | 
 | ||
|  | #include <stdint.h>
 | ||
|  | 
 | ||
|  | /* Platform selection options.
 | ||
|  | If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. | ||
|  | Possible values for uECC_PLATFORM are defined below: */ | ||
|  | #define uECC_arch_other 0
 | ||
|  | #define uECC_x86        1
 | ||
|  | #define uECC_x86_64     2
 | ||
|  | #define uECC_arm        3
 | ||
|  | #define uECC_arm_thumb  4
 | ||
|  | #define uECC_arm_thumb2 5
 | ||
|  | #define uECC_arm64      6
 | ||
|  | #define uECC_avr        7
 | ||
|  | 
 | ||
|  | /* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
 | ||
|  | If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your | ||
|  | platform. */ | ||
|  | 
 | ||
|  | /* Optimization level; trade speed for code size.
 | ||
|  |    Larger values produce code that is faster but larger. | ||
|  |    Currently supported values are 0 - 4; 0 is unusably slow for most applications. | ||
|  |    Optimization level 4 currently only has an effect ARM platforms where more than one | ||
|  |    curve is enabled. */ | ||
|  | #ifndef uECC_OPTIMIZATION_LEVEL
 | ||
|  |     #define uECC_OPTIMIZATION_LEVEL 2
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
 | ||
|  | used for (scalar) squaring instead of the generic multiplication function. This can make things | ||
|  | faster somewhat faster, but increases the code size. */ | ||
|  | #ifndef uECC_SQUARE_FUNC
 | ||
|  |     #define uECC_SQUARE_FUNC 0
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native
 | ||
|  | little-endian format for *all* arrays passed in and out of the public API. This includes public  | ||
|  | and private keys, shared secrets, signatures and message hashes.  | ||
|  | Using this switch reduces the amount of call stack memory used by uECC, since less intermediate | ||
|  | translations are required.  | ||
|  | Note that this will *only* work on native little-endian processors and it will treat the uint8_t | ||
|  | arrays passed into the public API as word arrays, therefore requiring the provided byte arrays  | ||
|  | to be word aligned on architectures that do not support unaligned accesses. | ||
|  | IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible | ||
|  | with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use | ||
|  | the same endianness. */ | ||
|  | #ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
 | ||
|  |     #define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* Curve support selection. Set to 0 to remove that curve. */ | ||
|  | #ifndef uECC_SUPPORTS_secp160r1
 | ||
|  |     #define uECC_SUPPORTS_secp160r1 1
 | ||
|  | #endif
 | ||
|  | #ifndef uECC_SUPPORTS_secp192r1
 | ||
|  |     #define uECC_SUPPORTS_secp192r1 1
 | ||
|  | #endif
 | ||
|  | #ifndef uECC_SUPPORTS_secp224r1
 | ||
|  |     #define uECC_SUPPORTS_secp224r1 1
 | ||
|  | #endif
 | ||
|  | #ifndef uECC_SUPPORTS_secp256r1
 | ||
|  |     #define uECC_SUPPORTS_secp256r1 1
 | ||
|  | #endif
 | ||
|  | #ifndef uECC_SUPPORTS_secp256k1
 | ||
|  |     #define uECC_SUPPORTS_secp256k1 1
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* Specifies whether compressed point format is supported.
 | ||
|  |    Set to 0 to disable point compression/decompression functions. */ | ||
|  | #ifndef uECC_SUPPORT_COMPRESSED_POINT
 | ||
|  |     #define uECC_SUPPORT_COMPRESSED_POINT 1
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | struct uECC_Curve_t; | ||
|  | typedef const struct uECC_Curve_t * uECC_Curve; | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | extern "C" | ||
|  | { | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #if uECC_SUPPORTS_secp160r1
 | ||
|  | uECC_Curve uECC_secp160r1(void); | ||
|  | #endif
 | ||
|  | #if uECC_SUPPORTS_secp192r1
 | ||
|  | uECC_Curve uECC_secp192r1(void); | ||
|  | #endif
 | ||
|  | #if uECC_SUPPORTS_secp224r1
 | ||
|  | uECC_Curve uECC_secp224r1(void); | ||
|  | #endif
 | ||
|  | #if uECC_SUPPORTS_secp256r1
 | ||
|  | uECC_Curve uECC_secp256r1(void); | ||
|  | #endif
 | ||
|  | #if uECC_SUPPORTS_secp256k1
 | ||
|  | uECC_Curve uECC_secp256k1(void); | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /* uECC_RNG_Function type
 | ||
|  | The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if | ||
|  | 'dest' was filled with random data, or 0 if the random data could not be generated. | ||
|  | The filled-in values should be either truly random, or from a cryptographically-secure PRNG. | ||
|  | 
 | ||
|  | A correctly functioning RNG function must be set (using uECC_set_rng()) before calling | ||
|  | uECC_make_key() or uECC_sign(). | ||
|  | 
 | ||
|  | Setting a correctly functioning RNG function improves the resistance to side-channel attacks | ||
|  | for uECC_shared_secret() and uECC_sign_deterministic(). | ||
|  | 
 | ||
|  | A correct RNG function is set by default when building for Windows, Linux, or OS X. | ||
|  | If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, | ||
|  | you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined | ||
|  | RNG function; you must provide your own. | ||
|  | */ | ||
|  | typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); | ||
|  | 
 | ||
|  | /* uECC_set_rng() function.
 | ||
|  | Set the function that will be used to generate random bytes. The RNG function should | ||
|  | return 1 if the random data was generated, or 0 if the random data could not be generated. | ||
|  | 
 | ||
|  | On platforms where there is no predefined RNG function (eg embedded platforms), this must | ||
|  | be called before uECC_make_key() or uECC_sign() are used. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     rng_function - The function that will be used to generate random bytes. | ||
|  | */ | ||
|  | void uECC_set_rng(uECC_RNG_Function rng_function); | ||
|  | 
 | ||
|  | /* uECC_get_rng() function.
 | ||
|  | 
 | ||
|  | Returns the function that will be used to generate random bytes. | ||
|  | */ | ||
|  | uECC_RNG_Function uECC_get_rng(void); | ||
|  | 
 | ||
|  | /* uECC_curve_private_key_size() function.
 | ||
|  | 
 | ||
|  | Returns the size of a private key for the curve in bytes. | ||
|  | */ | ||
|  | int uECC_curve_private_key_size(uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_curve_public_key_size() function.
 | ||
|  | 
 | ||
|  | Returns the size of a public key for the curve in bytes. | ||
|  | */ | ||
|  | int uECC_curve_public_key_size(uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_make_key() function.
 | ||
|  | Create a public/private key pair. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     public_key  - Will be filled in with the public key. Must be at least 2 * the curve size | ||
|  |                   (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 | ||
|  |                   bytes long. | ||
|  |     private_key - Will be filled in with the private key. Must be as long as the curve order; this | ||
|  |                   is typically the same as the curve size, except for secp160r1. For example, if the | ||
|  |                   curve is secp256r1, private_key must be 32 bytes long. | ||
|  | 
 | ||
|  |                   For secp160r1, private_key must be 21 bytes long! Note that the first byte will | ||
|  |                   almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). | ||
|  | 
 | ||
|  | Returns 1 if the key pair was generated successfully, 0 if an error occurred. | ||
|  | */ | ||
|  | int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_shared_secret() function.
 | ||
|  | Compute a shared secret given your secret key and someone else's public key. | ||
|  | Note: It is recommended that you hash the result of uECC_shared_secret() before using it for | ||
|  | symmetric encryption or HMAC. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     public_key  - The public key of the remote party. | ||
|  |     private_key - Your private key. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     secret - Will be filled in with the shared secret value. Must be the same size as the | ||
|  |              curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. | ||
|  | 
 | ||
|  | Returns 1 if the shared secret was generated successfully, 0 if an error occurred. | ||
|  | */ | ||
|  | int uECC_shared_secret(const uint8_t *public_key, | ||
|  |                        const uint8_t *private_key, | ||
|  |                        uint8_t *secret, | ||
|  |                        uECC_Curve curve); | ||
|  | 
 | ||
|  | #if uECC_SUPPORT_COMPRESSED_POINT
 | ||
|  | /* uECC_compress() function.
 | ||
|  | Compress a public key. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     public_key - The public key to compress. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     compressed - Will be filled in with the compressed public key. Must be at least | ||
|  |                  (curve size + 1) bytes long; for example, if the curve is secp256r1, | ||
|  |                  compressed must be 33 bytes long. | ||
|  | */ | ||
|  | void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_decompress() function.
 | ||
|  | Decompress a compressed public key. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     compressed - The compressed public key. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     public_key - Will be filled in with the decompressed public key. | ||
|  | */ | ||
|  | void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); | ||
|  | #endif /* uECC_SUPPORT_COMPRESSED_POINT */
 | ||
|  | 
 | ||
|  | /* uECC_valid_public_key() function.
 | ||
|  | Check to see if a public key is valid. | ||
|  | 
 | ||
|  | Note that you are not required to check for a valid public key before using any other uECC | ||
|  | functions. However, you may wish to avoid spending CPU time computing a shared secret or | ||
|  | verifying a signature using an invalid public key. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     public_key - The public key to check. | ||
|  | 
 | ||
|  | Returns 1 if the public key is valid, 0 if it is invalid. | ||
|  | */ | ||
|  | int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_compute_public_key() function.
 | ||
|  | Compute the corresponding public key for a private key. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     private_key - The private key to compute the public key for | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     public_key - Will be filled in with the corresponding public key | ||
|  | 
 | ||
|  | Returns 1 if the key was computed successfully, 0 if an error occurred. | ||
|  | */ | ||
|  | int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_sign() function.
 | ||
|  | Generate an ECDSA signature for a given hash value. | ||
|  | 
 | ||
|  | Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to | ||
|  | this function along with your private key. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     private_key  - Your private key. | ||
|  |     message_hash - The hash of the message to sign. | ||
|  |     hash_size    - The size of message_hash in bytes. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     signature - Will be filled in with the signature value. Must be at least 2 * curve size long. | ||
|  |                 For example, if the curve is secp256r1, signature must be 64 bytes long. | ||
|  | 
 | ||
|  | Returns 1 if the signature generated successfully, 0 if an error occurred. | ||
|  | */ | ||
|  | int uECC_sign(const uint8_t *private_key, | ||
|  |               const uint8_t *message_hash, | ||
|  |               unsigned hash_size, | ||
|  |               uint8_t *signature, | ||
|  |               uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_HashContext structure.
 | ||
|  | This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). | ||
|  | The structure will be used for multiple hash computations; each time a new hash | ||
|  | is computed, init_hash() will be called, followed by one or more calls to | ||
|  | update_hash(), and finally a call to finish_hash() to produce the resulting hash. | ||
|  | 
 | ||
|  | The intention is that you will create a structure that includes uECC_HashContext | ||
|  | followed by any hash-specific data. For example: | ||
|  | 
 | ||
|  | typedef struct SHA256_HashContext { | ||
|  |     uECC_HashContext uECC; | ||
|  |     SHA256_CTX ctx; | ||
|  | } SHA256_HashContext; | ||
|  | 
 | ||
|  | void init_SHA256(uECC_HashContext *base) { | ||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||
|  |     SHA256_Init(&context->ctx); | ||
|  | } | ||
|  | 
 | ||
|  | void update_SHA256(uECC_HashContext *base, | ||
|  |                    const uint8_t *message, | ||
|  |                    unsigned message_size) { | ||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||
|  |     SHA256_Update(&context->ctx, message, message_size); | ||
|  | } | ||
|  | 
 | ||
|  | void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { | ||
|  |     SHA256_HashContext *context = (SHA256_HashContext *)base; | ||
|  |     SHA256_Final(hash_result, &context->ctx); | ||
|  | } | ||
|  | 
 | ||
|  | ... when signing ... | ||
|  | { | ||
|  |     uint8_t tmp[32 + 32 + 64]; | ||
|  |     SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; | ||
|  |     uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); | ||
|  | } | ||
|  | */ | ||
|  | typedef struct uECC_HashContext { | ||
|  |     void (*init_hash)(const struct uECC_HashContext *context); | ||
|  |     void (*update_hash)(const struct uECC_HashContext *context, | ||
|  |                         const uint8_t *message, | ||
|  |                         unsigned message_size); | ||
|  |     void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result); | ||
|  |     unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ | ||
|  |     unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ | ||
|  |     uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ | ||
|  | } uECC_HashContext; | ||
|  | 
 | ||
|  | /* uECC_sign_deterministic() function.
 | ||
|  | Generate an ECDSA signature for a given hash value, using a deterministic algorithm | ||
|  | (see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling | ||
|  | this function; however, if the RNG is defined it will improve resistance to side-channel | ||
|  | attacks. | ||
|  | 
 | ||
|  | Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to | ||
|  | this function along with your private key and a hash context. Note that the message_hash | ||
|  | does not need to be computed with the same hash function used by hash_context. | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     private_key  - Your private key. | ||
|  |     message_hash - The hash of the message to sign. | ||
|  |     hash_size    - The size of message_hash in bytes. | ||
|  |     hash_context - A hash context to use. | ||
|  | 
 | ||
|  | Outputs: | ||
|  |     signature - Will be filled in with the signature value. | ||
|  | 
 | ||
|  | Returns 1 if the signature generated successfully, 0 if an error occurred. | ||
|  | */ | ||
|  | int uECC_sign_deterministic(const uint8_t *private_key, | ||
|  |                             const uint8_t *message_hash, | ||
|  |                             unsigned hash_size, | ||
|  |                             const uECC_HashContext *hash_context, | ||
|  |                             uint8_t *signature, | ||
|  |                             uECC_Curve curve); | ||
|  | 
 | ||
|  | /* uECC_verify() function.
 | ||
|  | Verify an ECDSA signature. | ||
|  | 
 | ||
|  | Usage: Compute the hash of the signed data using the same hash as the signer and | ||
|  | pass it to this function along with the signer's public key and the signature values (r and s). | ||
|  | 
 | ||
|  | Inputs: | ||
|  |     public_key   - The signer's public key. | ||
|  |     message_hash - The hash of the signed data. | ||
|  |     hash_size    - The size of message_hash in bytes. | ||
|  |     signature    - The signature value. | ||
|  | 
 | ||
|  | Returns 1 if the signature is valid, 0 if it is invalid. | ||
|  | */ | ||
|  | int uECC_verify(const uint8_t *public_key, | ||
|  |                 const uint8_t *message_hash, | ||
|  |                 unsigned hash_size, | ||
|  |                 const uint8_t *signature, | ||
|  |                 uECC_Curve curve); | ||
|  | 
 | ||
|  | #ifdef __cplusplus
 | ||
|  | } /* end of extern "C" */ | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #endif /* _UECC_H_ */
 |