Skip to content

Commit b1e0bfb

Browse files
committed
Import ipcrypt
1 parent a8da414 commit b1e0bfb

2 files changed

Lines changed: 484 additions & 0 deletions

File tree

dnscrypt-proxy/ipcrypt.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package main
2+
3+
import (
4+
"crypto/rand"
5+
"encoding/hex"
6+
"fmt"
7+
"net"
8+
"strings"
9+
10+
"github.com/jedisct1/dlog"
11+
ipcrypt "github.com/jedisct1/go-ipcrypt"
12+
)
13+
14+
// IPCryptConfig holds the configuration for IP address encryption
15+
type IPCryptConfig struct {
16+
Key []byte
17+
Algorithm string
18+
Tweak []byte // For non-deterministic modes
19+
}
20+
21+
// NewIPCryptConfig creates a new IPCryptConfig from configuration values
22+
// Returns nil when encryption is disabled (algorithm is "none" or empty)
23+
func NewIPCryptConfig(keyHex string, algorithm string) (*IPCryptConfig, error) {
24+
// Default to "none" if empty
25+
if algorithm == "" {
26+
algorithm = "none"
27+
}
28+
29+
// Return nil for "none" algorithm - encryption disabled
30+
if algorithm == "none" {
31+
return nil, nil
32+
}
33+
34+
if keyHex == "" {
35+
return nil, fmt.Errorf("IP encryption algorithm is set to %s but no key provided", algorithm)
36+
}
37+
38+
key, err := hex.DecodeString(keyHex)
39+
if err != nil {
40+
return nil, fmt.Errorf("invalid IP encryption key (must be hex): %w", err)
41+
}
42+
43+
config := &IPCryptConfig{
44+
Key: key,
45+
Algorithm: algorithm,
46+
}
47+
48+
// Validate key length and prepare config based on algorithm
49+
switch strings.ToLower(algorithm) {
50+
case "ipcrypt-deterministic":
51+
// Deterministic IPCrypt uses 16-byte keys
52+
if len(key) != 16 {
53+
return nil, fmt.Errorf("ipcrypt-deterministic requires a 16-byte (32 hex chars) key, got %d bytes", len(key))
54+
}
55+
56+
case "ipcrypt-nd":
57+
// Non-deterministic with 8-byte tweak
58+
if len(key) != 16 {
59+
return nil, fmt.Errorf("ipcrypt-nd requires a 16-byte (32 hex chars) key, got %d bytes", len(key))
60+
}
61+
config.Tweak = make([]byte, 8)
62+
63+
case "ipcrypt-ndx":
64+
// Extended non-deterministic with 16-byte tweak
65+
if len(key) != 32 {
66+
return nil, fmt.Errorf("ipcrypt-ndx requires a 32-byte (64 hex chars) key, got %d bytes", len(key))
67+
}
68+
config.Tweak = make([]byte, 16)
69+
70+
default:
71+
return nil, fmt.Errorf("unsupported IP encryption algorithm: %s (must be 'ipcrypt-deterministic', 'ipcrypt-nd', 'ipcrypt-ndx', or 'none')", algorithm)
72+
}
73+
74+
return config, nil
75+
}
76+
77+
// EncryptIP encrypts an IP address using the configured encryption
78+
func (config *IPCryptConfig) EncryptIP(ip net.IP) (string, error) {
79+
if config == nil {
80+
return ip.String(), nil
81+
}
82+
83+
switch config.Algorithm {
84+
case "ipcrypt-deterministic":
85+
// Deterministic encryption
86+
encrypted, err := ipcrypt.EncryptIP(config.Key, ip)
87+
if err != nil {
88+
return "", fmt.Errorf("failed to encrypt IP: %w", err)
89+
}
90+
return encrypted.String(), nil
91+
92+
case "ipcrypt-nd":
93+
// Non-deterministic: generate random tweak for this encryption
94+
if _, err := rand.Read(config.Tweak); err != nil {
95+
return "", fmt.Errorf("failed to generate random tweak: %w", err)
96+
}
97+
encrypted, err := ipcrypt.EncryptIPNonDeterministic(ip.String(), config.Key, config.Tweak)
98+
if err != nil {
99+
return "", fmt.Errorf("failed to encrypt IP (nd): %w", err)
100+
}
101+
// Return as hex string for non-deterministic modes since they return bytes
102+
return hex.EncodeToString(encrypted), nil
103+
104+
case "ipcrypt-ndx":
105+
// Extended non-deterministic: generate random tweak
106+
if _, err := rand.Read(config.Tweak); err != nil {
107+
return "", fmt.Errorf("failed to generate random tweak: %w", err)
108+
}
109+
encrypted, err := ipcrypt.EncryptIPNonDeterministicX(ip.String(), config.Key, config.Tweak)
110+
if err != nil {
111+
return "", fmt.Errorf("failed to encrypt IP (ndx): %w", err)
112+
}
113+
// Return as hex string for non-deterministic modes
114+
return hex.EncodeToString(encrypted), nil
115+
116+
default:
117+
return "", fmt.Errorf("unsupported algorithm: %s", config.Algorithm)
118+
}
119+
}
120+
121+
// EncryptIPString encrypts an IP address string
122+
func (config *IPCryptConfig) EncryptIPString(ipStr string) string {
123+
if config == nil || ipStr == "" {
124+
return ipStr
125+
}
126+
127+
ip := net.ParseIP(ipStr)
128+
if ip == nil {
129+
// If it's not a valid IP, return as-is
130+
return ipStr
131+
}
132+
133+
encrypted, err := config.EncryptIP(ip)
134+
if err != nil {
135+
dlog.Warnf("Failed to encrypt IP %s: %v", ipStr, err)
136+
return ipStr
137+
}
138+
139+
return encrypted
140+
}
141+
142+
// DecryptIP decrypts an encrypted IP address
143+
func (config *IPCryptConfig) DecryptIP(encryptedStr string) (string, error) {
144+
if config == nil {
145+
return encryptedStr, nil
146+
}
147+
148+
switch config.Algorithm {
149+
case "ipcrypt-deterministic":
150+
// Parse as IP for deterministic mode
151+
ip := net.ParseIP(encryptedStr)
152+
if ip == nil {
153+
return "", fmt.Errorf("invalid encrypted IP address: %s", encryptedStr)
154+
}
155+
decrypted, err := ipcrypt.DecryptIP(config.Key, ip)
156+
if err != nil {
157+
return "", fmt.Errorf("failed to decrypt IP: %w", err)
158+
}
159+
return decrypted.String(), nil
160+
161+
case "ipcrypt-nd":
162+
// Decode from hex for non-deterministic mode
163+
encrypted, err := hex.DecodeString(encryptedStr)
164+
if err != nil {
165+
return "", fmt.Errorf("failed to decode encrypted IP: %w", err)
166+
}
167+
decrypted, err := ipcrypt.DecryptIPNonDeterministic(encrypted, config.Key)
168+
if err != nil {
169+
return "", fmt.Errorf("failed to decrypt IP (nd): %w", err)
170+
}
171+
return decrypted, nil
172+
173+
case "ipcrypt-ndx":
174+
// Decode from hex for extended non-deterministic mode
175+
encrypted, err := hex.DecodeString(encryptedStr)
176+
if err != nil {
177+
return "", fmt.Errorf("failed to decode encrypted IP: %w", err)
178+
}
179+
decrypted, err := ipcrypt.DecryptIPNonDeterministicX(encrypted, config.Key)
180+
if err != nil {
181+
return "", fmt.Errorf("failed to decrypt IP (ndx): %w", err)
182+
}
183+
return decrypted, nil
184+
185+
default:
186+
return "", fmt.Errorf("unsupported algorithm: %s", config.Algorithm)
187+
}
188+
}

0 commit comments

Comments
 (0)