espressif / esp-wolfssl

WolfSSL port for ESP-IDF & ESP8266_RTOS_SDK
38 stars 13 forks source link

What do I do when I always return '-170' when using wc_ecc_shared_secret? #21

Open zhy2020 opened 1 year ago

zhy2020 commented 1 year ago

My program receives an ephemeral_key (publickey) in the format ProtobufCBinaryData. I want to use my private key (private_key ECC_SECP256R1) and ephemeral_key to generate a shared key, What do I do when I always return '-170' when using wc_ecc_shared_secret?

ecc_key my_private_key; // ECC_SECP256R1 byte my_public_key[65]; // wc_ecc_export_x963_ex()

ecc_key other_pub_key[65]; int to_load_key(ProtobufCBinaryData ephemeral_key) { int ret = 0;

wc_ecc_init(&other_pub_key);
ret = wc_ecc_import_x963((byte *)ephemeral_key.data, (word32)ephemeral_key.len, &other_pub_key);

//int curve_idx = wc_ecc_get_curve_idx(ECC_SECP256R1);
//other_pub_key= wc_ecc_new_point(); // ecc_point *other_pub_key;
//ret = wc_ecc_import_point_der(ephemeral_key.data, ephemeral_key.len, curve_idx, other_pub_key);

ret = wc_ecc_shared_secret(&my_private_key, &other_pub_key, shared_key, shared_key_len);
if (ret != 0)
{
    ESP_LOGI(TAG, "========= wc_ecc_shared_secret error %d", ret);
    wc_ecc_free(&other_pub_key);
    return -4; // Error computing shared key
}
return 0;

}

zhy2020 commented 1 year ago

somebody help me?

gojimmypi commented 1 year ago

@zhy2020 my apologies for missing this. Have you made any progress? If not, I'll try to take a look this week.

In the meantime: you'll get a much quicker response by submitting your questions over on wolfSSL.

Additionally, as noted in https://github.com/espressif/esp-wolfssl/issues/16, this repo has a somewhat old submodule of wolfssl. Using the most recent code may have even solved the problem you are encountering.

mahavirj commented 1 year ago

@zhy2020 Error code that you posted points to incorrect arguments to the API. You may try the sample code from https://github.com/wolfSSL/wolfssl/blob/bdcf6928a2227f5b6768c845d3c58fa82714b030/IDE/IAR-MSP430/main.c#L241-L295, probably it should help your use-case.

zhy2020 commented 1 year ago

@zhy2020我很抱歉错过了这个。你有进步吗?如果没有,我这周会试着看看。

同时:通过在wolfSSL上提交您的问题,您会得到更快的答复。

此外,如#16中所述,此 repo 有一个有点旧的 wolfssl 子模块。使用最新的代码甚至可能已经解决了您遇到的问题。

So far there has been no progress

gojimmypi commented 1 year ago

@zhy2020 is it possible for you to share your ecc_key my_private_key my_public_key[65] and other_pub_key values used in the example above?

If you don't want to post them here, perhaps you could send them to support@wolfssl.com for me to test?

zhy2020 commented 1 year ago

my_private_key

my_private_key is imported through the.pem file -----BEGIN EC PRIVATE KEY----- MHcCAQEEIGXOdeNRODqoWF2G1Pv5c/9606thVSgAR2b0MDRZErxwoAoGCCqGSM49 AwEHoUQDQgAEJJOl0J2L60fM3o+sGHuGrQCZEMlBIv2N6uOYYE2JfllBg5OIYGsi jzV60X62bCasAXcLYOSGmyDHmdN2W1/BdA== -----END EC PRIVATE KEY-----

The hexadecimal value of my_public_key is 042493a5d09d8beb47ccde8fac187b86ad009910c94122fd8deae398604d897e5941839388606b228f357ad17eb66c26ac01770b60e4869b20c799d3 765b5fc174

ephemeral_key.data is b'04f3476fb37270eef09966fd17ca7967ede63a2bb3d23b4aee6e8b459482aebd7a939a95cbbbd01a1ec46b1976509e1cb82990d8eec34c98d14b69c5d8f7cee21c'

int curveId = ECC_SECP256R1; ecc_key my_private_key ; // 私钥 byte my_public_key[65];

static void generate_private_key(void) { int ret; long fileSz = private_key_pem_end - private_key_pem_start; int inSz = (int)fileSz;

word32 idx = 0;

wc_ecc_init(&my_private_key ); // initialize key

byte der[ECC_BUFSIZE];

wc_KeyPemToDer(private_key_pem_start, (int)fileSz, &der, ECC_BUFSIZE, NULL); 

ret = wc_EccPrivateKeyDecode(&der, &idx, &my_private_key , (word32)inSz);
if (ret < 0)
{
    ESP_LOGI(GATTC_TAG, "error decoding ecc key "); // error decoding ecc key
}

int check_result;

check_result = wc_ecc_check_key(&my_private_key );

if (check_result == MP_OKAY)
{
    ESP_LOGI(GATTC_TAG, "check_private_key yes==============");
}
else
{
    ESP_LOGI(GATTC_TAG, "check_private_key no==============");
}

}

static void generate_public_key(void) { int ret; word32 buffSz = sizeof(my_public_key);

ret = wc_ecc_export_x963_ex(&my_private_key, (byte *)my_public_key, &buffSz, 0);
if (ret != 0)
{
    // error exporting key
    ESP_LOGI(TAG, "error exporting public key");
}
ESP_LOGI(TAG, "public key: ");
for (int i = 0; i < 65; i++)
{
     printf("%02x", (unsigned char)my_public_key[i]);
}

}

gojimmypi commented 1 year ago

Hello @zhy2020 and thank you for the additional details.

I've created a sample app and have confirmed the -170 error you are seeing:

image

It appears the value being passed for private_key->type is zero, and should otherwise be a valid type. (see ecc.c - the type needs to be either ECC_PRIVATEKEY or ECC_PRIVATEKEY_ONLY)

I will next work on providing a working example.

gojimmypi commented 1 year ago

Hi @zhy2020 - I've updated my demo app that seems to be working a bit better.

I found the key to success is to use the wc_ecc_check_key.

The demo app is not quite as polished as I'd like, as I used the openssl commandline tool on your example private key file, provided above:

openssl ec -in my_private_key_example.pem.txt  -text -noout

It generated this text:

        read EC key
        Private-Key: (256 bit)
        priv:
            65:ce:75:e3:51:38:3a:a8:58:5d:86:d4:fb:f9:73:
            ff:7a:d3:ab:61:55:28:00:47:66:f4:30:34:59:12:
            bc:70
        pub:
            04:24:93:a5:d0:9d:8b:eb:47:cc:de:8f:ac:18:7b:
            86:ad:00:99:10:c9:41:22:fd:8d:ea:e3:98:60:4d:
            89:7e:59:41:83:93:88:60:6b:22:8f:35:7a:d1:7e:
            b6:6c:26:ac:01:77:0b:60:e4:86:9b:20:c7:99:d3:
            76:5b:5f:c1:74
        ASN1 OID: prime256v1
        NIST CURVE: P-256

That text, you'll see I assigned to unsigned char private_key[] and unsigned char public_key[] that were used as parameters to wc_ecc_import_private_key.

Ideally, I would have liked to read your PEM-encoded ANSI X9.62 private key directly in the ESP32 without needing the openssl tool. I'm confident that's possible; I just need to do a bit more homework.

zhy2020 commented 1 year ago

Hi @zhy2020 - I've updated my demo app that seems to be working a bit better.

I found the key to success is to use the wc_ecc_check_key.

The demo app is not quite as polished as I'd like, as I used the openssl commandline tool on your example private key file, provided above:

openssl ec -in my_private_key_example.pem.txt  -text -noout

It generated this text:

        read EC key
        Private-Key: (256 bit)
        priv:
            65:ce:75:e3:51:38:3a:a8:58:5d:86:d4:fb:f9:73:
            ff:7a:d3:ab:61:55:28:00:47:66:f4:30:34:59:12:
            bc:70
        pub:
            04:24:93:a5:d0:9d:8b:eb:47:cc:de:8f:ac:18:7b:
            86:ad:00:99:10:c9:41:22:fd:8d:ea:e3:98:60:4d:
            89:7e:59:41:83:93:88:60:6b:22:8f:35:7a:d1:7e:
            b6:6c:26:ac:01:77:0b:60:e4:86:9b:20:c7:99:d3:
            76:5b:5f:c1:74
        ASN1 OID: prime256v1
        NIST CURVE: P-256

That text, you'll see I assigned to unsigned char private_key[] and unsigned char public_key[] that were used as parameters to wc_ecc_import_private_key.

Ideally, I would have liked to read your PEM-encoded ANSI X9.62 private key directly in the ESP32 without needing the openssl tool. I'm confident that's possible; I just need to do a bit more homework.

Thank you very much for your help. The program has been running normally.

zhy2020 commented 1 year ago

sorry, I was too anxious and neglected the correctness of the value. I have been able to generate shared_key by using the wc_ecc_set_rng and wc_ecc_check_key methods. It is not the same as the shared_key generated by python code.

python code :

`

cryptography

from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.backends import default_backend

def getSharedKey(self):

creates sha1 hasher for creating shared key

    hasher = hashes.Hash(hashes.SHA1())
    # exchange own private key with car's ephemeral key to create an intermediate shared key
    shared_key = self.private_key.exchange(
        ec.ECDH(), self.vehicle_key)
    # intermediate shared key is then inserted into the hasher
    hasher.update(shared_key)
    # and the first 16 bytes of the hash will be our final shared key
    return hasher.finalize()[:16]`

python sharedkey:

1681879233373

esp32 sharedkey: (29677) btn_target: Successfully called wc_ecc_shared_secret for my_ecc_private_key and my_ecc_public_key 03 89 f7 75 81 8a b0 ef 9a e3 7d 8a 46 34 e3 a9 df e1 b3 1c f8 c3 b1 6f b2 59 98 85 7a e2 d4 77

gojimmypi commented 1 year ago

Hi @zhy2020 I've continued to work on a working example, but I don't quite have it completed yet.

Are you still getting the same ECC_BAD_ARG_E = -170, / ECC input argument of wrong type / error?

I'd be interested in seeing all of your latest code if you can share it.

zhy2020 commented 1 year ago

Sorry I forgot to synchronize my progress, the program has not returned -170, I was mistaken private_key.pem file, I can get the correct shared_key. But when I used the generated shared_key to encrypt aec gcm, I got the wrong data

` int counter = 1; byte shared_key_hash[16]; static void generate_shared_key(void) { Sha sha[1]; byte shared_key[1024] = {0}; word32 shared_key_len = sizeof(shared_key); RNG rng; int ret = 0;

// private_key set rng
wc_InitRng(&rng);

ret = wc_ecc_set_rng(&private_key, &rng);
if (ret == 0)
{
    ESP_LOGI(TAG, "Successfully called wc_ecc_set_rng for a_private_key");
}
else
{
    ESP_LOGE(TAG, "Failed wc_ecc_set_rng for a_private_key. Error = %d", ret);
}

// create shared
ret = wc_ecc_shared_secret(&private_key, &vehicle_key, shared_key, &shared_key_len);
if (ret != 0)
{
    ESP_LOGI(TAG, "========= wc_ecc_shared_secret error %d", ret);
}
else
{
    ESP_LOGI(TAG, "Successfully called wc_ecc_shared_secret for my_ecc_private_key and my_ecc_public_key");
    ESP_LOG_BUFFER_HEX_LEVEL(TAG, shared_key, shared_key_len, ESP_LOG_INFO);
}

if ((wc_InitSha(sha)) != 0)
{
    ESP_LOGI(TAG, "wc_InitSha failed");
}
else
{
    wc_ShaUpdate(sha, (byte *)shared_key, shared_key_len);
    wc_ShaFinal(sha, shared_key_hash);
}

ESP_LOGI(TAG, "shared_key_hash");
dump_bytes_stderr(16, (uint8_t *)shared_key_hash); 

}

generate_shared_key(); // shared_key_hash : hex=> e0 44 b6 42 34 95 32 80 c5 34 a5 dc d9 7f ac de

nonce[0] = (counter >> 24) & 255;
nonce[1] = (counter >> 16) & 255;
nonce[2] = (counter >> 8) & 255;
nonce[3] = counter & 255;

uint8_t _to_vcsecmessage_pack; // hex=> 12 04 1a 02 08 02 / Create and initialize AES key */ Aes aes;

/* Create and initialize GCM context */
wc_AesInit(&aes, NULL, 0);

int ret = wc_AesGcmSetKey(&aes, (const byte*)shared_key_hash, 16);
if (ret != 0) {
    printf("Failed to set GCM key, error %d\n", ret);

}

ret = wc_AesGcmEncrypt(&aes, (byte*)ciphertext, (const byte*)_to_vcsecmessage_pack, 22, (const byte* )nonce, 4, NULL, 16, NULL, 16);
if (ret != 0) {
    printf("Failed to encrypt, error %d\n", ret);
}

dump_bytes_stderr(22, ciphertext);  // hex => 9f 7b 96 df a7 c5 d6 35 26 ea e4 9b a5 ea 38 5d 3c b6 e9 ce d7 3b

`

but by python3 code:

` encryptor = AESGCM(shared_key_hash) nonce = bytearray() nonce.append((1 >> 24) & 255) nonce.append((1 >> 16) & 255) nonce.append((1 >> 8) & 255) nonce.append(1 & 255)

encrypted_msg = encryptor.encrypt( nonce, _to_vcsecmessage_pack, None ) print("encrypted_msg", encrypted_msg.hex(" "))

// 9f 7b 96 df a7 c5 3e b0 9d 0d c8 6e c3 5b 12 01 bf 05 d4 dd 17 e4 ` Where does the program need to be modified?

gojimmypi commented 1 year ago

Hi @zhy2020 I've not had a chance to look at this, but I'm wondering about your memory utilization? Have you checked heap & stack and available memory? For instance, an app I'm working on now... just changing from "no optimization debug" to "optimize for size" had this impact on memory:

Used DATA_FLASH: 143KB out of 8192KB (1%) [-23K]
Used INSTR_FLASH: 465KB out of 3264KB (14%) [-284K]
Used INSTR_RAM: 53KB out of 128KB (42%) [-43K]
Used DATA_RAM: 26KB out of 320KB (8%) [-1824]

Notice in particular the whopping 43K just by changing an optimization setting.

Have you tried turning on "stack smashing" and "heap poisoning" to determine if the failure is memory-related?

zhy2020 commented 1 year ago

Sorry, I am an amateur developer on esp32 platform, I don't know how to test as you said, do you have time to help me solve this problem? thank you

gojimmypi commented 1 year ago

Hi @zhy2020 - if using the VisualGDB extension, the heap and stack terms can be searched:

image

image

If using the command-line idf.py (idf.py menuconfig), the heap settings can be found under component config:

image

Stack settings under component config - system settings:

image

Stack smashing under compiler options:

image

Also, I've been working on a similar and possibly related issue in https://github.com/wolfSSL/wolfssl/issues/6205 - I'd be interested in seeing if the above stack and heap issues are not causing a problem, then perhaps try turning off hardware acceleration to see if it makes any difference.

I've had limited available time, but indeed I do plan on resolving this problem and creating a robust example.