mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2024-12-13 22:46:44 +01:00
83 lines
2.4 KiB
Go
83 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"errors"
|
|
|
|
"github.com/jedisct1/xsecretbox"
|
|
)
|
|
|
|
const (
|
|
NonceSize = xsecretbox.NonceSize
|
|
HalfNonceSize = xsecretbox.NonceSize / 2
|
|
TagSize = xsecretbox.TagSize
|
|
)
|
|
|
|
func pad(packet []byte, minSize int) []byte {
|
|
packet = append(packet, 0x80)
|
|
for len(packet) < minSize {
|
|
packet = append(packet, 0)
|
|
}
|
|
return packet
|
|
}
|
|
|
|
func unpad(packet []byte) ([]byte, error) {
|
|
for i := len(packet); ; {
|
|
if i == 0 {
|
|
return nil, errors.New("Invalid padding (short packet)")
|
|
}
|
|
i--
|
|
if packet[i] == 0x80 {
|
|
return packet[:i], nil
|
|
} else if packet[i] != 0x00 {
|
|
return nil, errors.New("Invalid padding (delimiter not found)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (proxy *Proxy) Encrypt(serverInfo *ServerInfo, packet []byte, proto string) (encrypted []byte, clientNonce []byte, err error) {
|
|
nonce, clientNonce := make([]byte, NonceSize), make([]byte, HalfNonceSize)
|
|
rand.Read(clientNonce)
|
|
copy(nonce, clientNonce)
|
|
minQuestionSize := len(packet)
|
|
if proto == "udp" {
|
|
minQuestionSize = proxy.questionSizeEstimator.MinQuestionSize()
|
|
} else {
|
|
var xpad [1]byte
|
|
rand.Read(xpad[:])
|
|
minQuestionSize += int(xpad[0])
|
|
}
|
|
paddedLength := Min((minQuestionSize+63)&^63, MaxDNSUDPPacketSize-1)
|
|
if paddedLength <= 0 || len(packet) >= paddedLength {
|
|
err = errors.New("Question too large; cannot be padded")
|
|
return
|
|
}
|
|
encrypted = append(serverInfo.MagicQuery[:], proxy.proxyPublicKey[:]...)
|
|
encrypted = append(encrypted, nonce[:HalfNonceSize]...)
|
|
encrypted = xsecretbox.Seal(encrypted, nonce, pad(packet, paddedLength), serverInfo.SharedKey[:])
|
|
return
|
|
}
|
|
|
|
func (proxy *Proxy) Decrypt(serverInfo *ServerInfo, encrypted []byte, nonce []byte) ([]byte, error) {
|
|
serverMagicLen := len(ServerMagic)
|
|
responseHeaderLen := serverMagicLen + NonceSize
|
|
if len(encrypted) < responseHeaderLen+TagSize+int(MinDNSPacketSize) ||
|
|
!bytes.Equal(encrypted[:serverMagicLen], ServerMagic[:]) {
|
|
return encrypted, errors.New("Short message")
|
|
}
|
|
serverNonce := encrypted[serverMagicLen:responseHeaderLen]
|
|
if !bytes.Equal(nonce[:HalfNonceSize], serverNonce[:HalfNonceSize]) {
|
|
return encrypted, errors.New("Unexpected nonce")
|
|
}
|
|
packet, err := xsecretbox.Open(nil, serverNonce, encrypted[responseHeaderLen:], serverInfo.SharedKey[:])
|
|
if err != nil {
|
|
return encrypted, errors.New("Incorrect tag")
|
|
}
|
|
packet, err = unpad(packet)
|
|
if err != nil || len(packet) < MinDNSPacketSize {
|
|
return encrypted, errors.New("Incorrect padding")
|
|
}
|
|
return packet, nil
|
|
}
|