ECDSA keys implementation for Python.
This extension uses OpenSSL for elliptic cryptography and is written in pure C. Its main purpose is to provide an interface suitable to the key operations used in OpenSSH. It means key save/load and data sign/verify.
The only requirements are CMake as build system, OpenSSL and Python.
To build the extension just use:
ecdsa$ mkdir build && cd build
ecdsa/build$ cmake ..
ecdsa/build$ make && make install
All the paths are detected automatically by default, but you can specify:
-
Where to find OpenSSL:
cmake \ -DOPENSSL_CRYPTO_LIBRARY=/home/openssl/lib/libcrypto.so \ -DOPENSSL_INCLUDE_DIR=/home/openssl/include \ -DOPENSSL_SSL_LIBRARY=/home/openssl/lib/libssl.so ..
-
Where to find Python:
cmake \ -DPYTHON_EXECUTABLE=/home/python/bin/python \ -DPYTHON_INCLUDE_DIR=/home/python/include/python2.7 \ -DPYTHON_LIBRARY=/home/python/lib/libpython2.7.so \ ..
-
Python site-packages directory where to install (taken from python itself by default):
cmake -DINSTALL_DIR=lib/python2.7/dist-packages -DCMAKE_INSTALL_PREFIX=/usr ..
-
Install the whole package into custom location
make DESTDIR=../debian/tmp install
All the options can be used in any combinations.
from ecdsa import Key
# Read the key
privateKeyString = open('/home/user/.ssh/id_ecdsa').read()
publicKeyString = open('/home/user/.ssh/id_ecdsa.pub').read().split(' ')[1] # strip prefix and comment
privateKey = Key.from_string(privateKeyString)
publicKey = Key.from_string(publicKeyString)
# Now sign something
data = 'some my data'
signature = privateKey.sign(data)
# And verify the signature
assert publicKey.verify(data, signature), "public key not belongs to the private one"
assert privateKey.verify(data, signature), "you should be able to verify by private key, as well"
# Check if the key can sign
assert privateKey.has_private()
assert not publicKey.has_private()
# generate new key
key = Key.generate(521)
# Display its fingerprint in SSH-compatible format
fp = ':'.join(x.encode('hex') for x in key.fingerprint())
print "Generated key ({kt}): {fp}".format(kt=key.nid_name(), fp=fp)
# write it for ssh
open('/home/user/.ssh/id_ecdsa', 'wb').write(key.to_pem())
open('/home/user/.ssh/id_ecdsa.pub', 'wb').write(
"{keyType} {key} {comment}".format(keyType=key.nid_name(), key=key.to_ssh(), comment="[email protected]")
)
# sign and verify data for ssh
import hashlib
def hash_for_key(key):
bits = key.bits()
if bits == 256:
return hashlib.sha256
elif bits == 384:
return hashlib.sha384
else:
return hashlib.sha512
data = 'some data to sign'
digest = hash_for_key(key)(data).digest()
signature = key.sign(digest)
assert key.verify(digest, signature) # Note, SSH always operates with digests!