Reads an EC key from its hexadecimal (base16) representation.
Public Declare Function ECC_ReadKeyByCurve Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strHexKey As String, ByVal strCurveName As String, ByVal nOptions As Long) As Long
nRet = ECC_ReadKeyByCurve(strOutput, Len(strOutput), strHexKey, strCurveName, nOptions)
long __stdcall ECC_ReadKeyByCurve(char *szOutput, long nOutChars, const char *szHexKey, const char *szCurveName, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a nonzero error code.
Public Function eccReadKeyByCurve
(szHexKey As String, szCurveName As String, Optional nOptions As Long = 0) As String
static std::string dipki::Ecc::ReadKeyByCurve (std::string hexKey, Curve curve, Publicity publicity=Publicity::PrivateKey)
static Ecc.read_key_by_curve(keyhex, curvename, ispublic=False)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output string is an ephemeral internal key string valid only for the current session. This internal key string can be used directly by functions such as ECC_DHSharedSecret or SIG_SignData. You can analyze the key string using ECC_QueryKey or save it in one of the supported key file formats using ECC_SaveKey or ECC_SaveEncKey. The input string is expected to be the hexadecimal (base16) representation of a private or public key.
NIST/SEC/Brainpool curves: A private key is represented by the hexadecimal encoding of its integer value encoded in octets
as per section 3 of [RFC5915].
A public key is represented by the hexadecimal encoding of the octet string as defined in section 4.3.6 of
[X9-63]; that is, 04||Px||Py
.
Only the uncompressed form of a public key (beginning "04") is supported due to patent issues.
It is an error if the key value is out of range or not a valid point on the curve.
Safe curves: Both private and public keys are represented by the hexadecimal encoding of its integer value encoded as a byte array in little-endian form as per [RFC7748] and [RFC8032]. For Ed25519 and X25519, the input string szHexKey is always expected to be a hexadecimal representation of exactly 32 bytes. Set nOptions as PKI_ECC_PRIVATE_KEY (default 0) or PKI_ECC_PUBLIC_KEY to indicate whether the key value represents a private or public key, respectively. Any 32-byte key string will be accepted as input and any required bit masking (e.g. for an X25519 private key) will be applied before use.
Supported curve names for szCurveName are:
Curve name | Alternative names | Remarks |
---|---|---|
secp192r1 | P-192 , P_192 , prime192v1 | NIST |
secp224r1 | P-224 , P_224 | NIST |
secp256r1 | P-256 , P_256 , prime256v1 | NIST |
secp384r1 | P-384 , P_384 | NIST |
secp521r1 | P-521 , P_521 | NIST |
secp256k1 | SEC/Bitcoin | |
Ed25519 | Safe EdDSA curve [RFC8032] | |
Ed448 | Safe EdDSA curve [RFC8032] | |
X25519 | Safe ECDH curve [RFC7748] | |
X448 | Safe ECDH curve [RFC7748] | |
brainpoolP256r1 | [RFC5639] | |
brainpoolP384r1 | [RFC5639] | |
brainpoolP512r1 | [RFC5639] |
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strHexKey As String Dim strCurveName As String Dim strQuery As String Dim strBuffer As String Dim strBase58 As String Dim abTemp() As Byte Dim nBytes As Long ' 1. A NIST P-192 public key in X9.63 uncompressed format strHexKey = _ "0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96" strCurveName = "prime192v1" ' A synonym for "P-192" Debug.Print "KEYHEX: " & strHexKey Debug.Print "CURVE: " & strCurveName ' Find required length of internal key string nChars = ECC_ReadKeyByCurve("", 0, strHexKey, strCurveName, 0) Debug.Print "ECC_ReadKeyByCurve returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadKeyByCurve(strIntKey, Len(strIntKey), strHexKey, strCurveName, 0) ' Find the key size in bits strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 0)" Debug.Print ' 2. A Bitcoin private key in base58 form strBase58 = "6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN" Debug.Print "KEYB58: " & strBase58 strCurveName = "secp256k1" ' Convert to a hex string nBytes = CNV_Base58ToBytes(0, 0, strBase58) Debug.Assert (nBytes > 0) ReDim abTemp(nBytes - 1) nBytes = CNV_Base58ToBytes(abTemp(0), nBytes, strBase58) strHexKey = cnvHexStrFromBytes(abTemp) Debug.Print "KEYHEX: " & strHexKey Debug.Print "CURVE: " & strCurveName ' Find required length of internal key string nChars = ECC_ReadKeyByCurve("", 0, strHexKey, strCurveName, 0) Debug.Print "ECC_ReadKeyByCurve returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadKeyByCurve(strIntKey, Len(strIntKey), strHexKey, strCurveName, 0) ' Find the key size in bits strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 1)" ' Extract the public key in hex form strQuery = "publicKey" nChars = ECC_QueryKey("", 0, strIntKey, strQuery, 0) strBuffer = String(nChars, " ") nChars = ECC_QueryKey(strBuffer, Len(strBuffer), strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" If nChars > 0 Then Debug.Print "[" & Left(strBuffer, nChars) & "]"
KEYHEX: 0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96 CURVE: prime192v1 ECC_ReadKeyByCurve returns 100 (expected +ve) ECC_QueryKey('keyBits')=192 (expected +ve) ECC_QueryKey('isPrivate')=0 (expected 0) KEYB58: 6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN KEYHEX: 4CA55366ADE9E9BC12319DFFC246F64EB7FA07755925B92CEFC92D740DBC51ED CURVE: secp256k1 ECC_ReadKeyByCurve returns 196 (expected +ve) ECC_QueryKey('keyBits')=256 (expected +ve) ECC_QueryKey('isPrivate')=1 (expected 1) ECC_QueryKey('publicKey')= [04654bacc2fc7a3bde0f8eb95dc5aac9ba1df732255cf7f2eb7e1e8e6edbb1f4188ff3752ac4bdf1e3a31a488747745dddcbabd33a10c3b52d737c092851da13c0]
Dim curveName As String Dim alicePrivateKeyHex As String Dim ourPrivateKey As String Dim nChars As Long curveName = "X25519" alicePrivateKeyHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" ' The old long way... nChars = ECC_ReadKeyByCurve(vbNullString, 0, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert nChars > 0 ourPrivateKey = String(nChars, " ") nChars = ECC_ReadKeyByCurve(ourPrivateKey, nChars, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) ' The new short way with a wrapper function ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert Len(ourPrivateKey) > 0 Debug.Print "Key curve=" & eccQueryKey(ourPrivateKey, "curveName", 0) & " keyBits=" & eccQueryKey(ourPrivateKey, "keyBits", 0)
Dim strCurveName As String Dim ourPrivateKey As String Dim theirPublicKey As String Dim lpZZ() As Byte ' Ref: RFC7748 Section 6.1 Const alicePrivateKeyHex As String = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" Const alicePublicKeyHex As String = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" Const bobPrivateKeyHex As String = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" Const bobPublicKeyHex As String = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" strCurveName = "X25519" ' 1. Alice's private + Bob's public ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(bobPublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ' 2. Bob's private + Alice's public ourPrivateKey = eccReadKeyByCurve(bobPrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(alicePublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"