diff --git a/EvpTestRecipes/3.0/evppkey_ecx.txt b/EvpTestRecipes/3.0/evppkey_ecx.txt index 9e8144e8..e8a0dd1b 100644 --- a/EvpTestRecipes/3.0/evppkey_ecx.txt +++ b/EvpTestRecipes/3.0/evppkey_ecx.txt @@ -89,3 +89,221 @@ Result = KEYPAIR_MISMATCH PrivPubKeyPair = Bob-25519:Alice-25519-PUBLIC Result = KEYPAIR_MISMATCH + +Title = X25519 non-canonical public keys + +# reduces to u = 2 mod p +PublicKeyRaw=NonCanonical-Pub-1:X25519:efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-1 +SharedSecret=E80C0BE9D3A1C5D71EDD6316E8C9115CA35397CD47109BD38E32864F1ADECF4D + +# reduces to u = 3 mod p +PublicKeyRaw=NonCanonical-Pub-2:X25519:f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-2 +SharedSecret=2B6282A3A5AA1380B79D8ED2F73811F182E35E17E25A86D23C4D2F65713A6B7F + +# high bit set AND value >= p after masking, reduces to u = 3 mod p +PublicKeyRaw=NonCanonical-Pub-3:X25519:f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-3 +SharedSecret=2B6282A3A5AA1380B79D8ED2F73811F182E35E17E25A86D23C4D2F65713A6B7F + +# reduces to u = 4 mod p +PublicKeyRaw=NonCanonical-Pub-4:X25519:f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-4 +SharedSecret=3DC4B23E14B1E04DA492BAEBA54AE9CF9CD5298713903E6238E5128B31FA5E4E + +# reduces to u = 5 mod p +PublicKeyRaw=NonCanonical-Pub-5:X25519:f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-5 +SharedSecret=717EFC3F25E74904CCDF9896B6EB5836E85A45B5A7A26F9E3ACF91F0EB7D3F4A + +# reduces to u = 6 mod p +PublicKeyRaw=NonCanonical-Pub-6:X25519:f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-6 +SharedSecret=0FD3892BF714427086056B360E24A98CF0EE50BA6DC45744EBAA0BB8F9BC1F27 + +# reduces to u = 7 mod p +PublicKeyRaw=NonCanonical-Pub-7:X25519:f4ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-7 +SharedSecret=AF4F41D8794E87F83BEF3BF7B0929D43133911C25C5105AFB221A79FC9946C59 + +# reduces to u = 8 mod p +PublicKeyRaw=NonCanonical-Pub-8:X25519:f5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-8 +SharedSecret=C8F33C10FCF2B405BB6097703DE0D4E706522736FAE188E1EBF7E4C1BCC2211B + +# reduces to u = 9 (the base point) mod p +PublicKeyRaw=NonCanonical-Pub-9:X25519:f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-9 +SharedSecret=8520F0098930A754748B7DDCB43EF75A0DBF3A0D26381AF4EBA4A98EAA9B4E6A + +# reduces to u = 10 mod p +PublicKeyRaw=NonCanonical-Pub-10:X25519:f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-10 +SharedSecret=01EE50445ED8B4AE530677B182359A0E41312B80EA4CC72185D18F352F485065 + +# reduces to u = 11 mod p +PublicKeyRaw=NonCanonical-Pub-11:X25519:f8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-11 +SharedSecret=E087CBDC36A1C45005481BC63B949590DCDC0F538A04C9BBC1C13E3DB0B82A52 + +# reduces to u = 12 mod p +PublicKeyRaw=NonCanonical-Pub-12:X25519:f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-12 +SharedSecret=98205C5722464A4FEFA3535D51BB4BFD25E7F1584A4DD7AFA74CE035D058892A + +# reduces to u = 13 mod p +PublicKeyRaw=NonCanonical-Pub-13:X25519:faffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-13 +SharedSecret=B8042BA97FC573CA543F1D05A56F3DC45BE0CB1B13CB9E01F07386E479980314 + +# reduces to u = 14 mod p +PublicKeyRaw=NonCanonical-Pub-14:X25519:fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-14 +SharedSecret=53446A13586F563B6C32B9F40FA122A5F15AF45C5E750003A27C280CD39BC340 + +# reduces to u = 15 mod p +PublicKeyRaw=NonCanonical-Pub-15:X25519:fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-15 +SharedSecret=FD5168B75730FD82D6392D05D53E2346CCD2F0895D4588F68977BE2BD719BA3B + +# reduces to u = 16 mod p +PublicKeyRaw=NonCanonical-Pub-16:X25519:fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-16 +SharedSecret=2FEF9732A4204D308743EC3DF457D9F6AF7AB3601097E4201FF04D773EC4C815 + +# reduces to u = 17 mod p +PublicKeyRaw=NonCanonical-Pub-17:X25519:feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-17 +SharedSecret=81A02A45014594332261085128959869FC0540C6B12380F51DB4B41380DE2C2C + +# reduces to u = 18 mod p +PublicKeyRaw=NonCanonical-Pub-18:X25519:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=NonCanonical-Pub-18 +SharedSecret=359668D79A67267A57FFEF8F0F4A9882A7C0E3122CB1999C5626346383F9F811 + +# Non-canonical p+0 (reduces to u = 0, identity) and p+1 (reduces to u = 1, low-order) +# are tested in the low-order section below as LowOrder-Pub-6-Identity-NonCanonical +# and LowOrder-Pub-5-NonCanonical respectively. + +Title = X25519 high bit (bit 255) set + +# Canonical non-low-order key with high bit set: must produce same shared secret +# Tests that bit 255 is masked before use +PublicKeyRaw=HighBit-Pub-1:X25519:de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882bcf + +Derive=Alice-25519-Raw +PeerKey=HighBit-Pub-1 +SharedSecret=4A5D9D5BA4CE2DE1728E3BF480350F25E07E21C947D19E3376F09B3C1E161742 + +# Canonical low-order key (u = 0) with high bit set +PublicKeyRaw=HighBit-LowOrder-Pub-1:X25519:0000000000000000000000000000000000000000000000000000000000000080 + +Derive=Alice-25519-Raw +PeerKey=HighBit-LowOrder-Pub-1 +Result=DERIVE_ERROR + +# Non-canonical (p+2, reduces to u = 2) with high bit set +# Tests that high bit is masked BEFORE non-canonical reduction +PublicKeyRaw=HighBit-NonCanonical-Pub-1:X25519:efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +Derive=Alice-25519-Raw +PeerKey=HighBit-NonCanonical-Pub-1 +SharedSecret=E80C0BE9D3A1C5D71EDD6316E8C9115CA35397CD47109BD38E32864F1ADECF4D + +# Non-canonical (p+1, reduces to u = 1, low-order) with high bit set +# Tests high-bit masking + non-canonical reduction + low-order rejection +PublicKeyRaw=HighBit-NonCanonical-Pub-2:X25519:eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +Derive=Alice-25519-Raw +PeerKey=HighBit-NonCanonical-Pub-2 +Result=DERIVE_ERROR + +Title = X25519 low-order public keys + +# u = 0 (identity) +PublicKeyRaw=LowOrder-Pub-0:X25519:0000000000000000000000000000000000000000000000000000000000000000 + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-0 +Result=DERIVE_ERROR + +# u = 1 (low-order point) +PublicKeyRaw=LowOrder-Pub-1:X25519:0100000000000000000000000000000000000000000000000000000000000000 + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-1 +Result=DERIVE_ERROR + +# Wycheproof low-order point on the curve +PublicKeyRaw=LowOrder-Pub-2:X25519:e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800 + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-2 +Result=DERIVE_ERROR + +# Wycheproof low-order point on the twist +PublicKeyRaw=LowOrder-Pub-3:X25519:5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157 + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-3 +Result=DERIVE_ERROR + +# u = p - 1 (low-order) +PublicKeyRaw=LowOrder-Pub-4:X25519:ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-4 +Result=DERIVE_ERROR + +# Non-canonical encoding of u = 1 (value = 1 + p = eeff..ff7f) +# Tests both canonicalization AND low-order rejection +PublicKeyRaw=LowOrder-Pub-5-NonCanonical:X25519:eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-5-NonCanonical +Result=DERIVE_ERROR + +# Non-canonical encoding of identity (value = p = edff...ff7f, reduces to 0) +# Acceptance criterion #3: identity must be rejected +PublicKeyRaw=LowOrder-Pub-6-Identity-NonCanonical:X25519:edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f + +Derive=Alice-25519-Raw +PeerKey=LowOrder-Pub-6-Identity-NonCanonical +Result=DERIVE_ERROR diff --git a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c index 5681b523..368c79ac 100644 --- a/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c +++ b/SymCryptProvider/src/keymgmt/p_scossl_ecc_keymgmt.c @@ -13,7 +13,6 @@ extern "C" { #endif -#define SCOSSL_X25519_MAX_SIZE (32) #define SCOSSL_ECC_DEFAULT_DIGEST SN_sha256 #define SCOSSL_ECC_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_PUBLIC_KEY | OSSL_KEYMGMT_SELECT_PRIVATE_KEY | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) @@ -527,6 +526,7 @@ static SCOSSL_STATUS p_scossl_ecc_keymgmt_set_params(_Inout_ SCOSSL_ECC_KEY_CTX SCOSSL_STATUS ret = SCOSSL_FAILURE; SYMCRYPT_NUMBER_FORMAT numFormat = keyCtx->isX25519 ? SYMCRYPT_NUMBER_FORMAT_LSB_FIRST : SYMCRYPT_NUMBER_FORMAT_MSB_FIRST; SYMCRYPT_ECPOINT_FORMAT pointFormat = keyCtx->isX25519 ? SYMCRYPT_ECPOINT_FORMAT_X : SYMCRYPT_ECPOINT_FORMAT_XY; + UINT32 flags = SYMCRYPT_FLAG_ECKEY_ECDH; const OSSL_PARAM *p; if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY)) != NULL) @@ -553,6 +553,16 @@ static SCOSSL_STATUS p_scossl_ecc_keymgmt_set_params(_Inout_ SCOSSL_ECC_KEY_CTX ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); goto cleanup; } + + if (cbPublicKey != SCOSSL_X25519_KEY_SIZE) + { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + goto cleanup; + } + + p_scossl_x25519_canonicalize_public_key(pbPublicKey); + + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; } else { @@ -585,7 +595,7 @@ static SCOSSL_STATUS p_scossl_ecc_keymgmt_set_params(_Inout_ SCOSSL_ECC_KEY_CTX pbPublicKey, cbPublicKey, numFormat, pointFormat, - SYMCRYPT_FLAG_ECKEY_ECDH, + flags, keyCtx->key); if (scError != SYMCRYPT_NO_ERROR) { @@ -1102,6 +1112,14 @@ static SCOSSL_STATUS p_scossl_x25519_keymgmt_import(_Inout_ SCOSSL_ECC_KEY_CTX * ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); goto cleanup; } + + if (cbPublicKey != SCOSSL_X25519_KEY_SIZE) + { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + goto cleanup; + } + + p_scossl_x25519_canonicalize_public_key(pbPublicKey); } if ((p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL) @@ -1112,6 +1130,12 @@ static SCOSSL_STATUS p_scossl_x25519_keymgmt_import(_Inout_ SCOSSL_ECC_KEY_CTX * goto cleanup; } + if (cbPrivateKey != SCOSSL_X25519_KEY_SIZE) + { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + goto cleanup; + } + // Preserve original bits for export keyCtx->modifiedPrivateBits = pbPrivateKey[0] & 0x07; keyCtx->modifiedPrivateBits |= pbPrivateKey[cbPrivateKey-1] & 0xc0; @@ -1126,7 +1150,7 @@ static SCOSSL_STATUS p_scossl_x25519_keymgmt_import(_Inout_ SCOSSL_ECC_KEY_CTX * pbPublicKey, cbPublicKey, SYMCRYPT_NUMBER_FORMAT_LSB_FIRST, SYMCRYPT_ECPOINT_FORMAT_X, - SYMCRYPT_FLAG_ECKEY_ECDH, + SYMCRYPT_FLAG_ECKEY_ECDH | SYMCRYPT_FLAG_KEY_NO_FIPS, keyCtx->key); if (scError != SYMCRYPT_NO_ERROR) { diff --git a/SymCryptProvider/src/p_scossl_ecc.c b/SymCryptProvider/src/p_scossl_ecc.c index 704c7803..4e2704c1 100644 --- a/SymCryptProvider/src/p_scossl_ecc.c +++ b/SymCryptProvider/src/p_scossl_ecc.c @@ -11,7 +11,33 @@ extern "C" { #endif -#define SCOSSL_X25519_MAX_SIZE (32) +// Canonicalize an X25519 public key in place per RFC 7748 section 5. +// Masks the high bit (bit 255) and reduces non-canonical values (>= p = 2^255 - 19) +// modulo p. The buffer must be exactly 32 bytes and mutable. +_Use_decl_annotations_ +void p_scossl_x25519_canonicalize_public_key(PBYTE pbPublicKey) +{ + pbPublicKey[31] &= 0x7f; + + if (pbPublicKey[0] >= 0xed && pbPublicKey[31] == 0x7f) + { + BOOL nonCanonical = TRUE; + for (SIZE_T i = 1; i < 31; i++) + { + if (pbPublicKey[i] != 0xff) + { + nonCanonical = FALSE; + break; + } + } + + if (nonCanonical) + { + pbPublicKey[0] -= 0xed; + memset(&pbPublicKey[1], 0, 31); + } + } +} _Use_decl_annotations_ SCOSSL_ECC_KEY_CTX *p_scossl_ecc_new_ctx(SCOSSL_PROVCTX *provctx) @@ -53,6 +79,7 @@ SCOSSL_ECC_KEY_CTX *p_scossl_ecc_dup_ctx(SCOSSL_ECC_KEY_CTX *keyCtx, int selecti SIZE_T cbPrivateKey = 0; SCOSSL_STATUS success = SCOSSL_FAILURE; SYMCRYPT_ECPOINT_FORMAT pointFormat = keyCtx->isX25519 ? SYMCRYPT_ECPOINT_FORMAT_X : SYMCRYPT_ECPOINT_FORMAT_XY; + UINT32 flags = SYMCRYPT_FLAG_ECKEY_ECDH; SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; SCOSSL_ECC_KEY_CTX *copyCtx = OPENSSL_zalloc(sizeof(SCOSSL_ECC_KEY_CTX)); @@ -120,13 +147,18 @@ SCOSSL_ECC_KEY_CTX *p_scossl_ecc_dup_ctx(SCOSSL_ECC_KEY_CTX *keyCtx, int selecti goto cleanup; } + if (keyCtx->isX25519) + { + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; + } + // Default ECDH only. If the key is used for ECDSA then we call SymCryptEckeyExtendKeyUsage scError = SymCryptEckeySetValue( pbPrivateKey, cbPrivateKey, pbPublicKey, cbPublicKey, SYMCRYPT_NUMBER_FORMAT_MSB_FIRST, pointFormat, - SYMCRYPT_FLAG_ECKEY_ECDH, + flags, copyCtx->key); if (scError != SYMCRYPT_NO_ERROR) { @@ -234,7 +266,7 @@ SIZE_T p_scossl_ecc_get_max_result_size(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, BOOL is { if (keyCtx->isX25519) { - return SCOSSL_X25519_MAX_SIZE; + return SCOSSL_X25519_KEY_SIZE; } else if (isEcdh) { @@ -492,6 +524,7 @@ SCOSSL_STATUS p_scossl_ecc_set_encoded_key(SCOSSL_ECC_KEY_CTX *keyCtx, PBYTE pbPublicKey = NULL; SIZE_T cbPublicKey = 0; PBYTE pbPrivateKey = NULL; + UINT32 flags = SYMCRYPT_FLAG_ECKEY_ECDH; SYMCRYPT_ERROR scError; SCOSSL_STATUS ret = SCOSSL_FAILURE; @@ -504,6 +537,14 @@ SCOSSL_STATUS p_scossl_ecc_set_encoded_key(SCOSSL_ECC_KEY_CTX *keyCtx, { numFormat = SYMCRYPT_NUMBER_FORMAT_LSB_FIRST; pointFormat = SYMCRYPT_ECPOINT_FORMAT_X; + flags |= SYMCRYPT_FLAG_KEY_NO_FIPS; + + if ((pbEncodedPublicKey != NULL && cbEncodedPublicKey != SCOSSL_X25519_KEY_SIZE) || + (pbEncodedPrivateKey != NULL && cbEncodedPrivateKey != SCOSSL_X25519_KEY_SIZE)) + { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + goto cleanup; + } } else { @@ -526,8 +567,15 @@ SCOSSL_STATUS p_scossl_ecc_set_encoded_key(SCOSSL_ECC_KEY_CTX *keyCtx, { if (keyCtx->isX25519) { - pbPublicKey = (PBYTE) pbEncodedPublicKey; + if ((pbPublicKey = OPENSSL_malloc(cbEncodedPublicKey)) == NULL) + { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + goto cleanup; + } cbPublicKey = cbEncodedPublicKey; + + memcpy(pbPublicKey, pbEncodedPublicKey, cbPublicKey); + p_scossl_x25519_canonicalize_public_key(pbPublicKey); } else { @@ -581,7 +629,7 @@ SCOSSL_STATUS p_scossl_ecc_set_encoded_key(SCOSSL_ECC_KEY_CTX *keyCtx, pbPublicKey, cbPublicKey, numFormat, pointFormat, - SYMCRYPT_FLAG_ECKEY_ECDH, + flags, keyCtx->key); if (scError != SYMCRYPT_NO_ERROR) { @@ -600,16 +648,11 @@ SCOSSL_STATUS p_scossl_ecc_set_encoded_key(SCOSSL_ECC_KEY_CTX *keyCtx, keyCtx->key = NULL; } - // X25519 needs to copy and decode the private key, other ECC needs - // to copy and decode the public key. + OPENSSL_free(pbPublicKey); if (keyCtx->isX25519) { OPENSSL_secure_clear_free(pbPrivateKey, cbEncodedPrivateKey); } - else - { - OPENSSL_free(pbPublicKey); - } EC_GROUP_free(ecGroup); EC_POINT_free(ecPoint); diff --git a/SymCryptProvider/src/p_scossl_ecc.h b/SymCryptProvider/src/p_scossl_ecc.h index ff02ef64..3e396b32 100644 --- a/SymCryptProvider/src/p_scossl_ecc.h +++ b/SymCryptProvider/src/p_scossl_ecc.h @@ -12,6 +12,8 @@ extern "C" { #endif +#define SCOSSL_X25519_KEY_SIZE (32) + typedef struct { OSSL_LIB_CTX *libctx; BOOL initialized; @@ -52,6 +54,8 @@ SIZE_T p_scossl_ecc_get_max_result_size(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, BOOL is SIZE_T p_scossl_ecc_get_encoded_key_size(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, int selection); SCOSSL_STATUS p_scossl_ecc_get_encoded_key(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, int selection, _Out_writes_bytes_(*pcbKey) PBYTE *ppbKey, _Out_ SIZE_T *pcbKey); +void p_scossl_x25519_canonicalize_public_key(_Inout_updates_(SCOSSL_X25519_KEY_SIZE) PBYTE pbPublicKey); + SCOSSL_STATUS p_scossl_ecc_set_encoded_key(_In_ SCOSSL_ECC_KEY_CTX *keyCtx, _In_reads_bytes_opt_(cbEncodedPublicKey) PCBYTE pbEncodedPublicKey, SIZE_T cbEncodedPublicKey, _In_reads_bytes_opt_(cbEncodedPrivateKey) PCBYTE pbEncodedPrivateKey, SIZE_T cbEncodedPrivateKey);