ecdsa

package
v1.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 1, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

README

ECDSA

Elliptic Curve Digital Signature Algorithm for efficient digital signatures.

Overview

The ecdsa package provides ECDSA digital signatures using NIST-approved elliptic curves. It offers smaller key sizes and faster operations compared to RSA while maintaining equivalent security levels.

Features

  • Multiple Curves - P-256, P-384, P-521 support
  • Fast Signatures - Faster than RSA
  • Small Keys - 256-bit key ≈ 128-bit security (vs 3072-bit RSA)
  • NIST Standard - FIPS 186-4 compliant
  • Key Formats - PEM/PKCS8/PKIX support

Installation

go get -u github.com/common-library/go/security/crypto/ecdsa

Quick Start

import (
    "crypto/elliptic"
    "github.com/common-library/go/security/crypto/ecdsa"
)

// Generate key pair
keyPair := &ecdsa.KeyPair{}
keyPair.Generate(elliptic.P256())

// Sign message
signature, _ := keyPair.Sign("message")

// Verify signature
valid := keyPair.Verify("message", signature)

API Reference

KeyPair Methods
Generate
func (kp *KeyPair) Generate(curve elliptic.Curve) error

Generates ECDSA key pair on specified curve.

Curves:

  • elliptic.P256() - 256-bit (recommended for most applications)
  • elliptic.P384() - 384-bit (higher security)
  • elliptic.P521() - 521-bit (maximum security)
Sign
func (kp *KeyPair) Sign(message string) (Signature, error)

Creates digital signature.

Verify
func (kp *KeyPair) Verify(message string, signature Signature) bool

Verifies digital signature.

Examples

Basic Signing
package main

import (
    "crypto/elliptic"
    "fmt"
    "log"
    "github.com/common-library/go/security/crypto/ecdsa"
)

func main() {
    // Generate P-256 key pair
    keyPair := &ecdsa.KeyPair{}
    err := keyPair.Generate(elliptic.P256())
    if err != nil {
        log.Fatal(err)
    }
    
    // Sign message
    message := "Important message"
    signature, err := keyPair.Sign(message)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Signature R: %x\n", signature.R)
    fmt.Printf("Signature S: %x\n", signature.S)
    
    // Verify signature
    valid := keyPair.Verify(message, signature)
    if valid {
        fmt.Println("✓ Signature is valid")
    } else {
        fmt.Println("✗ Signature is invalid")
    }
}
Different Curve Sizes
package main

import (
    "crypto/elliptic"
    "fmt"
    "github.com/common-library/go/security/crypto/ecdsa"
)

func main() {
    curves := []struct {
        name  string
        curve elliptic.Curve
    }{
        {"P-256", elliptic.P256()},
        {"P-384", elliptic.P384()},
        {"P-521", elliptic.P521()},
    }
    
    for _, c := range curves {
        keyPair := &ecdsa.KeyPair{}
        keyPair.Generate(c.curve)
        
        privateKey, publicKey := keyPair.GetKeyPair()
        privKey := privateKey.Get()
        pubKey := publicKey.Get()
        
        fmt.Printf("%s:\n", c.name)
        fmt.Printf("  Private key size: %d bits\n", privKey.Params().BitSize)
        fmt.Printf("  Public key X: %d bytes\n", len(pubKey.X.Bytes()))
        fmt.Printf("  Public key Y: %d bytes\n", len(pubKey.Y.Bytes()))
    }
}
Key Export and Import
package main

import (
    "crypto/elliptic"
    "log"
    "os"
    "github.com/common-library/go/security/crypto/ecdsa"
)

func main() {
    // Generate and save
    keyPair := &ecdsa.KeyPair{}
    keyPair.Generate(elliptic.P256())
    
    privateKey, publicKey := keyPair.GetKeyPair()
    
    privatePem, _ := privateKey.GetPemPKCS8()
    publicPem, _ := publicKey.GetPemPKIX()
    
    os.WriteFile("ecdsa_private.pem", []byte(privatePem), 0600)
    os.WriteFile("ecdsa_public.pem", []byte(publicPem), 0644)
    
    // Load and use
    privatePem2, _ := os.ReadFile("ecdsa_private.pem")
    newPrivate := &ecdsa.PrivateKey{}
    newPrivate.SetPemPKCS8(string(privatePem2))
    
    signature, _ := newPrivate.Sign("test message")
    log.Printf("Signature created with loaded key: %v", signature)
}
Message Authentication
package main

import (
    "crypto/elliptic"
    "fmt"
    "github.com/common-library/go/security/crypto/ecdsa"
)

func authenticateMessage(message string, signature ecdsa.Signature, publicKeyPem string) bool {
    publicKey := &ecdsa.PublicKey{}
    err := publicKey.SetPemPKIX(publicKeyPem)
    if err != nil {
        return false
    }
    
    return publicKey.Verify(message, signature)
}

func main() {
    // Sender
    keyPair := &ecdsa.KeyPair{}
    keyPair.Generate(elliptic.P256())
    
    message := "Transfer $100 to account 12345"
    signature, _ := keyPair.Sign(message)
    
    _, publicKey := keyPair.GetKeyPair()
    publicPem, _ := publicKey.GetPemPKIX()
    
    // Receiver
    valid := authenticateMessage(message, signature, publicPem)
    if valid {
        fmt.Println("✓ Message authenticated")
    } else {
        fmt.Println("✗ Authentication failed")
    }
    
    // Tampered message
    tamperedValid := authenticateMessage("Transfer $999 to account 12345", signature, publicPem)
    if !tamperedValid {
        fmt.Println("✓ Tampered message detected")
    }
}

Best Practices

1. Choose Appropriate Curve
// Good: P-256 for most applications
keyPair.Generate(elliptic.P256())

// Good: P-384 for higher security requirements
keyPair.Generate(elliptic.P384())

// Consider: P-521 only if maximum security needed
keyPair.Generate(elliptic.P521())
2. Verify All Signatures
// Good: Always verify before trusting
if keyPair.Verify(message, signature) {
    processMessage(message)
}

// Avoid: Process without verification
processMessage(message)
3. Use Non-Deterministic Signatures
// ECDSA signatures are naturally non-deterministic
// Each signature for the same message will be different
// This is a security feature

Curve Comparison

Curve Key Size Security Level Performance
P-256 256 bits 128-bit Fast
P-384 384 bits 192-bit Moderate
P-521 521 bits 256-bit Slower

Equivalent RSA Key Sizes:

  • P-256 ≈ RSA 3072-bit
  • P-384 ≈ RSA 7680-bit
  • P-521 ≈ RSA 15360-bit

Security Considerations

  • Randomness: Each signature uses random nonce (automatically handled)
  • Signature Verification: Always required before trusting data
  • Curve Choice: P-256 suitable for most applications
  • Key Protection: Protect private keys with file permissions
  • Message Hashing: Messages are automatically hashed before signing

Performance Tips

  1. Reuse Keys - Generate once, use many times
  2. P-256 for Speed - Fastest curve with good security
  3. Batch Verification - Verify multiple signatures in parallel
  4. Cache Public Keys - Store frequently used public keys

ECDSA vs Other Algorithms

Feature ECDSA RSA Ed25519
Key Size Small Large Very Small
Speed Fast Slow Very Fast
Signatures Non-deterministic Deterministic (PSS) Deterministic
NIST Approved Yes Yes No
Use Case General Legacy/Compatibility Modern Apps

Dependencies

  • crypto/ecdsa - Go standard library
  • crypto/elliptic - Elliptic curve operations
  • crypto/rand - Cryptographic random generator
  • crypto/x509 - X.509 encoding

Further Reading

Documentation

Overview

Package ecdsa provides ECDSA digital signature cryptography.

This package implements Elliptic Curve Digital Signature Algorithm (ECDSA) with support for multiple NIST curves, signature generation and verification, and PEM format key storage.

Features

  • ECDSA key pair generation (P-256, P-384, P-521 curves)
  • Digital signature creation and verification
  • PEM/PKCS8/PKIX format support
  • SSH public key format conversion
  • Smaller key sizes than RSA

Basic Example

keyPair := &ecdsa.KeyPair{}
err := keyPair.Generate(elliptic.P256())
signature, _ := keyPair.Sign("message")
valid := keyPair.Verify("message", signature)

Package ecdsa provides ecdsa crypto related implementations.

Package ecdsa provides ecdsa crypto related implementations.

Package ecdsa provides ecdsa crypto related implementations.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type KeyPair

type KeyPair struct {
	// contains filtered or unexported fields
}

KeyPair provides ECDSA key pair operations.

func (*KeyPair) Generate

func (kp *KeyPair) Generate(curve elliptic.Curve) error

Generate creates a new ECDSA key pair.

Parameters

  • curve: Elliptic curve (P256, P384, or P521)

Returns

  • error: Error if generation fails, nil on success

Examples

P-256 curve (recommended for most applications):

keyPair := &ecdsa.KeyPair{}
err := keyPair.Generate(elliptic.P256())

P-384 curve (higher security):

err := keyPair.Generate(elliptic.P384())

func (*KeyPair) GetKeyPair

func (kp *KeyPair) GetKeyPair() (privateKey PrivateKey, publicKey PublicKey)

GetKeyPair retrieves the private and public keys.

Returns

  • privateKey: ECDSA private key
  • publicKey: ECDSA public key

Examples

privateKey, publicKey := keyPair.GetKeyPair()

func (*KeyPair) SetKeyPair

func (kp *KeyPair) SetKeyPair(privateKey PrivateKey, publicKey PublicKey)

SetKeyPair sets the private and public keys.

Parameters

  • privateKey: ECDSA private key
  • publicKey: ECDSA public key

Examples

keyPair.SetKeyPair(privateKey, publicKey)

func (*KeyPair) Sign

func (kp *KeyPair) Sign(message string) (Signature, error)

Sign creates a digital signature for the message.

Parameters

  • message: Text message to sign

Returns

  • Signature: ECDSA signature (R and S components)
  • error: Error if signing fails, nil on success

Examples

signature, err := keyPair.Sign("Hello, World!")

func (*KeyPair) Verify

func (kp *KeyPair) Verify(message string, signature Signature) bool

Verify verifies a digital signature.

Parameters

  • message: Original text message
  • signature: ECDSA signature to verify

Returns

  • bool: true if signature is valid, false otherwise

Examples

signature, _ := keyPair.Sign("message")
valid := keyPair.Verify("message", signature)

type PrivateKey

type PrivateKey struct {
	// contains filtered or unexported fields
}

PrivateKey is struct that provides private key related methods.

func (*PrivateKey) Get

func (pk *PrivateKey) Get() *ecdsa.PrivateKey

Get returns the underlying *ecdsa.PrivateKey.

This method provides direct access to the Go standard library ecdsa.PrivateKey for use with other crypto functions that require the native type.

Returns:

  • *ecdsa.PrivateKey: The underlying private key

Example:

nativeKey := privateKey.Get()
// Use with Go crypto functions
x509.MarshalECPrivateKey(nativeKey)

func (*PrivateKey) GetCurve

func (pk *PrivateKey) GetCurve() elliptic.Curve

GetCurve returns the elliptic curve used by this key.

This method retrieves the elliptic curve (P-256, P-384, or P-521) that was used to generate this key pair.

Returns:

  • elliptic.Curve: The elliptic curve of this key

Behavior:

  • Common curves: elliptic.P256(), P384(), P521()
  • The curve determines key size and security level

Example:

curve := privateKey.GetCurve()
fmt.Printf("Key uses curve: %s\n", curve.Params().Name)

func (*PrivateKey) GetPemEC

func (pk *PrivateKey) GetPemEC() (string, error)

GetPemEC encodes the private key as a PEM-encoded EC private key string.

This method converts the ECDSA private key to PEM format using the EC private key structure. The format uses "ECDSA PRIVATE KEY" as the PEM block type.

Returns:

  • string: PEM-encoded EC private key
  • error: Error if encoding fails

Behavior:

  • Output format: "-----BEGIN ECDSA PRIVATE KEY-----\n...\n-----END ECDSA PRIVATE KEY-----"
  • Includes the curve parameters
  • ECDSA-specific format

Example:

pemString, err := privateKey.GetPemEC()
if err != nil {
    log.Fatal(err)
}
os.WriteFile("ecdsa_private.pem", []byte(pemString), 0600)

func (*PrivateKey) GetPublicKey

func (pk *PrivateKey) GetPublicKey() PublicKey

GetPublicKey extracts the public key from the private key.

Every ECDSA private key contains the corresponding public key. This method creates a PublicKey instance containing the public key portion.

Returns:

  • PublicKey: The corresponding public key

Behavior:

  • The public key is derived from the private key's curve point
  • The returned public key can be safely shared with others
  • Useful for distributing public keys for signature verification

Example:

privateKey := &ecdsa.PrivateKey{}
privateKey.SetCurve(elliptic.P256())
publicKey := privateKey.GetPublicKey()
// Share publicKey with others for verification

func (*PrivateKey) Set

func (pk *PrivateKey) Set(privateKey *ecdsa.PrivateKey)

Set assigns an existing *ecdsa.PrivateKey to this PrivateKey instance.

This method allows setting the private key from an existing Go standard library ecdsa.PrivateKey, useful when loading keys from other sources.

Parameters:

  • privateKey: The ecdsa.PrivateKey to assign

Example:

nativeKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
privateKey := &ecdsa.PrivateKey{}
privateKey.Set(nativeKey)

func (*PrivateKey) SetCurve

func (pk *PrivateKey) SetCurve(curve elliptic.Curve) error

SetCurve generates a new ECDSA private key using the specified curve.

This is a convenience method that generates a new key pair on the specified elliptic curve and sets it as the current private key.

Parameters:

  • curve: The elliptic curve to use (P-256, P-384, or P-521)

Returns:

  • error: Error if key generation fails

Behavior:

  • Generates both private and public keys
  • Uses cryptographically secure random number generator
  • P-256 recommended for most applications

Example:

privateKey := &ecdsa.PrivateKey{}
err := privateKey.SetCurve(elliptic.P256())
if err != nil {
    log.Fatal(err)
}

func (*PrivateKey) SetPemEC

func (pk *PrivateKey) SetPemEC(pemEC string) error

SetPemEC loads a private key from a PEM-encoded EC private key string.

This method decodes a PEM-encoded EC private key and sets it as the current private key. The input should have the "ECDSA PRIVATE KEY" PEM block type.

Parameters:

  • pemEC: PEM-encoded EC private key string

Returns:

  • error: Error if decoding fails or format is invalid

Behavior:

  • Expects "-----BEGIN ECDSA PRIVATE KEY-----" header
  • Automatically detects the curve from key data
  • Validates the EC key structure

Example:

pemData, _ := os.ReadFile("ecdsa_private.pem")
privateKey := &ecdsa.PrivateKey{}
err := privateKey.SetPemEC(string(pemData))
if err != nil {
    log.Fatal(err)
}

func (*PrivateKey) Sign

func (pk *PrivateKey) Sign(message string) (Signature, error)

Sign creates a digital signature for the given message.

This method generates an ECDSA signature using the private key. The message is automatically hashed with SHA-256 before signing. Signatures are non-deterministic (each call produces a different signature for the same message).

Parameters:

  • message: The string to sign

Returns:

  • Signature: The signature containing R and S components
  • error: Error if signing fails

Behavior:

  • Message is hashed with SHA-256 automatically
  • Uses cryptographically secure random number generator
  • Signature format: {R, S} where both are big.Int

Example:

privateKey := &ecdsa.PrivateKey{}
privateKey.SetCurve(elliptic.P256())
signature, err := privateKey.Sign("message to sign")
if err != nil {
    log.Fatal(err)
}

func (*PrivateKey) Verify

func (pk *PrivateKey) Verify(message string, signature Signature) bool

Verify verifies a digital signature against the message.

This method verifies that a signature was created by the private key corresponding to this public key. The message is hashed with SHA-256 before verification.

Parameters:

  • message: The original message that was signed
  • signature: The signature to verify

Returns:

  • bool: true if signature is valid, false otherwise

Behavior:

  • Message is hashed with SHA-256 automatically
  • Timing-safe comparison
  • Returns false on any error (no error return)

Example:

valid := privateKey.Verify("message to sign", signature)
if valid {
    fmt.Println("Signature is valid")
}

type PublicKey

type PublicKey struct {
	// contains filtered or unexported fields
}

PublicKey is struct that provides public key related methods.

func (*PublicKey) Get

func (pk *PublicKey) Get() ecdsa.PublicKey

Get returns the underlying ecdsa.PublicKey.

This method provides direct access to the Go standard library ecdsa.PublicKey for use with other crypto functions that require the native type.

Returns:

  • ecdsa.PublicKey: The underlying public key (returned by value)

Example:

nativeKey := publicKey.Get()
// Use with Go crypto functions
x509.MarshalPKIXPublicKey(&nativeKey)

func (*PublicKey) GetPemPKIX

func (pk *PublicKey) GetPemPKIX() (string, error)

GetPemPKIX encodes the public key as a PEM-encoded PKIX string.

PKIX (Public-Key Infrastructure X.509) is the algorithm-agnostic public key format. This is the preferred format for modern applications as it can represent public keys from various algorithms (RSA, ECDSA, Ed25519, etc.).

Returns:

  • string: PEM-encoded PKIX public key
  • error: Error if encoding fails

Behavior:

  • Output format: "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
  • Algorithm-agnostic format (includes algorithm identifier)
  • Better interoperability with other systems

Example:

pemString, err := publicKey.GetPemPKIX()
if err != nil {
    log.Fatal(err)
}
os.WriteFile("ecdsa_public.pem", []byte(pemString), 0644)

func (*PublicKey) GetSsh

func (pk *PublicKey) GetSsh() (string, error)

GetSsh encodes the public key as an SSH authorized_keys format string.

This method converts the ECDSA public key to the SSH authorized_keys format, which is used for SSH authentication and other SSH-based systems.

Returns:

  • string: SSH authorized_keys format string
  • error: Error if encoding fails

Behavior:

  • Output format: "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY..." (single line)
  • Curve name included in format (nistp256, nistp384, nistp521)
  • Compatible with OpenSSH and other SSH implementations

Example:

sshKey, err := publicKey.GetSsh()
if err != nil {
    log.Fatal(err)
}
os.WriteFile("id_ecdsa.pub", []byte(sshKey), 0644)

func (*PublicKey) GetSshPublicKey

func (pk *PublicKey) GetSshPublicKey() (ssh.PublicKey, error)

GetSshPublicKey converts the public key to an ssh.PublicKey.

This method creates an ssh.PublicKey instance from the ECDSA public key, which can be used with the golang.org/x/crypto/ssh package for SSH operations.

Returns:

  • ssh.PublicKey: The SSH public key instance
  • error: Error if conversion fails

Behavior:

  • Returns a type that implements ssh.PublicKey interface
  • Can be used with ssh package functions
  • Preserves all key material including curve

Example:

sshPubKey, err := publicKey.GetSshPublicKey()
if err != nil {
    log.Fatal(err)
}
// Use with SSH package
cert := &ssh.Certificate{Key: sshPubKey}

func (*PublicKey) Set

func (pk *PublicKey) Set(publicKey ecdsa.PublicKey)

Set assigns an existing ecdsa.PublicKey to this PublicKey instance.

This method allows setting the public key from an existing Go standard library ecdsa.PublicKey, useful when loading keys from other sources.

Parameters:

  • publicKey: The ecdsa.PublicKey to assign

Example:

nativeKey := ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
publicKey := &ecdsa.PublicKey{}
publicKey.Set(nativeKey)

func (*PublicKey) SetPemPKIX

func (pk *PublicKey) SetPemPKIX(pemPKIX string) error

SetPemPKIX loads a public key from a PEM-encoded PKIX string.

This method decodes a PEM-encoded PKIX public key and sets it as the current public key. PKIX format is algorithm-agnostic and widely supported.

Parameters:

  • pemPKIX: PEM-encoded PKIX public key string

Returns:

  • error: Error if decoding fails or key is not ECDSA

Behavior:

  • Expects "-----BEGIN PUBLIC KEY-----" header
  • Automatically identifies ECDSA algorithm from key data
  • Type assertion ensures the key is ECDSA

Example:

pemData, _ := os.ReadFile("ecdsa_public.pem")
publicKey := &ecdsa.PublicKey{}
err := publicKey.SetPemPKIX(string(pemData))
if err != nil {
    log.Fatal(err)
}

func (*PublicKey) SetSsh

func (pk *PublicKey) SetSsh(sshKey string) error

SetSsh loads a public key from an SSH authorized_keys format string.

This method parses an SSH authorized_keys format string and sets the ECDSA public key. The format is commonly found in ~/.ssh/authorized_keys files.

Parameters:

  • sshKey: SSH authorized_keys format string (e.g., "ecdsa-sha2-nistp256 AAAAE...")

Returns:

  • error: Error if parsing fails or key is not ECDSA

Behavior:

  • Accepts single-line SSH format
  • Ignores comments and options if present
  • Type assertion ensures the key is ECDSA

Example:

sshData, _ := os.ReadFile("id_ecdsa.pub")
publicKey := &ecdsa.PublicKey{}
err := publicKey.SetSsh(string(sshData))
if err != nil {
    log.Fatal(err)
}

func (*PublicKey) SetSshPublicKey

func (pk *PublicKey) SetSshPublicKey(publicKey ssh.PublicKey) error

SetSshPublicKey loads a public key from an ssh.PublicKey.

This method converts an ssh.PublicKey instance to an ECDSA public key. The ssh.PublicKey must contain an ECDSA key, otherwise an error occurs.

Parameters:

  • publicKey: The ssh.PublicKey to convert

Returns:

  • error: Error if conversion fails or key is not ECDSA

Behavior:

  • Type assertion ensures the key is ECDSA
  • Marshals and unmarshals to ensure proper conversion
  • Replaces the current key if successful

Example:

sshPubKey, _ := ssh.ParsePublicKey(sshKeyBytes)
publicKey := &ecdsa.PublicKey{}
err := publicKey.SetSshPublicKey(sshPubKey)
if err != nil {
    log.Fatal(err)
}

func (*PublicKey) Verify

func (pk *PublicKey) Verify(message string, signature Signature) bool

Verify verifies a digital signature against the message.

This method verifies that a signature was created by the corresponding private key. The message is hashed with SHA-256 before verification, matching the Sign operation.

Parameters:

  • message: The original message that was signed
  • signature: The signature to verify (containing R and S components)

Returns:

  • bool: true if signature is valid, false otherwise

Behavior:

  • Message is hashed with SHA-256 automatically
  • Constant-time comparison (timing-safe)
  • Returns false on any error (no error return)

Example:

valid := publicKey.Verify("message to sign", signature)
if valid {
    fmt.Println("✓ Signature is valid")
} else {
    fmt.Println("✗ Signature is invalid")
}

type Signature

type Signature struct {
	R *big.Int
	S *big.Int
}

Signature represents an ECDSA digital signature with R and S components.

An ECDSA signature consists of two large integers (R and S) that together prove the authenticity and integrity of a message. Both components are required for signature verification.

Features:

  • Non-deterministic: Same message produces different signatures
  • Compact: Smaller than RSA signatures for equivalent security
  • Secure: Based on elliptic curve discrete logarithm problem

Security:

  • Each signature uses a unique random nonce automatically
  • Nonce reuse would reveal the private key (prevented by crypto/rand)
  • R and S are typically 32-48 bytes each depending on curve

Example:

signature := ecdsa.Signature{
    R: r,  // First signature component
    S: s,  // Second signature component
}

// Verify signature
valid := publicKey.Verify(message, signature)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL