This commit is contained in:
Sudo-Ivan
2025-01-01 00:40:25 -06:00
parent 785bc7d782
commit 30ea1dd0c7
15 changed files with 1016 additions and 847 deletions

View File

@@ -17,24 +17,24 @@ import (
"encoding/hex"
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
)
const (
CURVE = "Curve25519"
KEYSIZE = 512 // Combined length of encryption key (256) and signing key (256)
RATCHETSIZE = 256
RATCHET_EXPIRY = 2592000 // 30 days in seconds
CURVE = "Curve25519"
KEYSIZE = 512 // Combined length of encryption key (256) and signing key (256)
RATCHETSIZE = 256
RATCHET_EXPIRY = 2592000 // 30 days in seconds
TRUNCATED_HASHLENGTH = 128
NAME_HASH_LENGTH = 80
NAME_HASH_LENGTH = 80
// Token constants for Fernet-like spec
TOKEN_OVERHEAD = 16 // AES block size
TOKEN_OVERHEAD = 16 // AES block size
AES128_BLOCKSIZE = 16
HASHLENGTH = 256
SIGLENGTH = KEYSIZE
HASHLENGTH = 256
SIGLENGTH = KEYSIZE
)
type Identity struct {
@@ -45,10 +45,10 @@ type Identity struct {
hash []byte
hexHash string
appData []byte
ratchets map[string][]byte
ratchetExpiry map[string]int64
mutex sync.RWMutex
ratchets map[string][]byte
ratchetExpiry map[string]int64
mutex *sync.RWMutex
}
var (
@@ -170,7 +170,7 @@ func (i *Identity) Encrypt(plaintext []byte, ratchet []byte) ([]byte, error) {
if _, err := io.ReadFull(rand.Reader, ephemeralPrivKey); err != nil {
return nil, err
}
ephemeralPubKey, err := curve25519.X25519(ephemeralPrivKey, curve25519.Basepoint)
if err != nil {
return nil, err
@@ -183,7 +183,7 @@ func (i *Identity) Encrypt(plaintext []byte, ratchet []byte) ([]byte, error) {
}
// Generate shared secret
sharedSecret, err := curve25519.X25519(ephemeralPrivKey, targetKey)
sharedSecret, err := curve25519.X25519(ephemeralPrivKey, targetKey)
if err != nil {
return nil, err
}
@@ -255,15 +255,15 @@ func GetRandomHash() []byte {
return TruncatedHash(randomData)
}
func Remember(packetHash, destHash []byte, publicKey []byte, appData []byte) {
if len(destHash) > TRUNCATED_HASHLENGTH/8 {
destHash = destHash[:TRUNCATED_HASHLENGTH/8]
}
func Remember(packet []byte, destHash []byte, publicKey []byte, appData []byte) {
hashStr := hex.EncodeToString(destHash)
knownDestinations[string(destHash)] = []interface{}{
time.Now().Unix(),
packetHash,
publicKey,
// Store destination data as [packet, destHash, identity, appData]
id := FromPublicKey(publicKey)
knownDestinations[hashStr] = []interface{}{
packet,
destHash,
id,
appData,
}
}
@@ -464,7 +464,7 @@ func (i *Identity) tryRatchetDecryption(peerPubBytes, ciphertext, ratchet []byte
return nil, nil, err
}
ratchetID := i.GetRatchetID(ratchetPubBytes)
// Generate shared key
sharedKey, err := curve25519.X25519(ratchetPriv, peerPubBytes)
if err != nil {
@@ -618,3 +618,71 @@ func (i *Identity) GetRatchetID(ratchetPubBytes []byte) []byte {
hash := sha256.Sum256(ratchetPubBytes)
return hash[:NAME_HASH_LENGTH/8]
}
func GetKnownDestination(hash string) ([]interface{}, bool) {
if data, exists := knownDestinations[hash]; exists {
return data, true
}
return nil, false
}
func (i *Identity) GetHexHash() string {
if i.hexHash == "" {
i.hexHash = hex.EncodeToString(i.Hash())
}
return i.hexHash
}
func (i *Identity) GetRatchetKey(id string) ([]byte, bool) {
ratchetPersistLock.Lock()
defer ratchetPersistLock.Unlock()
key, exists := knownRatchets[id]
return key, exists
}
func (i *Identity) SetRatchetKey(id string, key []byte) {
ratchetPersistLock.Lock()
defer ratchetPersistLock.Unlock()
knownRatchets[id] = key
}
// NewIdentity creates a new Identity instance with fresh keys
func NewIdentity() (*Identity, error) {
// Generate Ed25519 signing keypair
pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, fmt.Errorf("failed to generate Ed25519 keypair: %v", err)
}
// Generate X25519 encryption keypair
var encPrivKey [32]byte
if _, err := io.ReadFull(rand.Reader, encPrivKey[:]); err != nil {
return nil, fmt.Errorf("failed to generate X25519 private key: %v", err)
}
encPubKey, err := curve25519.X25519(encPrivKey[:], curve25519.Basepoint)
if err != nil {
return nil, fmt.Errorf("failed to generate X25519 public key: %v", err)
}
i := &Identity{
privateKey: encPrivKey[:],
publicKey: encPubKey,
signingKey: privKey,
verificationKey: pubKey,
ratchets: make(map[string][]byte),
ratchetExpiry: make(map[string]int64),
mutex: &sync.RWMutex{},
}
// Generate hash
combinedPub := make([]byte, KEYSIZE/8)
copy(combinedPub[:KEYSIZE/16], i.publicKey)
copy(combinedPub[KEYSIZE/16:], i.verificationKey)
hash := sha256.Sum256(combinedPub)
i.hash = hash[:]
return i, nil
}