I have following ECC private and public key pairs:
Private key : 0x63bd3b01c5ce749d87f5f7481232a93540acdb0f7b5c014ecd9cd32b041d6f33
Public Key : 0x04017655e42a892cc71bccedcb1cd421d03530e1d7edb52cef143c5562c4c6f0129fa5a37738013e64a1ff0e6cb7068815a13000eb162cb7a0214dfcf3c8fa101c
Curve : SECP256R1
I want to load these keys in Python to perform signing operations. Can you please suggest possible steps?
(I am comfortable to use "openssl ec" tools if necessary.)
Here is a simple example (using python 3 + cryptography module) loading your key to sign/verify:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature
private_value = 0x63bd3b01c5ce749d87f5f7481232a93540acdb0f7b5c014ecd9cd32b041d6f33
curve = ec.SECP256R1()
signature_algorithm = ec.ECDSA(hashes.SHA256())
# Make private and public keys from the private value + curve
priv_key = ec.derive_private_key(private_value, curve, default_backend())
pub_key = priv_key.public_key()
print('Private key: 0x%x' % priv_key.private_numbers().private_value)
print('Public point (Uncompressed): 0x%s' % pub_key.public_bytes(serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint).hex())
# Sign some data
data = b"this is some data to sign"
signature = priv_key.sign(data, signature_algorithm)
print('Signature: 0x%s' % signature.hex())
# Verify
try:
pub_key.verify(signature, data, signature_algorithm)
print('Verification OK')
except InvalidSignature:
print('Verification failed')
This will display:
Private key: 0x63bd3b01c5ce749d87f5f7481232a93540acdb0f7b5c014ecd9cd32b041d6f33
Public point (Uncompressed): 0x04017655e42a892cc71bccedcb1cd421d03530e1d7edb52cef143c5562c4c6f0129fa5a37738013e64a1ff0e6cb7068815a13000eb162cb7a0214dfcf3c8fa101c
Signature: 0x304402200308ac7b7a56e7227d665d8f652d849935b4876c5ecef252ed9713c975b0a6280220696c134bb6e115b9ac18790c27009938f081bfaf063e547ce75bad3c9682890b
Verification OK
You can use the ECC.construct(**kwargs)
call to construct keys from the respective integers.
I've shown below how to do this for an uncompressed point in hex and then bytes rather than as a number though. An uncompressed point is not a number in itself. So I haven't included the 0x
in your question for these byte arrays.
The private key vector (usually denoted s
or d
, I prefer s
for secret) is a number, but generally it will be transmitted using bytes as well (if it is ever transmitted, usually it is kept in place).
from Crypto.PublicKey import ECC
# --- ECC public key from "flat" uncompressed EC point representation ---
# lets assume that the input is binary, rather than an integer
uncompressedPointHex = "04017655e42a892cc71bccedcb1cd421d03530e1d7edb52cef143c5562c4c6f0129fa5a37738013e64a1ff0e6cb7068815a13000eb162cb7a0214dfcf3c8fa101c"
uncompressedPoint = bytes.fromhex(uncompressedPointHex)
# check if the point is uncompressed rather than compressed
# for compressed points ask a separate *question*
off = 0
if (uncompressedPoint[off] != 0x04):
raise Exception("Not an uncompressed point")
off += 1
sizeBytes = (len(uncompressedPoint) - 1) // 2
xBin = uncompressedPoint[off:off + sizeBytes]
x = int.from_bytes(xBin, 'big', signed=False)
off += sizeBytes
yBin = uncompressedPoint[off:off + sizeBytes]
y = int.from_bytes(yBin, 'big', signed=False)
off += sizeBytes
if (off != len(uncompressedPoint)):
raise Exception("Invalid format of uncompressed point")
# if you already have integers, this is all you need
publicKey = ECC.construct(curve="secp256r1", point_x=x, point_y=y)
# obviously just for testing the result
print(publicKey)
# --- ECC private key from "flat" uncompressed EC point representation ---
# lets assume that the input is binary, rather than an integer
sHex = "63bd3b01c5ce749d87f5f7481232a93540acdb0f7b5c014ecd9cd32b041d6f33"
sBin = bytes.fromhex(sHex)
# very straightforward conversion, as S is just there
s = int.from_bytes(sBin, 'big', signed=False)
# if you already have integers, this is all you need
privateKey = ECC.construct(curve="secp256r1", d=s)
# obviously just for testing the result
print(privateKey)
outputs
EccKey(curve='NIST P-256',
point_x=661393602013979783798470650260404653019684003375182707210783968552030760978,
point_y=72210400889213969389982861398963807410315877398616325431902307461337204789276)
EccKey(curve='NIST P-256',
point_x=661393602013979783798470650260404653019684003375182707210783968552030760978,
point_y=72210400889213969389982861398963807410315877398616325431902307461337204789276,
d=45113313355812346734724097146216873116458888764597604491161664272788312911667)
...slightly formatted with whitespace to show that the second key is indeed the private key containing d.
The x
and y
values can be calculated from d
(point multiplication with the base point: d*G
), which is why the private key can contain them without having them specified during construction.
Note that I've used Python 3, maybe some Python dev is able to convert it to Python 2 and include the result in this answer. The idea / calls should be similar after all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With