kopia lustrzana https://github.com/solokeys/solo1
				
				
				
			
		
			
				
	
	
		
			445 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			445 wiersze
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
| // Copyright 2019 SoloKeys Developers
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 | |
| // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 | |
| // http://opensource.org/licenses/MIT>, at your option. This file may not be
 | |
| // copied, modified, or distributed except according to those terms.
 | |
| /*
 | |
|  *  Wrapper for crypto implementation on device.
 | |
|  *
 | |
|  *  Can be replaced with different crypto implementation by
 | |
|  *  defining EXTERNAL_SOLO_CRYPTO
 | |
|  *
 | |
|  * */
 | |
| #ifndef EXTERNAL_SOLO_CRYPTO
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "util.h"
 | |
| #include "crypto.h"
 | |
| 
 | |
| #include "sha256.h"
 | |
| #include "uECC.h"
 | |
| #include "aes.h"
 | |
| #include "ctap.h"
 | |
| #include "device.h"
 | |
| // stuff for SHA512
 | |
| #include "sha2.h"
 | |
| #include "blockwise.h"
 | |
| #include APP_CONFIG
 | |
| #include "log.h"
 | |
| 
 | |
| #if defined(STM32L432xx)
 | |
| #include "salty.h"
 | |
| #else
 | |
| #include <sodium/crypto_sign_ed25519.h>
 | |
| #endif
 | |
| 
 | |
| typedef enum
 | |
| {
 | |
|     MBEDTLS_ECP_DP_NONE = 0,
 | |
|     MBEDTLS_ECP_DP_SECP192R1,      /*!< 192-bits NIST curve  */
 | |
|     MBEDTLS_ECP_DP_SECP224R1,      /*!< 224-bits NIST curve  */
 | |
|     MBEDTLS_ECP_DP_SECP256R1,      /*!< 256-bits NIST curve  */
 | |
|     MBEDTLS_ECP_DP_SECP384R1,      /*!< 384-bits NIST curve  */
 | |
|     MBEDTLS_ECP_DP_SECP521R1,      /*!< 521-bits NIST curve  */
 | |
|     MBEDTLS_ECP_DP_BP256R1,        /*!< 256-bits Brainpool curve */
 | |
|     MBEDTLS_ECP_DP_BP384R1,        /*!< 384-bits Brainpool curve */
 | |
|     MBEDTLS_ECP_DP_BP512R1,        /*!< 512-bits Brainpool curve */
 | |
|     MBEDTLS_ECP_DP_CURVE25519,           /*!< Curve25519               */
 | |
|     MBEDTLS_ECP_DP_SECP192K1,      /*!< 192-bits "Koblitz" curve */
 | |
|     MBEDTLS_ECP_DP_SECP224K1,      /*!< 224-bits "Koblitz" curve */
 | |
|     MBEDTLS_ECP_DP_SECP256K1,      /*!< 256-bits "Koblitz" curve */
 | |
| } mbedtls_ecp_group_id;
 | |
| 
 | |
| 
 | |
| static SHA256_CTX sha256_ctx;
 | |
| static cf_sha512_context sha512_ctx;
 | |
| static const struct uECC_Curve_t * _es256_curve = NULL;
 | |
| static const uint8_t * _signing_key = NULL;
 | |
| static int _key_len = 0;
 | |
| 
 | |
| // Secrets for testing only
 | |
| static uint8_t master_secret[64];
 | |
| static uint8_t transport_secret[32];
 | |
| 
 | |
| 
 | |
| void crypto_sha256_init(void)
 | |
| {
 | |
|     sha256_init(&sha256_ctx);
 | |
| }
 | |
| 
 | |
| void crypto_sha512_init(void)
 | |
| {
 | |
|     cf_sha512_init(&sha512_ctx);
 | |
| }
 | |
| 
 | |
| void crypto_load_master_secret(uint8_t * key)
 | |
| {
 | |
| #if KEY_SPACE_BYTES < 96
 | |
| #error "need more key bytes"
 | |
| #endif
 | |
|     memmove(master_secret, key, 64);
 | |
|     memmove(transport_secret, key+64, 32);
 | |
| }
 | |
| 
 | |
| void crypto_reset_master_secret(void)
 | |
| {
 | |
|     memset(master_secret, 0, 64);
 | |
|     memset(transport_secret, 0, 32);
 | |
|     ctap_generate_rng(master_secret, 64);
 | |
|     ctap_generate_rng(transport_secret, 32);
 | |
| }
 | |
| 
 | |
| 
 | |
| void crypto_sha256_update(uint8_t * data, size_t len)
 | |
| {
 | |
|     sha256_update(&sha256_ctx, data, len);
 | |
| }
 | |
| 
 | |
| void crypto_sha512_update(const uint8_t * data, size_t len) {
 | |
|     cf_sha512_update(&sha512_ctx, data, len);
 | |
| }
 | |
| 
 | |
| void crypto_sha256_update_secret()
 | |
| {
 | |
|     sha256_update(&sha256_ctx, master_secret, 32);
 | |
| }
 | |
| 
 | |
| void crypto_sha256_final(uint8_t * hash)
 | |
| {
 | |
|     sha256_final(&sha256_ctx, hash);
 | |
| }
 | |
| 
 | |
| void crypto_sha512_final(uint8_t * hash)
 | |
| {
 | |
|     // NB: there is also cf_sha512_digest
 | |
|     cf_sha512_digest_final(&sha512_ctx, hash);
 | |
| }
 | |
| 
 | |
| void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
 | |
| {
 | |
|     uint8_t buf[64];
 | |
|     unsigned int i;
 | |
|     memset(buf, 0, sizeof(buf));
 | |
| 
 | |
|     if (key == CRYPTO_MASTER_KEY)
 | |
|     {
 | |
|         key = master_secret;
 | |
|         klen = sizeof(master_secret)/2;
 | |
|     }
 | |
|     else if (key == CRYPTO_TRANSPORT_KEY)
 | |
|     {
 | |
|         key = transport_secret;
 | |
|         klen = 32;
 | |
|     }
 | |
| 
 | |
|     if(klen > 64)
 | |
|     {
 | |
|         printf2(TAG_ERR, "Error, key size must be <= 64\n");
 | |
|         exit(1);
 | |
|     }
 | |
| 
 | |
|     memmove(buf, key, klen);
 | |
| 
 | |
|     for (i = 0; i < sizeof(buf); i++)
 | |
|     {
 | |
|         buf[i] = buf[i] ^ 0x36;
 | |
|     }
 | |
| 
 | |
|     crypto_sha256_init();
 | |
|     crypto_sha256_update(buf, 64);
 | |
| }
 | |
| 
 | |
| void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
 | |
| {
 | |
|     uint8_t buf[64];
 | |
|     unsigned int i;
 | |
|     crypto_sha256_final(hmac);
 | |
|     memset(buf, 0, sizeof(buf));
 | |
|     if (key == CRYPTO_MASTER_KEY)
 | |
|     {
 | |
|         key = master_secret;
 | |
|         klen = sizeof(master_secret)/2;
 | |
|     }
 | |
|     else if (key == CRYPTO_TRANSPORT_KEY2)
 | |
|     {
 | |
|         key = transport_secret;
 | |
|         klen = 32;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     if(klen > 64)
 | |
|     {
 | |
|         printf2(TAG_ERR, "Error, key size must be <= 64\n");
 | |
|         exit(1);
 | |
|     }
 | |
|     memmove(buf, key, klen);
 | |
| 
 | |
|     for (i = 0; i < sizeof(buf); i++)
 | |
|     {
 | |
|         buf[i] = buf[i] ^ 0x5c;
 | |
|     }
 | |
| 
 | |
|     crypto_sha256_init();
 | |
|     crypto_sha256_update(buf, 64);
 | |
|     crypto_sha256_update(hmac, 32);
 | |
|     crypto_sha256_final(hmac);
 | |
| }
 | |
| 
 | |
| 
 | |
| void crypto_ecc256_init(void)
 | |
| {
 | |
|     uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
 | |
|     _es256_curve = uECC_secp256r1();
 | |
| }
 | |
| 
 | |
| 
 | |
| void crypto_ecc256_load_attestation_key(void)
 | |
| {
 | |
|     _signing_key = device_get_attestation_key();
 | |
|     _key_len = 32;
 | |
| }
 | |
| 
 | |
| void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
 | |
| {
 | |
|     if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
 | |
|     {
 | |
|         printf2(TAG_ERR, "error, uECC failed\n");
 | |
|         exit(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2)
 | |
| {
 | |
|     static uint8_t privkey[32];
 | |
|     generate_private_key(data,len,data2,len2,privkey);
 | |
|     _signing_key = privkey;
 | |
|     _key_len = 32;
 | |
| }
 | |
| 
 | |
| void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID)
 | |
| {
 | |
| 
 | |
|     const struct uECC_Curve_t * curve = NULL;
 | |
| 
 | |
|     switch(MBEDTLS_ECP_ID)
 | |
|     {
 | |
|         case MBEDTLS_ECP_DP_SECP192R1:
 | |
|             curve = uECC_secp192r1();
 | |
|             if (_key_len != 24)  goto fail;
 | |
|             break;
 | |
|         case MBEDTLS_ECP_DP_SECP224R1:
 | |
|             curve = uECC_secp224r1();
 | |
|             if (_key_len != 28)  goto fail;
 | |
|             break;
 | |
|         case MBEDTLS_ECP_DP_SECP256R1:
 | |
|             curve = uECC_secp256r1();
 | |
|             if (_key_len != 32)  goto fail;
 | |
|             break;
 | |
|         case MBEDTLS_ECP_DP_SECP256K1:
 | |
|             curve = uECC_secp256k1();
 | |
|             if (_key_len != 32)  goto fail;
 | |
|             break;
 | |
|         default:
 | |
|             printf2(TAG_ERR, "error, invalid ECDSA alg specifier\n");
 | |
|             exit(1);
 | |
|     }
 | |
| 
 | |
|     if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
 | |
|     {
 | |
|         printf2(TAG_ERR, "error, uECC failed\n");
 | |
|         exit(1);
 | |
|     }
 | |
|     return;
 | |
| 
 | |
| fail:
 | |
|     printf2(TAG_ERR, "error, invalid key length\n");
 | |
|     exit(1);
 | |
| 
 | |
| }
 | |
| 
 | |
| void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey)
 | |
| {
 | |
|     crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
 | |
|     crypto_sha256_update(data, len);
 | |
|     crypto_sha256_update(data2, len2);
 | |
|     crypto_sha256_update(master_secret, 32);    // TODO AES
 | |
|     crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
 | |
| 
 | |
|     crypto_aes256_init(master_secret + 32, NULL);
 | |
|     crypto_aes256_encrypt(privkey, 32);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);*/
 | |
| void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y)
 | |
| {
 | |
|     uint8_t privkey[32];
 | |
|     uint8_t pubkey[64];
 | |
| 
 | |
|     generate_private_key(data,len,NULL,0,privkey);
 | |
| 
 | |
|     memset(pubkey,0,sizeof(pubkey));
 | |
|     uECC_compute_public_key(privkey, pubkey, _es256_curve);
 | |
|     memmove(x,pubkey,32);
 | |
|     memmove(y,pubkey+32,32);
 | |
| }
 | |
| void crypto_ecc256_compute_public_key(uint8_t * privkey, uint8_t * pubkey)
 | |
| {
 | |
|     uECC_compute_public_key(privkey, pubkey, _es256_curve);
 | |
| }
 | |
| 
 | |
| 
 | |
| void crypto_load_external_key(uint8_t * key, int len)
 | |
| {
 | |
|     _signing_key = key;
 | |
|     _key_len = len;
 | |
| }
 | |
| 
 | |
| 
 | |
| void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
 | |
| {
 | |
|     if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
 | |
|     {
 | |
|         printf2(TAG_ERR, "Error, uECC_make_key failed\n");
 | |
|         exit(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret)
 | |
| {
 | |
|     if (uECC_shared_secret(pubkey, privkey, shared_secret, _es256_curve) != 1)
 | |
|     {
 | |
|         printf2(TAG_ERR, "Error, uECC_shared_secret failed\n");
 | |
|         exit(1);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| struct AES_ctx aes_ctx;
 | |
| void crypto_aes256_init(uint8_t * key, uint8_t * nonce)
 | |
| {
 | |
|     if (key == CRYPTO_TRANSPORT_KEY)
 | |
|     {
 | |
|         AES_init_ctx(&aes_ctx, transport_secret);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         AES_init_ctx(&aes_ctx, key);
 | |
|     }
 | |
|     if (nonce == NULL)
 | |
|     {
 | |
|         memset(aes_ctx.Iv, 0, 16);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         memmove(aes_ctx.Iv, nonce, 16);
 | |
|     }
 | |
| }
 | |
| 
 | |
| // prevent round key recomputation
 | |
| void crypto_aes256_reset_iv(uint8_t * nonce)
 | |
| {
 | |
|     if (nonce == NULL)
 | |
|     {
 | |
|         memset(aes_ctx.Iv, 0, 16);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         memmove(aes_ctx.Iv, nonce, 16);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void crypto_aes256_decrypt(uint8_t * buf, int length)
 | |
| {
 | |
|     AES_CBC_decrypt_buffer(&aes_ctx, buf, length);
 | |
| }
 | |
| 
 | |
| void crypto_aes256_encrypt(uint8_t * buf, int length)
 | |
| {
 | |
|     AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
 | |
| }
 | |
| 
 | |
| void crypto_ed25519_derive_public_key(uint8_t * data, int len, uint8_t * x)
 | |
| {
 | |
| #if defined(STM32L432xx)
 | |
| 
 | |
|     uint8_t seed[salty_SECRETKEY_SEED_LENGTH];
 | |
| 
 | |
|     generate_private_key(data, len, NULL, 0, seed);
 | |
|     salty_public_key(&seed, (uint8_t (*)[salty_PUBLICKEY_SERIALIZED_LENGTH])x);
 | |
| 
 | |
| #else
 | |
| 
 | |
|     uint8_t seed[crypto_sign_ed25519_SEEDBYTES];
 | |
|     uint8_t   sk[crypto_sign_ed25519_SECRETKEYBYTES];
 | |
| 
 | |
|     generate_private_key(data, len, NULL, 0, seed);
 | |
|     crypto_sign_ed25519_seed_keypair(x, sk, seed);
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void crypto_ed25519_load_key(uint8_t * data, int len)
 | |
| {
 | |
| #if defined(STM32L432xx)
 | |
| 
 | |
|     static uint8_t seed[salty_SECRETKEY_SEED_LENGTH];
 | |
| 
 | |
|     generate_private_key(data, len, NULL, 0, seed);
 | |
| 
 | |
|     _signing_key = seed;
 | |
|     _key_len = salty_SECRETKEY_SEED_LENGTH;
 | |
| 
 | |
| #else
 | |
| 
 | |
|     uint8_t seed[crypto_sign_ed25519_SEEDBYTES];
 | |
|     uint8_t   pk[crypto_sign_ed25519_PUBLICKEYBYTES];
 | |
|     static uint8_t sk[crypto_sign_ed25519_SECRETKEYBYTES];
 | |
| 
 | |
|     generate_private_key(data, len, NULL, 0, seed);
 | |
|     crypto_sign_ed25519_seed_keypair(pk, sk, seed);
 | |
| 
 | |
|     _signing_key = sk;
 | |
|     _key_len = crypto_sign_ed25519_SECRETKEYBYTES;
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void crypto_ed25519_sign(uint8_t * data1, int len1, uint8_t * data2, int len2, uint8_t * sig)
 | |
| {
 | |
|     // ed25519 signature APIs need the message at once (by design!) and in one
 | |
|     // contiguous buffer (could be changed).
 | |
| 
 | |
|     // 512 is an arbitrary sanity limit, could be less
 | |
|     if (len1 < 0 || len2 < 0 || len1 > 512 || len2 > 512)
 | |
|     {
 | |
|         memset(sig, 0, 64); // ed25519 signature len is 64 bytes
 | |
|         return;
 | |
|     }
 | |
|     // XXX: dynamically sized allocation on the stack
 | |
|     const int len = len1 + len2; // 0 <= len <= 1024
 | |
|     uint8_t data[len1 + len2];
 | |
| 
 | |
|     memcpy(data,        data1, len1);
 | |
|     memcpy(data + len1, data2, len2);
 | |
| 
 | |
| #if defined(STM32L432xx)
 | |
| 
 | |
|     // TODO: check that correct load_key() had been called?
 | |
|     salty_sign((uint8_t (*)[salty_SECRETKEY_SEED_LENGTH])_signing_key, data, len,
 | |
|             (uint8_t (*)[salty_SIGNATURE_SERIALIZED_LENGTH])sig);
 | |
| 
 | |
| #else
 | |
| 
 | |
|     // TODO: check that correct load_key() had been called?
 | |
|     crypto_sign_ed25519_detached(sig, NULL, data, len, _signing_key);
 | |
| 
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #endif
 |