Client noisePacketConn.
[champa.git] / noise / noise.go
blob056903e7917b67c703fcb073f08ce62c6c3f2827
1 // Package noise provides a net.Conn-like interface for a
2 // Noise_NK_25519_ChaChaPoly_BLAKE2s. It encodes Noise messages onto a reliable
3 // stream using 16-bit length prefixes.
4 //
5 // https://noiseprotocol.org/noise.html
6 package noise
8 import (
9 "bufio"
10 "crypto/rand"
11 "encoding/binary"
12 "encoding/hex"
13 "errors"
14 "fmt"
15 "io"
16 "net"
17 "strings"
19 "github.com/flynn/noise"
20 "golang.org/x/crypto/curve25519"
23 // The length of public and private keys as returned by GeneratePrivkey.
24 const KeyLen = 32
26 const (
27 MsgTypeHandshakeInit = 1
28 MsgTypeHandshakeResp = 2
29 MsgTypeTransport = 4
32 // cipherSuite represents 25519_ChaChaPoly_BLAKE2s.
33 var cipherSuite = noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashBLAKE2s)
35 func ReadMessageFrom(conn net.PacketConn) (byte, []byte, net.Addr, error) {
36 var buf [1500]byte
37 for {
38 n, addr, err := conn.ReadFrom(buf[:])
39 if err != nil {
40 return 0, nil, nil, err
42 if n >= 1 {
43 return buf[0], buf[1:n], addr, nil
48 // readMessage reads a length-prefixed message from r. It returns a nil error
49 // only when a complete message was read. It returns io.EOF only when there were
50 // 0 bytes remaining to read from r. It returns io.ErrUnexpectedEOF when EOF
51 // occurs in the middle of an encoded message.
52 func readMessage(r io.Reader) ([]byte, error) {
53 var length uint16
54 err := binary.Read(r, binary.BigEndian, &length)
55 if err != nil {
56 // We may return a real io.EOF only here.
57 return nil, err
59 msg := make([]byte, int(length))
60 _, err = io.ReadFull(r, msg)
61 // Here we must change io.EOF to io.ErrUnexpectedEOF.
62 if err == io.EOF {
63 err = io.ErrUnexpectedEOF
65 return msg, err
68 // writeMessage writes msg as a length-prefixed message to w. It panics if the
69 // length of msg cannot be represented in 16 bits.
70 func writeMessage(w io.Writer, msg []byte) error {
71 length := uint16(len(msg))
72 if int(length) != len(msg) {
73 panic(len(msg))
75 err := binary.Write(w, binary.BigEndian, length)
76 if err != nil {
77 return err
79 _, err = w.Write(msg)
80 return err
83 // socket is the internal type that represents a Noise-wrapped
84 // io.ReadWriteCloser.
85 type socket struct {
86 recvPipe *io.PipeReader
87 sendCipher *noise.CipherState
88 io.ReadWriteCloser
91 func newSocket(rwc io.ReadWriteCloser, recvCipher, sendCipher *noise.CipherState) *socket {
92 pr, pw := io.Pipe()
93 // This loop calls readMessage, decrypts the messages, and feeds them
94 // into recvPipe where they will be returned from Read.
95 go func() (err error) {
96 defer func() {
97 pw.CloseWithError(err)
98 }()
99 for {
100 msg, err := readMessage(rwc)
101 if err != nil {
102 return err
104 p, err := recvCipher.Decrypt(nil, nil, msg)
105 if err != nil {
106 return err
108 _, err = pw.Write(p)
109 if err != nil {
110 return err
114 return &socket{
115 sendCipher: sendCipher,
116 recvPipe: pr,
117 ReadWriteCloser: rwc,
121 // Read reads decrypted data from the wrapped io.Reader.
122 func (s *socket) Read(p []byte) (int, error) {
123 return s.recvPipe.Read(p)
126 // Write writes encrypted data from the wrapped io.Writer.
127 func (s *socket) Write(p []byte) (int, error) {
128 total := 0
129 for len(p) > 0 {
130 n := len(p)
131 if n > 4096 {
132 n = 4096
134 msg, err := s.sendCipher.Encrypt(nil, nil, p[:n])
135 if err != nil {
136 return total, err
138 err = writeMessage(s.ReadWriteCloser, msg)
139 if err != nil {
140 return total, err
142 total += n
143 p = p[n:]
145 return total, nil
148 // newConfig instantiates configuration settings that are common to clients and
149 // servers.
150 func newConfig() noise.Config {
151 return noise.Config{
152 CipherSuite: cipherSuite,
153 Pattern: noise.HandshakeNK,
154 Prologue: []byte("Champa 2021-06-17"),
158 // NewClient wraps an io.ReadWriteCloser in a Noise protocol as a client, and
159 // returns after completing the handshake. It returns a non-nil error if there
160 // is an error during the handshake.
161 func NewClient(rwc io.ReadWriteCloser, serverPubkey []byte) (io.ReadWriteCloser, error) {
162 config := newConfig()
163 config.Initiator = true
164 config.PeerStatic = serverPubkey
165 handshakeState, err := noise.NewHandshakeState(config)
166 if err != nil {
167 return nil, err
170 // -> e, es
171 msg, _, _, err := handshakeState.WriteMessage(nil, nil)
172 if err != nil {
173 return nil, err
175 err = writeMessage(rwc, msg)
176 if err != nil {
177 return nil, err
180 // <- e, es
181 msg, err = readMessage(rwc)
182 if err != nil {
183 return nil, err
185 payload, sendCipher, recvCipher, err := handshakeState.ReadMessage(nil, msg)
186 if err != nil {
187 return nil, err
189 if len(payload) != 0 {
190 return nil, errors.New("unexpected server payload")
193 return newSocket(rwc, recvCipher, sendCipher), nil
196 // NewClient wraps an io.ReadWriteCloser in a Noise protocol as a server, and
197 // returns after completing the handshake. It returns a non-nil error if there
198 // is an error during the handshake.
199 func NewServer(rwc io.ReadWriteCloser, serverPrivkey []byte) (io.ReadWriteCloser, error) {
200 config := newConfig()
201 config.Initiator = false
202 config.StaticKeypair = noise.DHKey{
203 Private: serverPrivkey,
204 Public: PubkeyFromPrivkey(serverPrivkey),
206 handshakeState, err := noise.NewHandshakeState(config)
207 if err != nil {
208 return nil, err
211 // -> e, es
212 msg, err := readMessage(rwc)
213 if err != nil {
214 return nil, err
216 payload, _, _, err := handshakeState.ReadMessage(nil, msg)
217 if err != nil {
218 return nil, err
220 if len(payload) != 0 {
221 return nil, errors.New("unexpected server payload")
224 // <- e, es
225 msg, recvCipher, sendCipher, err := handshakeState.WriteMessage(nil, nil)
226 if err != nil {
227 return nil, err
229 err = writeMessage(rwc, msg)
230 if err != nil {
231 return nil, err
234 return newSocket(rwc, recvCipher, sendCipher), nil
237 // GeneratePrivkey generates a private key. The corresponding private key can be
238 // generated using PubkeyFromPrivkey.
239 func GeneratePrivkey() ([]byte, error) {
240 pair, err := noise.DH25519.GenerateKeypair(rand.Reader)
241 return pair.Private, err
244 // PubkeyFromPrivkey returns the public key that corresponds to privkey.
245 func PubkeyFromPrivkey(privkey []byte) []byte {
246 pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
247 if err != nil {
248 panic(err)
250 return pubkey
253 // ReadKey reads a hex-encoded key from r. r must consist of a single line, with
254 // or without a '\n' line terminator. The line must consist of KeyLen
255 // hex-encoded bytes.
256 func ReadKey(r io.Reader) ([]byte, error) {
257 br := bufio.NewReader(io.LimitReader(r, 100))
258 line, err := br.ReadString('\n')
259 if err == io.EOF {
260 err = nil
262 if err == nil {
263 // Check that we're at EOF.
264 _, err = br.ReadByte()
265 if err == io.EOF {
266 err = nil
267 } else if err == nil {
268 err = fmt.Errorf("file contains more than one line")
271 if err != nil {
272 return nil, err
274 line = strings.TrimSuffix(line, "\n")
275 return DecodeKey(line)
278 // WriteKey writes the hex-encoded key in a single line to w.
279 func WriteKey(w io.Writer, key []byte) error {
280 _, err := fmt.Fprintf(w, "%x\n", key)
281 return err
284 // DecodeKey decodes a hex-encoded private or public key.
285 func DecodeKey(s string) ([]byte, error) {
286 key, err := hex.DecodeString(s)
287 if err == nil && len(key) != KeyLen {
288 err = fmt.Errorf("length is %d, expected %d", len(key), KeyLen)
290 return key, err
293 // EncodeKey encodes a hex-encoded private or public key.
294 func EncodeKey(key []byte) string {
295 return hex.EncodeToString(key)