mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-23 19:30:09 +08:00
115 lines
3.7 KiB
Go
115 lines
3.7 KiB
Go
package encryption
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// NewClient new client from encryption string
|
|
// maybe return a nil *ClientInstance without any error, that means don't need to encrypt
|
|
func NewClient(encryption string) (*ClientInstance, error) {
|
|
switch encryption {
|
|
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
|
return nil, nil
|
|
}
|
|
if s := strings.Split(encryption, "."); len(s) == 5 && s[2] == "mlkem768Client" {
|
|
var minutes uint32
|
|
if s[0] != "1rtt" {
|
|
t := strings.TrimSuffix(s[0], "min")
|
|
if t == s[0] {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
i, err := strconv.Atoi(t)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
minutes = uint32(i)
|
|
}
|
|
var xorMode uint32
|
|
switch s[1] {
|
|
case "native":
|
|
case "divide":
|
|
xorMode = 1
|
|
case "random":
|
|
xorMode = 2
|
|
default:
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
xorPKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
if len(xorPKeyBytes) != X25519PasswordSize {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
nfsEKeyBytes, err := base64.RawURLEncoding.DecodeString(s[4])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
if len(nfsEKeyBytes) != MLKEM768ClientLength {
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
client := &ClientInstance{}
|
|
if err = client.Init(nfsEKeyBytes, xorPKeyBytes, xorMode, minutes); err != nil {
|
|
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
|
}
|
|
return client, nil
|
|
}
|
|
return nil, fmt.Errorf("invaild vless encryption value: %s", encryption)
|
|
}
|
|
|
|
// NewServer new server from decryption string
|
|
// maybe return a nil *ServerInstance without any error, that means don't need to decrypt
|
|
func NewServer(decryption string) (*ServerInstance, error) {
|
|
switch decryption {
|
|
case "", "none": // We will not reject empty string like xray-core does, because we need to ensure compatibility
|
|
return nil, nil
|
|
}
|
|
if s := strings.Split(decryption, "."); len(s) == 5 && s[2] == "mlkem768Seed" {
|
|
var minutes uint32
|
|
if s[0] != "1rtt" {
|
|
t := strings.TrimSuffix(s[0], "min")
|
|
if t == s[0] {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
i, err := strconv.Atoi(t)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
minutes = uint32(i)
|
|
}
|
|
var xorMode uint32
|
|
switch s[1] {
|
|
case "native":
|
|
case "divide":
|
|
xorMode = 1
|
|
case "random":
|
|
xorMode = 2
|
|
default:
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
xorSKeyBytes, err := base64.RawURLEncoding.DecodeString(s[3])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
if len(xorSKeyBytes) != X25519PrivateKeySize {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
nfsDKeySeed, err := base64.RawURLEncoding.DecodeString(s[4])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
if len(nfsDKeySeed) != MLKEM768SeedLength {
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|
|
server := &ServerInstance{}
|
|
if err = server.Init(nfsDKeySeed, xorSKeyBytes, xorMode, minutes); err != nil {
|
|
return nil, fmt.Errorf("failed to use mlkem768seed: %w", err)
|
|
}
|
|
return server, nil
|
|
}
|
|
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
|
}
|