Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b8b4aac
refactor: remove unused SignAndVerify method from EllipticCurve
meling Apr 13, 2025
e1a2a7a
refactor: remove commented gob-based encoder in EncodeMsg
meling Apr 13, 2025
fa07fb2
refactor: remove unnecessary error from encodeMsg function
meling Apr 13, 2025
875cb6e
refactor: replace method with EncodeMsg function and remove error
meling Apr 13, 2025
8cc1be8
refactor: replace encodeMsg with Encode method on gorums.Message type
meling Apr 13, 2025
f0f465e
refactor: use Hash function in Sign and VerifySignature methods
meling Apr 13, 2025
3daf7ed
chore: simplify var name in sign method
meling Apr 13, 2025
e0aaae5
refactor: move message validation to Message.isValid method
meling Apr 14, 2025
a695bdc
refactor: streamline createRequest function
meling Apr 14, 2025
51085a8
refactor(modernize): replace interface{} with any
meling Apr 14, 2025
46f2b47
refactor(modernize): use slices.Contains instead of manual loop check
meling Apr 14, 2025
8bae2d6
refactor(modernize): replace context.WithCancel with t.Context
meling Apr 14, 2025
5049083
refactor(modernize): replace b.N loops with b.Loop() in benchmarks
meling Apr 14, 2025
8be741c
refactor(modernize): compute start and end index using max and min
meling Apr 14, 2025
69876bc
refactor(modernize): replace 3-clause for loops with range loops
meling Apr 14, 2025
de05a05
refactor: move auth message validation to method on Metadata type
meling Apr 14, 2025
67c89ac
refactor: add allowList type and encapsulate validation logic
meling Apr 14, 2025
ddd62d5
refactor: simplify verification by returning invalid signature error
meling Apr 14, 2025
03cdce7
chore: remove unnecessary error handling in Sign method
meling Apr 15, 2025
dd4c619
refactor: simplify the Verify function to return error directly
meling Apr 15, 2025
74f4cb1
chore: WithAllowList could replace EnforceAuthentication
meling Apr 15, 2025
c1c372a
refactor: replace New method with NewWithAddr for EllipticCurve creation
meling Apr 15, 2025
40b7e63
refactor(snowflake): use consts for bit lengths; adds InvalidMachineID
meling Jun 13, 2025
519c3f0
refactor: use logging.MachineID helper to init logger
meling Jun 13, 2025
4254217
refactor: update Snowflake machine ID handling and improve docs
meling Jun 13, 2025
bff8a28
refactor: use ExtractShardID for shard ID extraction
meling Jun 13, 2025
bdb4989
refactor: remove unused listenAddr field in newClient
meling Jun 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 44 additions & 88 deletions authentication/authentication.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,43 @@ import (
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"net"
)

// Elliptic Curve Cryptography (ECC) is a key-based technique for encrypting data.
// ECC focuses on pairs of public and private keys for decryption and encryption of web traffic.
// ECC is frequently discussed in the context of the Rivest–Shamir–Adleman (RSA) cryptographic algorithm.
//
// https://pkg.go.dev/github.com/katzenpost/core/crypto/eddsa
// EllipticCurve represents an elliptic curve instance used for message authentication.
type EllipticCurve struct {
addr net.Addr // used to identify self
pubKeyCurve elliptic.Curve // http://golang.org/pkg/crypto/elliptic/#P256
privateKey *ecdsa.PrivateKey
publicKey *ecdsa.PublicKey
addr net.Addr // used to identify self
curve elliptic.Curve
privateKey *ecdsa.PrivateKey
publicKey *ecdsa.PublicKey
}

// New EllipticCurve instance
func New(curve elliptic.Curve) *EllipticCurve {
return &EllipticCurve{
pubKeyCurve: curve,
privateKey: new(ecdsa.PrivateKey),
curve: curve,
privateKey: new(ecdsa.PrivateKey),
}
}

// GenerateKeys EllipticCurve public and private keys
func (ec *EllipticCurve) GenerateKeys() error {
privKey, err := ecdsa.GenerateKey(ec.pubKeyCurve, rand.Reader)
// NewWithAddr returns a new EllipticCurve instance with the given address.
// It generates a new public-private key pair for the specified elliptic curve.
func NewWithAddr(curve elliptic.Curve, addr net.Addr) (*EllipticCurve, error) {
if addr == nil {
return nil, errors.New("address cannot be nil")
}
priv, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return err
return nil, err
}
ec.privateKey = privKey
ec.publicKey = &privKey.PublicKey
return nil
}

// RegisterKeys EllipticCurve public and private keys
func (ec *EllipticCurve) RegisterKeys(addr net.Addr, privKey *ecdsa.PrivateKey, pubKey *ecdsa.PublicKey) {
ec.addr = addr
ec.privateKey = privKey
ec.publicKey = pubKey
}

// Returns the EllipticCurve public and private keys
func (ec *EllipticCurve) Keys() (*ecdsa.PrivateKey, *ecdsa.PublicKey) {
return ec.privateKey, ec.publicKey
return &EllipticCurve{
addr: addr,
curve: curve,
privateKey: priv,
publicKey: &priv.PublicKey,
}, nil
}

// Returns the address
Expand Down Expand Up @@ -93,7 +85,7 @@ func (ec *EllipticCurve) DecodePrivate(pemEncodedPriv string) (*ecdsa.PrivateKey
func (ec *EllipticCurve) DecodePublic(pemEncodedPub string) (*ecdsa.PublicKey, error) {
blockPub, _ := pem.Decode([]byte(pemEncodedPub))
if blockPub == nil {
return nil, fmt.Errorf("invalid publicKey")
return nil, errors.New("invalid public key")
}
x509EncodedPub := blockPub.Bytes
genericPublicKey, err := x509.ParsePKIXPublicKey(x509EncodedPub)
Expand All @@ -102,76 +94,40 @@ func (ec *EllipticCurve) DecodePublic(pemEncodedPub string) (*ecdsa.PublicKey, e
}

func (ec *EllipticCurve) Sign(msg []byte) ([]byte, error) {
h := sha256.Sum256(msg)
hash := h[:]
signature, err := ecdsa.SignASN1(rand.Reader, ec.privateKey, hash)
if err != nil {
return nil, err
}
return signature, nil
return ecdsa.SignASN1(rand.Reader, ec.privateKey, Hash(msg))
}

func (ec *EllipticCurve) Hash(msg []byte) []byte {
h := sha256.Sum256(msg)
hash := h[:]
return hash
func Hash(msg []byte) []byte {
hash := sha256.Sum256(msg)
return hash[:]
}

// VerifySignature sign ecdsa style and verify signature
func (ec *EllipticCurve) VerifySignature(pemEncodedPub string, msg, signature []byte) (bool, error) {
h := sha256.Sum256(msg)
hash := h[:]
pubKey, err := ec.DecodePublic(pemEncodedPub)
if err != nil {
return false, err
}
ok := ecdsa.VerifyASN1(pubKey, hash, signature)
return ok, nil
}
var InvalidSignatureErr = errors.New("invalid signature")

// VerifySignature sign ecdsa style and verify signature
func (ec *EllipticCurve) SignAndVerify(privKey *ecdsa.PrivateKey, pubKey *ecdsa.PublicKey) ([]byte, bool, error) {
h := sha256.Sum256([]byte("test"))
hash := h[:]
signature, err := ecdsa.SignASN1(rand.Reader, privKey, hash)
// VerifySignature verifies the signature of the message's hash using the given PEM encoded
// public key. It returns an error if the signature is invalid or if there is an error
// decoding the public key.
func (ec *EllipticCurve) VerifySignature(pemEncodedPub string, msg, signature []byte) error {
pubKey, err := ec.DecodePublic(pemEncodedPub)
if err != nil {
return nil, false, err
return err
}
ok := ecdsa.VerifyASN1(pubKey, hash, signature)
return signature, ok, nil
}

func (ec *EllipticCurve) EncodeMsg(msg any) ([]byte, error) {
return []byte(fmt.Sprintf("%v", msg)), nil
/*var encodedMsg bytes.Buffer
gob.Register(msg)
enc := gob.NewEncoder(&encodedMsg)
err := enc.Encode(msg)
if err != nil {
return nil, err
if valid := ecdsa.VerifyASN1(pubKey, Hash(msg), signature); !valid {
return InvalidSignatureErr
}
return encodedMsg.Bytes(), nil*/
return nil
}

func encodeMsg(msg any) ([]byte, error) {
return []byte(fmt.Sprintf("%v", msg)), nil
func EncodeMsg(msg any) []byte {
return fmt.Appendf(nil, "%v", msg)
}

func Verify(pemEncodedPub string, signature, digest []byte, msg any) (bool, error) {
encodedMsg, err := encodeMsg(msg)
if err != nil {
return false, err
}
func Verify(pemEncodedPub string, signature, digest []byte, msg any) error {
encodedMsg := EncodeMsg(msg)
ec := New(elliptic.P256())
h := sha256.Sum256(encodedMsg)
hash := h[:]
hash := Hash(encodedMsg)
if !bytes.Equal(hash, digest) {
return false, fmt.Errorf("wrong digest")
}
pubKey, err := ec.DecodePublic(pemEncodedPub)
if err != nil {
return false, err
return errors.New("invalid digest for message")
}
ok := ecdsa.VerifyASN1(pubKey, hash, signature)
return ok, nil
return ec.VerifySignature(pemEncodedPub, encodedMsg, signature)
}
76 changes: 35 additions & 41 deletions authentication/authentication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,42 @@ package authentication
import (
"crypto/elliptic"
"errors"
"net"
"reflect"
"testing"
)

func TestAuthentication(t *testing.T) {
ec := New(elliptic.P256())
_ = ec.GenerateKeys()
err := ec.test()
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5000")
if err != nil {
t.Fatal(err)
}
ec, err := NewWithAddr(elliptic.P256(), addr)
if err != nil {
t.Fatal(err)
}
err = ec.test()
if err != nil {
t.Error(err)
}
}

func TestSignAndVerify(t *testing.T) {
ec1 := New(elliptic.P256())
err := ec1.GenerateKeys()
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5000")
if err != nil {
t.Fatal(err)
}

ec2 := New(elliptic.P256())
err = ec2.GenerateKeys()
ec1, err := NewWithAddr(elliptic.P256(), addr)
if err != nil {
t.Fatal(err)
}

message := "This is a message"

encodedMsg1, err := ec1.EncodeMsg(message)
ec2, err := NewWithAddr(elliptic.P256(), addr)
if err != nil {
t.Error(err)
t.Fatal(err)
}

message := "This is a message"
encodedMsg1 := EncodeMsg(message)
signature, err := ec1.Sign(encodedMsg1)
if err != nil {
t.Error(err)
Expand All @@ -44,37 +48,29 @@ func TestSignAndVerify(t *testing.T) {
t.Error(err)
}

encodedMsg2, err := ec2.EncodeMsg(message)
if err != nil {
t.Error(err)
}
ok, err := ec2.VerifySignature(pemEncodedPub, encodedMsg2, signature)
encodedMsg2 := EncodeMsg(message)
err = ec2.VerifySignature(pemEncodedPub, encodedMsg2, signature)
if err != nil {
t.Error(err)
}
if !ok {
t.Error("signature not ok!")
t.Errorf("VerifySignature() = %v, want nil", err)
}
}

func TestVerifyWithWrongPubKey(t *testing.T) {
ec1 := New(elliptic.P256())
err := ec1.GenerateKeys()
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5000")
if err != nil {
t.Fatal(err)
}

ec2 := New(elliptic.P256())
err = ec2.GenerateKeys()
ec1, err := NewWithAddr(elliptic.P256(), addr)
if err != nil {
t.Fatal(err)
}

message := "This is a message"
encodedMsg1, err := ec1.EncodeMsg(message)
ec2, err := NewWithAddr(elliptic.P256(), addr)
if err != nil {
t.Error(err)
t.Fatal(err)
}

message := "This is a message"
encodedMsg1 := EncodeMsg(message)
signature, err := ec1.Sign(encodedMsg1)
if err != nil {
t.Error(err)
Expand All @@ -86,16 +82,14 @@ func TestVerifyWithWrongPubKey(t *testing.T) {
t.Error(err)
}

encodedMsg2, err := ec2.EncodeMsg(message)
if err != nil {
t.Error(err)
}
ok, err := ec2.VerifySignature(pemEncodedPub, encodedMsg2, signature)
if err != nil {
t.Error(err)
}
if ok {
t.Error("signature should not be ok!")
encodedMsg2 := EncodeMsg(message)
err = ec2.VerifySignature(pemEncodedPub, encodedMsg2, signature)
if err == nil {
t.Errorf("VerifySignature() = nil, want %v", InvalidSignatureErr)
} else {
if !errors.Is(err, InvalidSignatureErr) {
t.Errorf("VerifySignature() = %v, want %v", err, InvalidSignatureErr)
}
}
}

Expand Down
14 changes: 4 additions & 10 deletions broadcast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package gorums

import (
"context"
"crypto/elliptic"
"hash/fnv"
"log/slog"
"strings"
Expand All @@ -19,11 +18,6 @@ import (
// exposing the log entry struct used for structured logging to the user
type LogEntry logging.LogEntry

// exposing the ellipticCurve struct for the user
func NewAuth(curve elliptic.Curve) *authentication.EllipticCurve {
return authentication.New(curve)
}

type broadcastServer struct {
viewMutex sync.RWMutex
id uint32
Expand Down Expand Up @@ -75,11 +69,10 @@ type (

type (
defaultImplementationFunc[T protoreflect.ProtoMessage, V protoreflect.ProtoMessage] func(ServerCtx, T) (V, error)
implementationFunc[T protoreflect.ProtoMessage, V Broadcaster] func(ServerCtx, T, V)
clientImplementationFunc[T protoreflect.ProtoMessage, V protoreflect.ProtoMessage] func(context.Context, T, uint64) (V, error)
)

type implementationFunc[T protoreflect.ProtoMessage, V Broadcaster] func(ServerCtx, T, V)

func CancelFunc(ServerCtx, protoreflect.ProtoMessage, Broadcaster) {}

const Cancellation string = "cancel"
Expand Down Expand Up @@ -163,7 +156,7 @@ func NewBroadcastOptions() broadcast.BroadcastOptions {
}
}

type Broadcaster interface{}
type Broadcaster any

type BroadcastMetadata struct {
BroadcastID uint64
Expand Down Expand Up @@ -208,6 +201,7 @@ func newBroadcastMetadata(md *ordering.Metadata) BroadcastMetadata {
}
}

func (md BroadcastMetadata) Verify(msg protoreflect.ProtoMessage) (bool, error) {
// TODO(meling): this method is never called
func (md BroadcastMetadata) Verify(msg protoreflect.ProtoMessage) error {
return authentication.Verify(md.OriginPubKey, md.OriginSignature, md.OriginDigest, msg)
}
Loading
Loading