mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-06-07 18:24:25 -04:00
132 lines
3.4 KiB
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
|
|
}
|