杰瑞科技汇

Linux下Python如何实现ECDSA签名与验证?

Of course! Here's a comprehensive guide to using the ecdsa library in Python on a Linux system, covering installation, key concepts, code examples, and best practices.

Linux下Python如何实现ECDSA签名与验证?-图1
(图片来源网络,侵删)

What is ECDSA?

ECDSA stands for Elliptic Curve Digital Signature Algorithm. It's a modern and highly efficient cryptographic standard used for:

  • Digital Signatures: Proving the authenticity and integrity of a message or data. (e.g., verifying a software update, signing a Git commit).
  • Key Agreement: Securely establishing a shared secret over an insecure channel. (e.g., in Elliptic Curve Diffie-Hellman - ECDH).

It's an alternative to older algorithms like RSA and DSA. Its main advantages are:

  • Smaller Key Sizes: Provides the same level of security as RSA with much smaller keys (e.g., a 256-bit ECDSA key is considered as strong as a 3072-bit RSA key).
  • Faster Operations: Signing and verification are significantly faster.

Installation on Linux

The ecdsa library is a pure Python implementation and is very easy to install using pip.

Ensure Python and Pip are installed:

Linux下Python如何实现ECDSA签名与验证?-图2
(图片来源网络,侵删)

Most modern Linux distributions come with Python 3 pre-installed. You can check with:

python3 --version
pip3 --version

If pip3 is not installed, you can usually install it with your system's package manager. For example, on Debian/Ubuntu:

sudo apt update
sudo apt install python3-pip

Install the ecdsa library:

This is a simple one-liner:

Linux下Python如何实现ECDSA签名与验证?-图3
(图片来源网络,侵删)
pip3 install ecdsa

This will download and install the library and its dependencies.


Core Concepts

Before diving into the code, let's understand the key components:

  • Curve: An elliptic curve is a mathematical curve defined by an equation. The ecdsa library supports several standard curves, the most common being:
    • secp256k1: Used by Bitcoin and other cryptocurrencies.
    • NIST256p (or P-256): A widely used general-purpose curve.
    • secp384r1 (or P-384): A stronger curve for higher security needs.
  • Private Key: A secret number that you must keep secret. It's used to create digital signatures. Anyone with your private key can impersonate you.
  • Public Key: A number derived from your private key using the curve's mathematics. You can (and should) share your public key freely. It's used to verify signatures created by your private key.
  • Signature: A pair of numbers (r, s) that proves you possess the private key corresponding to a public key, without actually revealing the private key. The signature is unique to the message being signed.

Code Examples

Let's go through the most common use cases.

Example 1: Generating a Key Pair

This is the first step. You generate a private key and derive its corresponding public key.

import ecdsa
import binascii
# 1. Choose a curve. Let's use the secp256k1 curve (common in crypto)
#    Other options: ecdsa.NIST256p, ecdsa.SECP384r1
curve = ecdsa.SECP256k1
# 2. Generate a new private key.
#    This is a large, random number.
#    In a real application, you MUST generate this securely (e.g., using os.urandom).
private_key = ecdsa.SigningKey.generate(curve=curve)
# 3. Get the private key in bytes (for storage)
private_key_bytes = private_key.to_string()
print(f"Private Key (hex): {binascii.hexlify(private_key_bytes).decode('utf-8')}")
# 4. Derive the public key from the private key
public_key = private_key.get_verifying_key()
# 5. Get the public key in bytes (for sharing)
#    The format includes a prefix indicating the curve type (e.g., 0x04 for uncompressed)
public_key_bytes = public_key.to_string()
print(f"Public Key (hex): {binascii.hexlify(public_key_bytes).decode('utf-8')}")
# You can also get the public key in different formats:
# PEM format (common for certificates and keys)
public_key_pem = public_key.to_pem()
print("\nPublic Key (PEM format):")
print(public_key_pem.decode('utf-8'))

Example 2: Signing and Verifying a Message

This is the core functionality of ECDSA.

import ecdsa
import hashlib
# Use the same key from the previous example (or generate a new one)
private_key = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
public_key = private_key.get_verifying_key()
# The message you want to sign
message = b"This is a secret message that needs to be authenticated."
# --- Signing ---
# 1. Hash the message. ECDSA signs the hash, not the raw message.
#    We use SHA256, a common and secure hash function.
message_hash = hashlib.sha256(message).digest()
# 2. Sign the hash with the private key
#    The signature is a tuple of two integers, r and s
signature = private_key.sign(message_hash)
print(f"Message: {message.decode('utf-8')}")
print(f"Signature (hex): {signature.hex()}")
# --- Verification ---
# In a real scenario, the verifier would have:
# 1. The original message
# 2. The signature
# 3. The sender's public key
# 1. Hash the message again (the verifier must do this independently)
message_hash_to_verify = hashlib.sha256(message).digest()
# 2. Verify the signature using the public key
try:
    is_valid = public_key.verify(signature, message_hash_to_verify)
    if is_valid:
        print("\nSignature is VALID!")
    else:
        print("\nSignature is INVALID!")
except ecdsa.BadSignatureError:
    print("\nSignature is INVALID! (BadSignatureError)")
# --- Verification with a tampered message ---
tampered_message = b"This is a TAMPERED message."
tampered_hash = hashlib.sha256(tampered_message).digest()
try:
    public_key.verify(signature, tampered_hash)
    print("Tampered message signature is valid (this should not happen)")
except ecdsa.BadSignatureError:
    print("\nTampered message signature is INVALID, as expected.")

Example 3: Key Serialization and Storage

You'll often need to store keys and load them back.

import ecdsa
import binascii
# --- Storing Keys ---
# Generate a key
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
vk = sk.get_verifying_key()
# Store private key in PEM format (includes curve info)
# This is a good, standard format for storage.
private_key_pem = sk.to_pem()
with open("private_key.pem", "wb") as f:
    f.write(private_key_pem)
# Store public key in PEM format
public_key_pem = vk.to_pem()
with open("public_key.pem", "wb") as f:
    f.write(public_key_pem)
# You can also store just the raw bytes (less portable, but smaller)
private_key_bytes = sk.to_string()
with open("private_key.bin", "wb") as f:
    f.write(private_key_bytes)
# --- Loading Keys ---
# Load private key from PEM file
with open("private_key.pem", "rb") as f:
    loaded_sk_pem = ecdsa.SigningKey.from_pem(f.read())
# Load public key from PEM file
with open("public_key.pem", "rb") as f:
    loaded_vk_pem = ecdsa.VerifyingKey.from_pem(f.read())
# Load private key from raw bytes file
with open("private_key.bin", "rb") as f:
    loaded_sk_bytes = ecdsa.SigningKey.from_string(f.read(), curve=ecdsa.SECP256k1)
# --- Verification that loaded keys work ---
message = b"Testing key loading."
signature = sk.sign(hashlib.sha256(message).digest())
# Verify using the loaded public key
try:
    loaded_vk_pem.verify(signature, hashlib.sha256(message).digest())
    print("\nSuccessfully signed and verified using loaded keys!")
except ecdsa.BadSignatureError:
    print("\nFailed to verify with loaded keys.")

Security Best Practices

  1. NEVER Hardcode Keys: Never put private keys directly in your source code. Load them from secure locations like environment variables, dedicated key management services (e.g., AWS KMS, HashiCorp Vault), or encrypted files.
  2. Secure Key Generation: Always use a cryptographically secure random number generator. The ecdsa library does this for you with generate(), but if you were implementing it yourself, you would use os.urandom().
  3. Use Standard Curves: Stick to well-vetted, standard curves like secp256k1, NIST256p, or secp384r1. Avoid creating your own curves or using obscure, non-standard ones.
  4. Hash Your Messages: Always hash your message with a strong algorithm (like SHA256) before signing. Signing the raw message is insecure and can lead to vulnerabilities.
  5. Handle Exceptions: Always wrap verification logic in a try...except ecdsa.BadSignatureError block to gracefully handle invalid signatures.
  6. Key Storage: If you must store keys on disk, encrypt the file containing the private key using a strong password. The cryptography library is excellent for this.
分享:
扫描分享到社交APP
上一篇
下一篇