79 lines
2.0 KiB
Go
79 lines
2.0 KiB
Go
package pnyx
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"crypto/sha512"
|
|
"fmt"
|
|
|
|
"filippo.io/edwards25519"
|
|
)
|
|
|
|
func NewSessionOpen(key ed25519.PrivateKey) ([]byte, ed25519.PrivateKey, error) {
|
|
if key == nil {
|
|
return nil, nil, fmt.Errorf("Cannot create a SESSION_OPEN packet without a key")
|
|
}
|
|
|
|
public, private, err := ed25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("Failed to generate ecdh key: %w", err)
|
|
}
|
|
|
|
packet := make([]byte, SESSION_OPEN_LENGTH)
|
|
cur := 0
|
|
|
|
copy(packet[cur:], []byte(key.Public().(ed25519.PublicKey)))
|
|
cur += PUBKEY_LENGTH
|
|
|
|
copy(packet[cur:], []byte(public))
|
|
cur += PUBKEY_LENGTH
|
|
|
|
signature := ed25519.Sign(key, packet[:cur])
|
|
copy(packet[cur:], signature)
|
|
cur += SIGNATURE_LENGTH
|
|
|
|
return packet, private, nil
|
|
}
|
|
|
|
func ParseSessionOpen(session_open []byte) (ed25519.PublicKey, ed25519.PublicKey, error) {
|
|
if len(session_open) != SESSION_OPEN_LENGTH {
|
|
return nil, nil, fmt.Errorf("Bad SESSION_OPEN length: %d/%d", len(session_open), SESSION_OPEN_LENGTH)
|
|
}
|
|
|
|
cur := 0
|
|
|
|
client_pubkey := (ed25519.PublicKey)(session_open[cur:cur+PUBKEY_LENGTH])
|
|
cur += PUBKEY_LENGTH
|
|
|
|
client_ecdh := (ed25519.PublicKey)(session_open[cur:cur+PUBKEY_LENGTH])
|
|
cur += PUBKEY_LENGTH
|
|
|
|
digest := session_open[:cur]
|
|
signature := session_open[cur:cur+SIGNATURE_LENGTH]
|
|
cur += SIGNATURE_LENGTH
|
|
|
|
if ed25519.Verify(client_pubkey, digest, signature) == false {
|
|
return nil, nil, fmt.Errorf("SESSION_OPEN signature verification failed")
|
|
}
|
|
|
|
return client_pubkey, client_ecdh, nil
|
|
}
|
|
|
|
func ECDH(public ed25519.PublicKey, private ed25519.PrivateKey) ([]byte, error) {
|
|
public_point, err := (&edwards25519.Point{}).SetBytes(public)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
|
|
h := sha512.Sum512(private.Seed())
|
|
private_scalar, err := (&edwards25519.Scalar{}).SetBytesWithClamping(h[:32])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
shared_point := public_point.ScalarMult(private_scalar, public_point)
|
|
|
|
return shared_point.BytesMontgomery(), nil
|
|
}
|