package encryption import ( "crypto/ecdh" "crypto/rand" "encoding/base64" "fmt" "github.com/metacubex/utls/mlkem" ) const MLKEM768SeedLength = mlkem.SeedSize const MLKEM768ClientLength = mlkem.EncapsulationKeySize768 const X25519PasswordSize = 32 const X25519PrivateKeySize = 32 func GenMLKEM768(seedStr string) (seedBase64, clientBase64 string, err error) { var seed [MLKEM768SeedLength]byte if len(seedStr) > 0 { s, _ := base64.RawURLEncoding.DecodeString(seedStr) if len(s) != MLKEM768SeedLength { err = fmt.Errorf("invalid length of ML-KEM-768 seed: %s", seedStr) return } seed = [MLKEM768SeedLength]byte(s) } else { _, err = rand.Read(seed[:]) if err != nil { return } } key, _ := mlkem.NewDecapsulationKey768(seed[:]) pub := key.EncapsulationKey() seedBase64 = base64.RawURLEncoding.EncodeToString(seed[:]) clientBase64 = base64.RawURLEncoding.EncodeToString(pub.Bytes()) return } func GenX25519(privateKeyStr string) (privateKeyBase64, passwordBase64 string, err error) { var privateKey [X25519PrivateKeySize]byte if len(privateKeyStr) > 0 { s, _ := base64.RawURLEncoding.DecodeString(privateKeyStr) if len(s) != X25519PrivateKeySize { err = fmt.Errorf("invalid length of X25519 private key: %s", privateKeyStr) return } privateKey = [X25519PrivateKeySize]byte(s) } else { _, err = rand.Read(privateKey[:]) if err != nil { return } } // Modify random bytes using algorithm described at: // https://cr.yp.to/ecdh.html. privateKey[0] &= 248 privateKey[31] &= 127 privateKey[31] |= 64 key, err := ecdh.X25519().NewPrivateKey(privateKey[:]) if err != nil { fmt.Println(err.Error()) return } privateKeyBase64 = base64.RawURLEncoding.EncodeToString(privateKey[:]) passwordBase64 = base64.RawURLEncoding.EncodeToString(key.PublicKey().Bytes()) return }