baseline: P1 契约、agent 核心与中继投递(既有工作首次入库)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Ephemeral is a one-use X25519 key pair.
|
||||
//
|
||||
// One use, enforced by not exposing the private half after the exchange: the caller gets the derived
|
||||
// key material, never the key, so there is nothing to reuse by accident later.
|
||||
type Ephemeral struct {
|
||||
private []byte
|
||||
public []byte
|
||||
}
|
||||
|
||||
// ErrEphemeralExhausted is returned when the system RNG cannot supply bytes. It is fatal for the
|
||||
// request and never retried: a PRNG failure means the process cannot be trusted to produce secrets.
|
||||
var ErrEphemeralExhausted = errors.New("wire: cannot read random bytes for an ephemeral key")
|
||||
|
||||
// NewEphemeral generates a key pair for exactly one exchange.
|
||||
func NewEphemeral() (Ephemeral, error) {
|
||||
private := make([]byte, KeyBytes)
|
||||
if _, err := rand.Read(private); err != nil {
|
||||
return Ephemeral{}, ErrEphemeralExhausted
|
||||
}
|
||||
public, err := PublicFrom(private)
|
||||
if err != nil {
|
||||
return Ephemeral{}, err
|
||||
}
|
||||
return Ephemeral{private: private, public: public}, nil
|
||||
}
|
||||
|
||||
// PublicFrom derives the X25519 public key for a private key.
|
||||
//
|
||||
// Exported because both sides of a test need it, and because a caller that already holds a private
|
||||
// key should not have to build a throwaway Ephemeral just to learn its own public half.
|
||||
func PublicFrom(private []byte) ([]byte, error) {
|
||||
key, err := ecdh.X25519().NewPrivateKey(private)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: private key rejected: %v", ErrBadKey, err)
|
||||
}
|
||||
return key.PublicKey().Bytes(), nil
|
||||
}
|
||||
|
||||
// Public is what goes in the envelope's ek field, signed along with everything else.
|
||||
func (e Ephemeral) Public() []byte { return e.public }
|
||||
|
||||
// Exchange performs X25519 against a peer public key and discards the private half.
|
||||
//
|
||||
// Zeroing is not a substitute for a proper memory barrier and does not defend against a process
|
||||
// dump, but it costs one line and removes the private key from the heap at the earliest point the
|
||||
// protocol no longer needs it.
|
||||
func (e Ephemeral) Exchange(peerPublic []byte) ([]byte, error) {
|
||||
shared, err := SharedSecret(e.private, peerPublic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := range e.private {
|
||||
e.private[i] = 0
|
||||
}
|
||||
return shared, nil
|
||||
}
|
||||
Reference in New Issue
Block a user