Files
go-i2p/lib/crypto/ecdsa/ecdsa_p256_private.go

132 lines
3.4 KiB
Go

package ecdsa
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"math/big"
"github.com/go-i2p/go-i2p/lib/crypto/types"
"github.com/samber/oops"
)
type (
ECP256PrivateKey [32]byte
)
// Len implements types.SigningPrivateKey.
func (e *ECP256PrivateKey) Len() int {
return 32
}
// Sign implements types.Signer.
func (e *ECP256PrivateKey) Sign(data []byte) (sig []byte, err error) {
// Hash the data first using SHA-256
hash := sha256.Sum256(data)
return e.SignHash(hash[:])
}
// SignHash implements types.Signer.
func (e *ECP256PrivateKey) SignHash(h []byte) (sig []byte, err error) {
// Convert byte array to ECDSA private key
curve := elliptic.P256()
privateKey := new(ecdsa.PrivateKey)
privateKey.PublicKey.Curve = curve
privateKey.D = new(big.Int).SetBytes(e[:])
// Calculate public key coordinates
privateKey.PublicKey.X, privateKey.PublicKey.Y = curve.ScalarBaseMult(e[:])
// Sign the hash
r, s, err := ecdsa.Sign(rand.Reader, privateKey, h)
if err != nil {
return nil, oops.Errorf("failed to sign hash: %w", err)
}
// Format the signature as R || S
sigR := r.Bytes()
sigS := s.Bytes()
// Ensure each component is padded to 32 bytes
sig = make([]byte, 64)
copy(sig[32-len(sigR):32], sigR)
copy(sig[64-len(sigS):], sigS)
log.Debug("Generated ECDSA-P256 signature")
return sig, nil
}
// Decrypt implements types.Decrypter.
func (e *ECP256PrivateKey) Decrypt(data []byte) ([]byte, error) {
// ECDSA doesn't typically provide decryption functionality
// This would require ECDH key derivation + symmetric decryption
// Implementing this for simplicity/compatibility
return nil, oops.Errorf("decryption not supported with ECDSA keys")
}
// Bytes implements types.PrivateKey.
func (e *ECP256PrivateKey) Bytes() []byte {
return e[:]
}
// Public implements types.PrivateKey.
func (e *ECP256PrivateKey) Public() (types.SigningPublicKey, error) {
curve := elliptic.P256()
// Calculate public key
x, y := curve.ScalarBaseMult(e[:])
if x == nil || y == nil {
return nil, oops.Errorf("failed to generate public key from private key")
}
// Encode public key as compressed point
publicKey := ECP256PublicKey{}
// Format as uncompressed point (0x04 || x || y)
xBytes := x.Bytes()
yBytes := y.Bytes()
// Copy coordinates to the public key
// P-256 coordinates are 32 bytes each
copy(publicKey[0:32], xBytes)
copy(publicKey[32:64], yBytes)
log.Debug("Generated ECDSA-P256 public key from private key")
return publicKey, nil
}
// Zero implements types.PrivateKey.
func (e *ECP256PrivateKey) Zero() {
// Securely erase the private key material
for i := range e {
e[i] = 0
}
log.Debug("Zeroed ECDSA-P256 private key")
}
// Generate implements SigningPrivateKey.Generate
func (e *ECP256PrivateKey) Generate() (types.SigningPrivateKey, error) {
// Generate a new private key
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, oops.Errorf("failed to generate ECDSA-P256 key: %w", err)
}
// Convert to our format
result := &ECP256PrivateKey{}
// Copy private key bytes with proper padding
dBytes := privateKey.D.Bytes()
copy(result[32-len(dBytes):], dBytes)
log.Debug("Generated new ECDSA-P256 private key")
return result, nil
}
// NewSigner implements SigningPrivateKey.NewSigner
func (e *ECP256PrivateKey) NewSigner() (types.Signer, error) {
// This key already implements the Signer interface
return e, nil
}